[comp.lang.c] Strange lint mumblings

daveh@marob.MASA.COM (Dave Hammond) (12/14/88)

Can anyone explain why the statement:

    exit(0);	/* followed immediately by main's closing brace */

causes lint to complain:

ma-main.c
==============
(137)  warning: main() returns random value to invocation environment


[yes, "exit(0)" is the statement on line 137 of the file ma-main.c]

--
Dave Hammond
  UUCP: uunet!masa.com!{dsix2,marob}!daveh
DOMAIN: dsix2!daveh@masa.com

earleh@eleazar.dartmouth.edu (Earle R. Horton) (12/14/88)

In article <416@marob.MASA.COM> daveh@marob.masa.com (Dave Hammond) writes:
>Can anyone explain why the statement:
>
>    exit(0);	/* followed immediately by main's closing brace */
>
>causes lint to complain:
>
>ma-main.c
>==============
>(137)  warning: main() returns random value to invocation environment

     Syntactically, "exit(0)" is a function call.  How the heck do you
expect lint to know that exit() never returns?  Since main() is
usually declared to be of type int, then lint is fully justified in
expecting to see a "return <something>" at the end of main().  You
will have to either live with the lint warning, or cause main() to
return something.

     How about:

	return(exit(0));
}

     That should keep lint happy!


Earle R. Horton. 23 Fletcher Circle, Hanover, NH 03755
(603) 643-4109
Graduate student.

grs@alobar.ATT.COM (Gregg Siegfried) (12/15/88)

In article <416@marob.MASA.COM> daveh@marob.masa.com (Dave Hammond) writes:
>Can anyone explain why the statement:
>    exit(0);	/* followed immediately by main's closing brace */
>causes lint to complain:
>(137)  warning: main() returns random value to invocation environment

Exit is not part of the C language and appears to lint (and the compiler)
as just another function call.  That it happens to free resources, close
files, and run down the process is just a handy coincidence. ;-)

To nuke this message, use return rather than exit.  In most Unix environments,
an implicit exit is linked in with crt0 anyway.

>Dave Hammond

Gregg Siegfried
grs@alobar.att.com

gwyn@smoke.BRL.MIL (Doug Gwyn ) (12/15/88)

In article <416@marob.MASA.COM> daveh@marob.masa.com (Dave Hammond) writes:
>Can anyone explain why the statement:
>    exit(0);	/* followed immediately by main's closing brace */
>causes lint to complain:
>(137)  warning: main() returns random value to invocation environment

"lint" doesn't know that exit() never returns.
Put /*NOTREACHED*/ after exit to tell "lint" this.

This discussion occurred only a few months ago..

gwyn@smoke.BRL.MIL (Doug Gwyn ) (12/15/88)

In article <11467@dartvax.Dartmouth.EDU> earleh@eleazar.dartmouth.edu (Earle R. Horton) writes:
>     How about:
>	return(exit(0));

Nope; that's a cure worse than the disease.  exit() should be
properly declared as having void result type (otherwise, "lint"
should complain about THAT), and you cannot return a void expression.

guy@auspex.UUCP (Guy Harris) (12/16/88)

 >    exit(0);	/* followed immediately by main's closing brace */
 >
 >causes lint to complain:
 >
 >(137)  warning: main() returns random value to invocation environment

See the other article in comp.lang.c/INFO-C about "incorrect" "lint"
complaints; the problem is the same - "lint" has no idea that "exit"
never returns, and therefore thinks that after it *does* return, "main"
returns by "falling off the end".  This means it doesn't return a value;
in many C implementations, returning from "main" with a particular value
causes the process to terminate with the returned value as its exit
status.  To fix this, either change

	exit(0);

to

	return 0;

(with parentheses added as per local preferences) or add

	/*NOTREACHED*/

after the "exit(0)".

rbutterworth@watmath.waterloo.edu (Ray Butterworth) (12/16/88)

In article <416@marob.MASA.COM>, daveh@marob.MASA.COM (Dave Hammond) writes:
> Can anyone explain why the statement:
>     exit(0);    /* followed immediately by main's closing brace */
> causes lint to complain:
> (137)  warning: main() returns random value to invocation environment

If your <stdlib.h> doesn't have something like "extern void /*GOTO*/ exit();"
in it (not many do), then your lint doesn't know that exit() never returns.

In that case, you have to code your example as:
        ...
        exit(0);
        /*NOTREACHED*/
    }

Most versions of lint take this comment to mean that it should pretend
that it had just processed an unconditional goto.

The big disadvantage of NOTREACHED is that lint will only tell you
something useful if you use it correctly, rather than if you forget
to use it (e.g. exit(0); x=5; return x;).

The disadvantage of NOTREACHED and GOTO is that the compiler can't
recognize them and use the knowledge to optimize the code.
Overloading a keyword, as in "extern goto exit();" in a header file
would be an ideal solution, but as you can probably guess:  that's not C.

ok@quintus.uucp (Richard A. O'Keefe) (12/16/88)

In article <1037@alobar.ATT.COM> grs@alobar.ATT.COM (Gregg Siegfried) writes:
>In article <416@marob.MASA.COM> daveh@marob.masa.com (Dave Hammond) writes:
>>Can anyone explain why the statement:
>>    exit(0);	/* followed immediately by main's closing brace */
>>causes lint to complain:
>>(137)  warning: main() returns random value to invocation environment

Note that exit() can be called *anywhere*, not just in main().
In particular, it can legitimately be called in functions which do NOT
return 'int' (e.g. many of my report-error-and-drop-dead functions are
declared 'void'), so the "return exit(0)" kludge that two posters have
suggested so far really isn't a very good idea.

If you read the lint documentation you will find that it understands some
special comments.  In particular, the way to handle things like exit()
and longjmp() is
	exit(0);
	/*NOTREACHED*/
which is reasonably clear to human readers as well.

logan@vsedev.VSE.COM (James Logan III) (12/17/88)

In article <416@marob.MASA.COM> daveh@marob.masa.com (Dave Hammond) writes:
# Can anyone explain why the statement:
# 
#     exit(0);	/* followed immediately by main's closing brace */
# 
# causes lint to complain:
# 
# ma-main.c
# ==============
# (137)  warning: main() returns random value to invocation environment

Lint does not realize that exit() does not return control back to
the function main().  Since you don't have "return <value>" as
the last statement, Lint thinks the return value of main() would be
undefined.

If you want lint to stop whining about it, change the last few
lines to:      

	exit(0);
	/*NOTREACHED*/
}

Don't ask me to give you a good reason for why lint doesn't know
about exit(); there is none.   

			-Jim

-- 
Jim Logan		logan@vsedev.vse.com
(703) 892-0002		uucp:	..!uunet!vsedev!logan
			inet:	logan%vsedev.vse.com@uunet.uu.net

john@frog.UUCP (John Woods) (12/19/88)

In article <1037@alobar.ATT.COM>, grs@alobar.ATT.COM (Gregg Siegfried) writes:
> In article <416@marob.MASA.COM> daveh@marob.masa.com (Dave Hammond) writes:
> >Can anyone explain why the statement:
> >    exit(0);	/* followed immediately by main's closing brace */
> >causes lint to complain:
> >(137)  warning: main() returns random value to invocation environment
>To nuke this message, use return rather than exit.

Even better is:

	main() {
		do_something_important();
		exit(0);
		/* NOTREACHED */
	}

the /* NOTREACHED */ lint directive instructs lint as to exactly what is going
on.  It also instructs the reader as to exactly what is going on.

It would have been nice if lint could have been taught that lint-library
functions with a definition something like

	void exit(n) int n; { /* NOTREACHED */ }

will never return, but on the other hand, making that manifest for the reader
in the place of use has benefits.
-- 
John Woods, Charles River Data Systems, Framingham MA, (508) 626-1101
...!decvax!frog!john, john@frog.UUCP, ...!mit-eddie!jfw, jfw@eddie.mit.edu

Go be a `traves wasswort.		- Doug Gwyn

sme@computing-maths.cardiff.ac.uk (Simon Elliott) (12/19/88)

In article <11467@dartvax.Dartmouth.EDU>, earleh@eleazar.dartmouth.edu (Earle R. Horton) writes:
> In article <416@marob.MASA.COM> daveh@marob.masa.com (Dave Hammond) writes:
> >Can anyone explain why the statement:
> >    exit(0);	/* followed immediately by main's closing brace */
> >causes lint to complain:
> >(137)  warning: main() returns random value to invocation environment

>	[discussion deleted] 
>      How about:

> 	return(exit(0));
> }

Well, in my manual (Section 2: 'Lint, a C Program Checker' by S.C.Johnson)
there is a section entitled 'Shutting Lint Up', with a comment to the effect
that sometimes the programmer is smarter than lint.

Following is a discussion  of the directives (syntactically comments) that
a programmer can use to let lint know that the programmer really knows what
(s)he is doing.  Among these are:

/*VARARGS*/ preceding a function definition, to let lint know it shouldn't
            complain about variable numbers of arguments to calls of the 
            following function.

/*NOTREACHED*/ to let lint know that a particular spot in the code is
            never executed.

There are several more such directives.

-- 
--------------------------------------------------------------------------
Simon Elliott            Internet: sme%v1.cm.cf.ac.uk@cunyvm.cuny.edu
UWCC Computer Centre     JANET:    sme@uk.ac.cf.cm.v1
40/41 Park Place         UUCP:     {backbones}!mcvax!ukc!reading!cf-cm!sme
Cardiff, Wales           PHONE:    +44 222 874300

stuart@bms-at.UUCP (Stuart Gathman) (12/20/88)

In article <416@marob.MASA.COM>, daveh@marob.MASA.COM (Dave Hammond) writes:
> Can anyone explain why the statement:

>     exit(0);	/* followed immediately by main's closing brace */

> causes lint to complain?

Lint does not know that exit(int) is an example of a 'goto' function, i.e.
a function that never returns.  Someone suggested on the net that 'goto'
should be used in a manner similar to 'void' in function declarations
of exit(), longjmp(), and friends to indicate this.  The compiler could
then generate better code (use goto instead of call, don't bother popping
arguments, no need to flush cached variables, etc.).

For now, lint recognizes a magic comment, "/*NOTREACHED*/" which should
follow exit() in your example.
-- 
Stuart D. Gathman	<stuart@bms-at.uucp>
			<..!{vrdxhq|daitc}!bms-at!stuart>

aaron@satco.UUCP (Aaron Pelton) (12/20/88)

In article <719@auspex.UUCP>, guy@auspex.UUCP (Guy Harris) writes:
> 
>  >    exit(0);	/* followed immediately by main's closing brace */
>  >causes lint to complain:
>  >(137)  warning: main() returns random value to invocation environment
> 
> status.  To fix this, either change
> 	exit(0);
> to
> 	return 0;
> (with parentheses added as per local preferences) or add
> 	/*NOTREACHED*/
> after the "exit(0)".

   This raises the question of what return does at the end of main as opposed
to what exit does. It is stated that exit() does assorted cleanup jobs. return
seems only to be specified as exiting a function.

Given the following:
main()
{
	printf("hello world\n");
	exit(0);
}

and the same with return(0) in place of exit, I came up with a grand total
of four lines difference in asm code. exit() seemed to be called in both
cases.

    Is exit() garuanteed to be called on exit of a program with return?

    Is there any inherent advantage of exit() over return for exiting main?

    Is there any danger in randomly switching from one to the other?
-- 
Aaron Pelton		    | If it sounds like an opinion, it's probably mine.
aaron@satco.UUCP            | Only R. Crusoe could have it all done by Friday
{decvax,uunet}!virgin!satco!aaron | So much for self taught C programming.....

guy@auspex.UUCP (Guy Harris) (12/21/88)

>    Is exit() garuanteed to be called on exit of a program with return?

All the UNIX C implementations I know of call "exit()" if you return
from "main()".  I think the dpANS explicitly requires this.

>    Is there any inherent advantage of exit() over return for exiting
>    main?

In dpANS C, and in any implementation that, when the ANS comes out, is
conformant to the ANS, no.  The return value of "main" is the exit
status passed to "exit()".

In some UNIX C implementations, yes; returning from "main()" always
causes "exit()" to be called with an argument of 0.  (This is true in
SunOS releases from 2.0 to 3.5, I think; this was fixed in 4.0.  I
remember somebody claiming it was true of some Amdahl UTS release as
well.)

In non-UNIX releases, it may also be true; I don't know which of them
either 1) cause "exit()" to be called if you return from "main()" or 2)
use the return value of "main()" as the argument to "exit()".

>    Is there any danger in randomly switching from one to the other?

"Randomly"?  As in

	if (rand() & 0x80)
		exit(1);
	else
		return 1;

If you know your code is always going to be built and run on an
implementation that does it right, no, they're equivalent.  Otherwise,
"exit()" is safer.

karl@haddock.ima.isc.com (Karl Heuer) (12/21/88)

In article <138@bms-at.UUCP> stuart@bms-at.UUCP (Stuart Gathman) writes:
>Someone suggested on the net that 'goto' should be used in a manner similar
>to 'void' in function declarations of exit(), longjmp(), and friends ...

I agree with the concept, but I think that overloading yet another keyword
would be a big mistake.

>The compiler could then generate better code (use goto instead of call, don't
>bother popping arguments, no need to flush cached variables, etc.).

Note that some of these optimizations would not always be legal if the
function is longjmp(), or any function which might call longjmp().

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

jeff@amsdsg.UUCP (Jeff Barr) (12/22/88)

In article <11467@dartvax.Dartmouth.EDU>, earleh@eleazar.dartmouth.edu (Earle R. Horton) writes:
> In article <416@marob.MASA.COM> daveh@marob.masa.com (Dave Hammond) writes:
> >Can anyone explain why the statement:
> >
> >    exit(0);	/* followed immediately by main's closing brace */
> >
> >causes lint to complain:
> >
> >ma-main.c
> >==============
> >(137)  warning: main() returns random value to invocation environment
> 

How about:

	void main ()
	{
	 ...

	 exit (0);
	}

						Jeff
-- 
	 /-------------------------------------------------------\
	/  Jeff Barr   AMS-DSG   uunet!amsdsg!jeff   800-832-8668 \
	\  American Express: "Don't leave $HOME without it".	  /
	 \-------------------------------------------------------/

guy@auspex.UUCP (Guy Harris) (12/22/88)

>How about:
>
>	void main ()
	...

Doesn't help (I tried it), and isn't correct anyway.  The dpANS
indicates, as I remember, that "main" is expected (at least in a hosted
environment) to return an "int", and that if "main" returns "exit" is
then called with its return value as an argument.

karl@haddock.ima.isc.com (Karl Heuer) (12/23/88)

In article <179@amsdsg.UUCP> jeff@amsdsg.UUCP (Jeff Barr) writes:
>> >(137)  warning: main() returns random value to invocation environment
>How about:
>	void main () { ... exit (0); }

(a)  It doesn't work, at least on the machine I tried.
(b)  According to the dpANS, the type of `main' must be either `int(void)' or
`int(int, char **)'.  A `void' declaration, although logically correct, cannot
be used in a strictly conforming program.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

gwyn@smoke.BRL.MIL (Doug Gwyn ) (12/27/88)

In article <179@amsdsg.UUCP> jeff@amsdsg.UUCP (Jeff Barr) writes:
>How about:
>	void main ()
>	{
>	 ...

Don't do this!  Declare your types properly!  Whatever is calling
main() is expecting it to have a certain "shape" (that of a function
with two arguments and returning an int); ANSI C requires that the
compiler be able to compensate for the arguments being omitted, but
not for the return type being garbled.

dave@micropen (David F. Carlson) (12/28/88)

In article <782@auspex.UUCP>, guy@auspex.UUCP (Guy Harris) writes:
> >How about:
> >
> >	void main ()
> 	...
> 
> Doesn't help (I tried it), and isn't correct anyway.  The dpANS
> indicates, as I remember, that "main" is expected (at least in a hosted
> environment) to return an "int", and that if "main" returns "exit" is
> then called with its return value as an argument.

int main()	{
 ....
 if (blah) exit(-1);

 ...
 return( 0 );
}

I have solved this "problem" by not using the function exit() to return
to the calling environment main() status.  Rather, use return at the end
of main().  Lint seems to like return from functions.  It never has been
able to deal with exit() properly, ("statement not reached", etc.) so why 
try?


-- 
David F. Carlson, Micropen, Inc.
micropen!dave@ee.rochester.edu

"The faster I go, the behinder I get." --Lewis Carroll

badri@valhalla.ee.rochester.edu (Badri Lokanathan) (12/28/88)

In article <599@micropen>, dave@micropen (David F. Carlson) writes:
> I have solved this "problem" by not using the function exit() to return
> to the calling environment main() status.  Rather, use return at the end
> of main().  Lint seems to like return from functions.  It never has been
> able to deal with exit() properly, ("statement not reached", etc.) so why 
> try?
> 
Alas, some of us (at least I) have gotten used to the easy clean up facility
that exit() provides. That is, flushing all I/O buffers and closing
them. return(status) works cleanly if the programmer takes care of
this. I have personally not had this problem with return/exit in lint, so I
shall continue to use exit (maybe I should use egress as PT Barnum once
did :-)
-- 
"I care about my fellow man              {) badri@ee.rochester.edu
 Being taken for a ride,                //\\ {ames,cmcl2,columbia,cornell,
 I care that things start changing     ///\\\ garp,harvard,ll-xn,rutgers}!
 But there's no one on my side."-UB40   _||_   rochester!ur-valhalla!badri

nevin1@ihlpb.ATT.COM (Liber) (12/28/88)

In article <11274@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>(b)  According to the dpANS, the type of `main' must be either `int(void)' or
>`int(int, char **)'.  A `void' declaration, although logically correct, cannot
>be used in a strictly conforming program.

It is only logically correct when exit() is "reachable" from all possible
executions of main().  It may not be logically correct if someone
recursively calls main() and expects a return value.  What value main()
returns and if main() calls some funky function so that it never
returns are two different issues.
-- 
NEVIN ":-)" LIBER  AT&T Bell Laboratories  nevin1@ihlpb.ATT.COM  (312) 979-4751

bill@twwells.uucp (T. William Wells) (12/29/88)

In article <599@micropen> dave@micropen (David F. Carlson) writes:
: I have solved this "problem" by not using the function exit() to return
: to the calling environment main() status.  Rather, use return at the end
: of main().  Lint seems to like return from functions.  It never has been
: able to deal with exit() properly, ("statement not reached", etc.) so why
: try?

Try putting /*NOTREACHED*/ after the exit(). That shuts up every lint
I know about. It's in the manual.

---
Bill
{uunet|novavax}!proxftl!twwells!bill

bill@twwells.uucp (T. William Wells) (12/29/88)

In article <1700@valhalla.ee.rochester.edu> badri@valhalla.ee.rochester.edu (Badri Lokanathan) writes:
: Alas, some of us (at least I) have gotten used to the easy clean up facility
: that exit() provides. That is, flushing all I/O buffers and closing
: them. return(status) works cleanly if the programmer takes care of
: this. I have personally not had this problem with return/exit in lint, so I
: shall continue to use exit (maybe I should use egress as PT Barnum once
: did :-)

Returning from main does all these things on every system I know of.
In other words,

main()
{
	...
	return (0);
}

and

main()
{
	...
	exit(0);
}

are pretty much equivalent. Generally, main is called from another
routine which, besides setting up the C run-time environment, does
something like:

crt0(argc, argv)
{
	exit(main(argc, argv));
}

The only exception that I know of to this are systems, like certain
versions of SunOS, that behave more like:

crt0(argc, argv)
{
	main(argc, argv);
	exit(0);
}

---
Bill
{uunet|novavax}!proxftl!twwells!bill

chris@mimsy.UUCP (Chris Torek) (12/30/88)

This has been mentioned before but I had better do it again:

>In article <599@micropen> dave@micropen (David F. Carlson) writes:
>>... Rather, use return at the end of main().

In article <1700@valhalla.ee.rochester.edu> badri@valhalla.ee.rochester.edu
(Badri Lokanathan) writes:
>Alas, some of us (at least I) have gotten used to the easy clean up facility
>that exit() provides. That is, flushing all I/O buffers and closing
>them. return(status) works cleanly if the programmer takes care of this.

In what the dpANS calls a hosted environment---that is, in all the
interesting cases; in freestanding environments like a Unix kernel,
one generally cannot exit at all---return(expr) from main and
exit(expr) have identical effects.  The startup code that calls main
reads, essentially,

	exit(main(argc, argv, envp));

There are a few exceptions, notably some versions of SunOS.  These
read

	(void) main(argc, argv, envp);
	exit(0);

so that return(expr) from main is the same as exit(0).  There should
never be any difference between

	main() { return (0); }

and

	main() { exit(0); }

even on the buggiest implementations around.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

mcdonald@uxe.cso.uiuc.edu (12/30/88)

>In what the dpANS calls a hosted environment---that is, in all the
>interesting cases; in freestanding environments like a Unix kernel,
>one generally cannot exit at all---return(expr) from main and
>exit(expr) have identical effects.  

There are, in the PC world, cases of non-hosted environments that are
relatively common - programs run under Microsoft Windows and the
OS/2 presentation manager are non-hosted environments. They don't
have main() at all. No argv and argc. And many of the standard library
routines don't work (getc and putc are missing, for example). I think
that they are certainly "interesting". Sickening, but interesting.

Doug McDonald

P.S. Inside a MS Windows program, it would be possible to write the
various subroutines and call a "main" in the usual way. For some
odd reason they haven't done it.

gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/02/89)

In article <1700@valhalla.ee.rochester.edu> badri@valhalla.ee.rochester.edu (Badri Lokanathan) writes:
>Alas, some of us (at least I) have gotten used to the easy clean up facility
>that exit() provides. That is, flushing all I/O buffers and closing
>them. return(status) works cleanly if the programmer takes care of
>this.

Oh, come on.  Return from main() is ALSO supposed to do this; it's
practically like a coroutine jump to exit() with the return value
being passed to exit as its argument.

The real problem comes when you try to return a non-zero termination
status via "return N;" from main() on a system like some releases of
SunOS where the run-time start-off code has been "hot wired" to force
an exit(0) whenever main returns.  That was a mistake that needs to
be fixed, but small consolation if it bites you.

msb@sq.uucp (Mark Brader) (01/05/89)

[If you see two versions of this, it's not my fault, I cancelled the first.]

To a comment about:
> > ... easy clean up facility
> > that exit() provides. That is, flushing all I/O buffers and closing
> > them. return(status) works cleanly if the programmer takes care of
> > this.

Doug Gwyn replies:
> Oh, come on.  Return from main() is ALSO supposed to do this; it's
> practically like a coroutine jump to exit() with the return value
> being passed to exit as its argument.

Personally I prefer to think of it as "It's as if the system started
the program by calling exit(main(...));", but it amounts to the same thing.

However, in a later article Doug says:
> exit(), which on systems conforming to the C
> standard will flush STDIO buffers and invoke any functions registered
> via atexit() ...

And this tips us to his unstated assumption.  Doug is talking about ANSI C,
which doesn't quite exist yet.  (Nearly -- the draft has been finalized and
submitted to X3, I hear tell -- but not yet.)  In the meantime, we can't
strictly call an implementation wrong if it complies with the original
C Reference Manual -- K&R appendix A.

And that Appendix doesn't mention main() at all, let alone the return
from main().  For that matter, it doesn't mention exit() either.  Status
returns through the argument of exit() *are* mentioned in the (tutorial)
body of the book, but the return from main() is not mentioned there either.

So systems where the return from main() is not equivalent to exit() are
not exactly wrong -- only old-fashioned, and soon to be nonstandard.
In the meantime, the cautious programmer will call exit().

Actually, in all of the foregoing I should speak of the return from the
*initial* call of main().  [Reference in draft standard: section 2.1.2.2]
The function could also be called recursively, and a return from an inner
call is in no way special.

Mark Brader			"... one of the main causes of the fall of
SoftQuad Inc., Toronto		 the Roman Empire was that, lacking zero, they
utzoo!sq!msb			 had no way to indicate successful termination
msb@sq.com			 of their C programs."		-- Robert Firth