[comp.lang.c] YALF

wsmith@m.cs.uiuc.edu (12/08/88)

Lint believes this simple program has both return(e); and just return;

function()
{
	int flag;
	do{
		return(3);
	} while(flag);
}

I suppose this should be added to the canonical collection of lint foulups.

Bill Smith
wsmith@cs.uiuc.edu
uiucdcs!wsmith

kolding@june.cs.washington.edu (Eric Koldinger) (12/14/88)

Bill Smith writes:
>Lint believes this simple program has both return(e); and just return;
>function()
>{
>	int flag;
>	do{
>		return(3);
>	} while(flag);
>}

  And so it does....

function()
{
	int flag;
	do{
		return(3);  /*  return(e) here */
	} while(flag);
    /* implied return here */
}

Lint can't determine where it will drop out, it only determines if there
is a path that could be executed to get there.  Something about the halting
problem, I believe....

-- 
	_   /|				Eric Koldinger
	\`o_O'				University of Washington
  	  ( )     "Gag Ack Barf"	Department of Computer Science
       	   U				kolding@cs.washington.edu

jdc@naucse.UUCP (John Campbell) (12/14/88)

From article <4700030@m.cs.uiuc.edu>, by wsmith@m.cs.uiuc.edu:
: 
: Lint believes this simple program has both return(e); and just return;
: 
: function()
: {
: 	int flag;
: 	do{
: 		return(3);
: 	} while(flag);
: }
: 
: I suppose this should be added to the canonical collection of lint foulups.
: 
: Bill Smith
: wsmith@cs.uiuc.edu
: uiucdcs!wsmith

If I had a piece of code like that I'd surely want lint to tell me about it.
Perhaps another look and I'd change it :-) 

-- 
	John Campbell               ...!arizona!naucse!jdc
                                    CAMPBELL@NAUVAX.bitnet
	unix?  Sure send me a dozen, all different colors.

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

>Lint believes this simple program has both return(e); and just return;

"lint" has no way of knowing, given its somewhat unsophisticated
analysis, that the loop never terminates; if it *did* terminate, the
function *would* have something that amounts to just a "return;".

>I suppose this should be added to the canonical collection of lint foulups.

No, because there is actually an "lint" feature to be used in this case;
just stick

	/*NOTREACHED*/

after the loop in question to convince "lint" that the loop really
doesn't terminate.

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

In article <6720@june.cs.washington.edu>, kolding@june.cs.washington.edu (Eric Koldinger) writes:
> Bill Smith writes:
> >Lint believes this simple program has both return(e); and just return;
> >function()
> >{
> >   int flag;
> >   do{
> >       return(3);
> >   } while(flag);
> >}
> And so it does....
> Lint can't determine where it will drop out, it only determines if there
> is a path that could be executed to get there.

Not true.  Replace the "return(3)" with a "goto label" and put a label
in front of the do statement.  You'll get the same messages from lint.
Lint knows what a goto does since it is part of the language.
It also knows what a return does since it too is part of the language.
Had it been written "return 3;" instead of like a function "return(3);"
this would have been more obvious.  Some versions of lint do know about
functions that don't return (declared as "extern /*GOTO*/ abort();"),
but most don't.

In any case, lint should have produced two warnings, not only the one
that was wrong:
  xx.c(10): warning: statement not reached
  xx.c(11): warning: function "func" has return(e); and return;

The first was correct, since the "while" part is never executed.
But after issuing a "not reached" warning, lint resets its flag
that indicates that the code has not been reached, and thus it
thinks the next line really is reached and gives the second warning.

It has to be this way, otherwise something like:
  goto label;
  a = 1;
  b = 2;
  ...
  z = 26;
would cause 26 "statement not reached" messages.
After complaining that "a = 1;" is not reached, you really don't
want to see the other 25 messages.

Consider it like getting 200 lines of compiler errors.
Only the first few probably make any sense.
The rest are either caused by the first mistakes, or are caused
by the compiler's attempts to recover after those mistakes.

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

In article <4700030@m.cs.uiuc.edu> wsmith@m.cs.uiuc.edu writes:
# 
# Lint believes this simple program has both return(e); and just return;
# 
# function()
# {
# 	int flag;
# 	do{
# 		return(3);
# 	} while(flag);
# }
# 
# I suppose this should be added to the canonical collection of lint foulups.

The function itself is a foulup.  First, you haven't initialized
"flag", and second, the function can be replaced with:  

	#define function()	3

What's the point?  Returning from the middle of a loop is poor
programming!

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

henry@utzoo.uucp (Henry Spencer) (12/17/88)

In article <717@auspex.UUCP> guy@auspex.UUCP (Guy Harris) writes:
>just stick
>
>	/*NOTREACHED*/
>
>after the loop in question to convince "lint" that the loop really
>doesn't terminate.

And as a not-so-minor bonus, in a non-trivial program with a non-trivial
loop cluttered with other code, this also makes it rather more obvious
to *humans* that the loop is not supposed to terminate.
-- 
"God willing, we will return." |     Henry Spencer at U of Toronto Zoology
-Eugene Cernan, the Moon, 1972 | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

mat@mole-end.UUCP (Mark A Terribile) (12/18/88)

For the code fragment:

	. . .
	do
	{
		return 1 ;
	} while( 0 )
}
> "lint" has no way of knowing, given its somewhat unsophisticated
> analysis, that the loop never terminates; ...
> function *would* have something that amounts to just a "return;".
...
> ... there is actually a "lint" feature to be used in this case:
> 
> 	/*NOTREACHED*/

I believe that /*NOTREACHED*/ is for things like exit(), which cannot return
at all.  Given that LINT professes to know about variables used before set,
it is certainly LINT's business to do a little basic flow analysis.  It
would be nice if LINT would warn that this ``loop'' does not and can not loop.

The parsing and data type analysis that LINT actually must do is much
hairier than the linked-list games that you play to find out what is and
isn't reached.  Moreover, it would help LINT to get the used/set checks
right.

With ANSI C and function prototypes, we may hope that LINT goes away.  We
now understand better what sort of checks to apply (Bjarne Stroustrup's C++
processors do a much better job than LINT, and without the extraneous noise)
and it makes sense to put them in the compiler.
-- 

(This man's opinions are his own.)
From mole-end				Mark Terribile

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

>I believe that /*NOTREACHED*/ is for things like exit(), which cannot return
>at all.  Given that LINT professes to know about variables used before set,
>it is certainly LINT's business to do a little basic flow analysis.  It
>would be nice if LINT would warn that this ``loop'' does not and can not loop.

That's nice; unfortunately, the S5R3 "lint" doesn't really back this
belief up - it merely gives "exit()" as an example, and just says that
"at appropriate points (it) stops comments about unreachable code." It
would be nice if "lint" did a better job of flow analysis; however,
until it does, I see little point in *not* using /*NOTREACHED*/ to quiet
the noise from "lint" so that one can do a better job of finding the
signal.

>With ANSI C and function prototypes, we may hope that LINT goes away.  We
>now understand better what sort of checks to apply (Bjarne Stroustrup's C++
>processors do a much better job than LINT, and without the extraneous noise)
>and it makes sense to put them in the compiler.

Well, perhaps.  Some of the "-h" checks ("h" can stand either for
"heuristic" or "hack") are useful, even though they could be considered
hacks; they warn of perfectly legal constructs that are generally the
result of a slip of the fingers.

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

In article <122@mole-end.UUCP> mat@mole-end.UUCP (Mark A Terribile) writes:
>With ANSI C and function prototypes, we may hope that LINT goes away.

Rather, we may hope that *certain features* of lint will migrate into the
code-generating compiler.  But there are still uses for lint.  For example,
the exit() example that started this discussion is still within the
jurisdiction of lint, since ANSI C doesn't distinguish void-valued functions
from non-returning functions.

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 <11245@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>... since ANSI C doesn't distinguish void-valued functions
>from non-returning functions.

What do you mean?  Function value type and whether a function returns
are orthogonal.

cmf@cisunx.UUCP (Carl M. Fongheiser) (12/31/88)

In article <9228@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>In article <11245@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>>... since ANSI C doesn't distinguish void-valued functions
>>from non-returning functions.
>
>What do you mean?  Function value type and whether a function returns
>are orthogonal.

Really?  I'm having a good deal of difficulty thinking of any reason why
one would declare a function which never returns as anything other than
void.

				Carl Fongheiser
				University of Pittsburgh
				...!pitt!cisunx!cmf
				cmf@unix.cis.pittsburgh.edu

raeburn@athena.mit.edu (Ken Raeburn) (01/01/89)

In article <14672@cisunx.UUCP> cmf@unix.cis.pittsburgh.edu (Carl M. Fongheiser) writes:
>In article <9228@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>>What do you mean?  Function value type and whether a function returns
>>are orthogonal.
>Really?  I'm having a good deal of difficulty thinking of any reason why
>one would declare a function which never returns as anything other than
>void.

How about type consistency?  Consider a library package which lets you
supply procedures to run, and expects a structure returned; some
compilers would allocate an invisible first argument telling you where
to put the structure.  If you want your procedure to read its
arguments properly -- even if it's going to do nothing more than print
them out and exit or abort -- its return value must be declared
properly.  (Okay, so I can't name such a package offhand.  The example
is still valid....)

Declaring it as returning some (non-void) type when it is known not to
return is pointless when you've got your choice, but if you have to
mesh with some existing scheme you have to do it anyways.

~~ Ken

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

In article <14672@cisunx.UUCP> cmf@unix.cis.pittsburgh.edu (Carl M. Fongheiser) writes:
>In article <9228@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>>Function value type and whether a function returns are orthogonal.
>Really?  I'm having a good deal of difficulty thinking of any reason why
>one would declare a function which never returns as anything other than
>void.

Where did you get the word "never"?

	unsigned int Square(unsigned int n)
	{	extern void exit(int);
		extern void /*also nonreturning*/ Fatal(char*);
		if (n >= 0x80)
			Fatal("overflow in Square");
		return n*n;
	}

This, not entirely implausible, function sometimes returns and
sometimes doesn't.  But that has nothing to do with its type.

dg@lakart.UUCP (David Goodenough) (01/04/89)

From article <9255@smoke.BRL.MIL>, by gwyn@smoke.BRL.MIL (Doug Gwyn ):
> In article <14672@cisunx.UUCP> cmf@unix.cis.pittsburgh.edu (Carl M. Fongheiser) writes:
>>In article <9228@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>>>Function value type and whether a function returns are orthogonal.
>>Really?  I'm having a good deal of difficulty thinking of any reason why
>>one would declare a function which never returns as anything other than
>>void.
> 
> Where did you get the word "never"?

Probably from the same place I did for the example below

> 	unsigned int Square(unsigned int n)
> 	{	extern void exit(int);
> 		extern void /*also nonreturning*/ Fatal(char*);
> 		if (n >= 0x80)
> 			Fatal("overflow in Square");
> 		return n*n;
> 	}
> 
> This, not entirely implausible, function sometimes returns and
> sometimes doesn't.  But that has nothing to do with its type.

True, but probably irrelevant. What Mr. Fongheiser is referring to is something
like:

void command()
 {
    extern void exit();

    for (;;)
     {
	switch (getchar())
	 {
	    case 'q':
	      exit();
	    /* NOTREACHED */
	    case 'a':
	      a_command();
	    break;

		/* etc. etc. */
	 }
     }
    /* NOTREACHED */
 }

command() can NEVER (repeat NEVER) return. Hence to give it (say) type int
is not sensible, meaningful or anything.

:-) :-) smiley mode on :-) :-)
What is in fact needed is ANOTHER function type notreturning, as opposed
to void, because in one way void implies return, it also however imples
return without a corresponding return value. notreturning imples that
a function is a one way thing. lint could be made a lot more sensible
about exit() if such a thing existed, and if we could figure out how to
tell it about for (;;) without breaks, we could do away with
/* NOTREACHED */
-- 
	dg@lakart.UUCP - David Goodenough		+---+
							| +-+-+
	....... !harvard!xait!lakart!dg			+-+-+ |
AKA:	dg%lakart.uucp@xait.xerox.com		  	  +---+

nevin1@ihlpb.ATT.COM (Liber) (01/06/89)

In article <379@lakart.UUCP> dg@lakart.UUCP (David Goodenough) writes:

>What is in fact needed is ANOTHER function type notreturning, as opposed
>to void, because in one way void implies return, it also however imples
>return without a corresponding return value. notreturning imples that
>a function is a one way thing.

This really would be messy.  How would you describe the functions which
return some of the time (far more common than never returning)?  I don't
see where yet another function type buys you anything in this case, since
return value and whether or not a function returns, as Doug Gwyn (I think)
said, orthogonal issues.

What do you do if a function is non-returning and it falls off the
bottom?  Never returning is a hard property to check in C.
-- 
 _ __	NEVIN ":-)" LIBER  nevin1@ihlpb.ATT.COM  (312) 979-4751  IH 4F-410
' )  )			 "I will not be pushed, filed, stamped, indexed,
 /  / _ , __o  ____	  briefed, debriefed or numbered!  My life is my own!"
/  (_</_\/ <__/ / <_	As far as I know, these are NOT the opinions of AT&T.

wald-david@CS.YALE.EDU (david wald) (01/07/89)

In article <9341@ihlpb.ATT.COM> nevin1@ihlpb.UUCP (55528-Liber,N.J.) writes:
>What do you do if a function is non-returning and it falls off the
>bottom?  Never returning is a hard property to check in C.

Try "uncomputable."


============================================================================
David Wald                                              wald-david@yale.UUCP
waldave@yalevm.bitnet                                 wald-david@cs.yale.edu
"A monk, a clone and a ferengi decide to go bowling together..."
============================================================================

karl@haddock.ima.isc.com (Karl Heuer) (01/07/89)

In article <9341@ihlpb.ATT.COM> nevin1@ihlpb.UUCP (55528-Liber,N.J.) writes:
>In article <379@lakart.UUCP> dg@lakart.UUCP (David Goodenough) writes:
>>What is in fact needed is ANOTHER function type `notreturning' ...
>
>This really would be messy.  How would you describe the functions which
>return some of the time (far more common than never returning)?

With the type that the function has when it does return.  The information
"this function sometimes doesn't return" is not particularly useful, so
there's no point in using the language to document it.  On the other hand, if
the function never returns, then the type information (usually "void") is
generally useless.  There *is* a conceptual difference difference between
"void exit();" and "void free();".

Note that both lint and the code-generator can take advantage of the fact that
a certain function never returns, if only there were a way to tell them.

>What do you do if a function is non-returning and it falls off the bottom?

The same thing that you do with a value-returning function that falls off the
bottom: you fix the bug (with the help of lint, if it can detect it -- which
it usually can).

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

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

In article <9341@ihlpb.ATT.COM> nevin1@ihlpb.UUCP (55528-Liber,N.J.) writes:
>Never returning is a hard property to check in C.

In fact it's impossible in general, because that would imply the
existence of a perfect decision procedure.  For example, suppose
that a proof-searching function returns if and only if it finds a
proof of Fermat's last theorem.  We don't know whether or not it
will "ever" return.  (Actually, since there are finite resources
in the run-time environment, if the algorithm cannot get into an
infinite loop then it must terminate eventually, but it may well
take longer than the age of the universe to do so.)

flaps@dgp.toronto.edu (Alan J Rosenthal) (01/08/89)

nevin1@ihlpb.UUCP (55528-Liber,N.J.) writes:
>What do you do if a function is non-returning and it falls off the
>bottom?  Never returning is a hard property to check in C.

You can't check it beforehand, but you can compile in an fprintf to stderr and
an exit instead of the stack popping sequence.  It's just like array bounds
checking in Pascal.  Sometimes you can check it at compile time, sometimes the
check is delayed until run time.

Of course, this check wouldn't probably be necessary to meet the definition
of C.  Giving an error message for explicit return statements would be
sufficient.

ajr

--
"The goto statement has been the focus of much of this controversy."
	    -- Aho & Ullman, Principles of Compiler Design, A-W 1977, page 54.