[comp.lang.c] gurulet aptitude test

mcdaniel@uicsrd.csrd.uiuc.edu (12/11/88)

I'm not a Gwyn/Torek/Harris-level guru, but I'll give it a shot.

Written 6:38 pm Dec 8, 1988 by jpa@celerity.UUCP in comp.lang.c:
> Please don't send me mail to tell me what the problem is
                                            ^^^
I count 12 problems with the code.  I suppose that the basis of the
problem is that the code was
> a contrived example
(as you put it) and was not linted.

Actually, not all the problems are "bugs" per se; some are just bad
style.  In this list, "struct zztop {" is designated line 1:

I     The program has no side-effects; a "decent" optimizer should
      dead-code the entire program.  :-)  However, a "decent" compiler
      wouldn't compile this program at all.

II    Line 4: the declaration of "struct zztop" was probably meant to
      have a ";" after the closing "}".  Without it, sub1()'s return
      type is "struct zztop":
            struct zztop {int a; int b;} sub1() {...}
      With a ";", sub1()'s return type is an int.  This point is
      irrelevant, really, since sub1's return value is always ignored.

III   Line 5 is an comment, but what it says is obvious from
      inspection. Comments like
		i++;	/* Increment i */
      ought to be avoided.  OK, I'll admit this one is reaching pretty
      far . . . :-)

IV    Line 10, "zz.a = 0x77777777;", is non-portable.  If "int"s are
      16 bits long, the result of assigning 0x77777777 (presumably a
      long) to the int zz.a is implementation-defined.

V     Line 12: sub1() is declared above as returning a value.
      However, no "return" statement is ever used in sub1().  It's not
      a bug because the return value of sub1() is never used.
      However, if a function doesn't return a value, I prefer to
      declare it "void".

VI    Line 13 has the first bug.  Line 11 implies that sub2 is a
      function of one argument (a struct zztop) returning int.  Line
      13 defines sub2 as a function of NO arguments, returning int.
      I'm not surprised that a coredump occurs.

VII   Line 16 is like line 10 (unportable to 16-bit machines).

VIII  Line 17: parentheses are no longer needed following "return".
      Some always use them, some don't.  I don't.  It's more or less a
      religious issue.

IX    Line 17: sub2() returns 0x77777777, but sub2()'s return type is
      int.  This will fail on 16-bit machines.

X     sub2()'s return value is always ignored.

XI    Line 22: the other unequivocal bug.  Above, sub1 was defined as
      a function returning int but taking no arguments.  Here, one
      argument is passed in.

XII   The program does not "exit()", nor does "main" return with a
      value.  On some systems, that means that the program exits with
      an undefined exit status, which is probably non-zero.  If this
      program were invoked in a Bourne-shell script under "set -e", or
      C-shell using "csh -e", the shell script would abort.  Always
      use "exit(expression)", or use "return expression;" in main().

Lint picks up many of these problems:

lint -phbxac bug.c
bug.c:
bug.c(10): warning: long assignment may lose accuracy
bug.c(16): warning: long assignment may lose accuracy
bug.c(17): warning: long assignment may lose accuracy
sub2: variable # of args.	bug.c(14)  ::  bug.c(11)
sub1: variable # of args.	bug.c(8)  ::  bug.c(22)
sub1 value is used, but none returned		<<< 1
sub2 returns value which is always ignored
_iob used( llib-port(25) ), but not defined	<<< 2

The messages marked "1" and "2" are spurious, but the rest are fine.

--

             Tim, the Bizarre and Oddly-Dressed Enchanter

Center for      |||  Internet, BITNET:  mcdaniel@uicsrd.csrd.uiuc.edu
Supercomputing  |||  UUCP:     {uunet,convex,pur-ee}!uiucuxc!uicsrd!mcdaniel
Research and    |||  ARPANET:  mcdaniel%uicsrd@uxc.cso.uiuc.edu
Development,    |||  CSNET:    mcdaniel%uicsrd@uiuc.csnet
U of Illinois   |||  DECnet:   GARCON::"mcdaniel@uicsrd.csrd.uiuc.edu"

greggy@infmx.UUCP (greg yachuk) (12/13/88)

In article <44200023@uicsrd.csrd.uiuc.edu> mcdaniel@uicsrd.csrd.uiuc.edu writes:
>II    Line 4: the declaration of "struct zztop" was probably meant to
>      have a ";" after the closing "}".  Without it, sub1()'s return
>      type is "struct zztop":
>            struct zztop {int a; int b;} sub1() {...}
>      With a ";", sub1()'s return type is an int.  This point is
>      irrelevant, really, since sub1's return value is always ignored.
       ^^^^^^^^^^
Actually, this is THE bug.  A struct is (traditionally) returned by address
(or implicitly by copying it to a generally known place).  It is then the
responsibility of the caller to not only remove the parameters from the
stack, but also to copy the returned value from where-ever to some local
place (variable or temp-location).  On a SUN-3, it appears to return the
address.  With this example code, a zero just *happens* to be the returned
value, since sub1() does not explicitly return a value.  Attempting to
dereferece location zero causes the core dump.

>             Tim, the Bizarre and Oddly-Dressed Enchanter

	-greg

Greg Yachuk	Informix Software Inc., Menlo Park, CA	(415) 322-4100
{uunet,pyramid}!infmx!greggy	why yes, I DID choose that login myself

"May I remind you that here at Atherton, Pembroke & Wills we do *not*
take fashion risks?"		-- Leo Cullum

mcdaniel@uicsrd.csrd.uiuc.edu (12/13/88)

Written  1:45 pm  Dec 12, 1988 by greggy@infmx.UUCP in comp.lang.c:
> In article <44200023@uicsrd.csrd.uiuc.edu> mcdaniel@uicsrd writes:
>>#4:          struct zztop {int a; int b;} sub1() {...}
>>      With a ";", sub1()'s return type is an int.  This point is
>>      irrelevant, really, since sub1's return value is always ignored.
>       ^^^^^^^^^^
. . .
> A struct is (traditionally) returned by address
> (or implicitly by copying it to a generally known place).
. . .
> On a SUN-3, it appears to return the
> address.  With this example code, a zero just *happens* to be the returned
> value, since sub1() does not explicitly return a value.  Attempting to
> dereference location zero causes the core dump.

It's a compiler bug.

I compiled and ran this code:
    #include <stdio.h>
    struct zztop { int a; int b; }
    sub1() { struct zztop dummy; printf("in sub1\n"); return dummy; }
    main() { printf("start main\n"); sub1(); printf("end main\n"); exit(0); }

As Greg noted, if "return dummy;" is commented out, this program core
dumps on a SUN 3 under BSD 4.2.  Quoting K&R's 2nd edition (page 225,
section A9.6):
   Flowing off the end of a function is equivalent to a "return" with
   no expression.  In either case, the returned value is undefined.

Note the wording: it says that the VALUE is undefined.  If they had
meant that this is illegal, or that the EFFECT is undefined, I think
K&R would have said so; they are usually very careful in their
terminology in the Appendix.  Therefore, I think that the core dump is
a bug in the SUN compiler, and that the code is legal dpANS C, with a
defined result, whether the "return" is commented out or not.

As a sanity check: functions written before "void" became common
usually have a return type of "int" but do not return a value.  If a
compiler were permitted to make such code illegal, MANY existing
programs would break.  I don't think that the ANSI C committee
intended to permit that.  (There's certainly nothing that says that
"int" functions are treated specially.)

> Greg Yachuk	Informix Software Inc., Menlo Park, CA	(415) 322-4100
> {uunet,pyramid}!infmx!greggy	why yes, I DID choose that login myself

--

             Tim, the Bizarre and Oddly-Dressed Enchanter

Center for      |||  Internet, BITNET:  mcdaniel@uicsrd.csrd.uiuc.edu
Supercomputing  |||  UUCP:     {uunet,convex,pur-ee}!uiucuxc!uicsrd!mcdaniel
Research and    |||  ARPANET:  mcdaniel%uicsrd@uxc.cso.uiuc.edu
Development,    |||  CSNET:    mcdaniel%uicsrd@uiuc.csnet
U of Illinois   |||  DECnet:   GARCON::"mcdaniel@uicsrd.csrd.uiuc.edu"

throopw@xyzzy.UUCP (Wayne A. Throop) (12/17/88)

> jpa@celerity.UUCP (Jeff Anderson)
> I submit it only as an interesting puzzle
> [... example appended to end of article for reference ...]

It's more than that.  It shows a place where lint gives a misleading-at-best
diagnostic.  In particular, lint says

    sub2: variable # of args.       t1.c(19)  ::  t1.c(16)
    sub1: variable # of args.       t1.c(13)  ::  t1.c(27)
    sub1 value is used, but none returned
    sub2 returns value which is always ignored

The oddity is "sub1 value is used, but none is returned".  The value
isn't, in fact, used.  But apparently many compilers generate code
which fails if a function declared to return a struct does not do so.

This problem would be much less probable if one always declared one's
function types explicitly.  And paid attention to what lint tells one,
of course.

/***************************************************\
* 						    *
* What is wrong with this program? This is a test.  *
* 						    *
\***************************************************/
struct zztop {
    int             a;
    int             b;
}
/* main calls sub1 which calls sub2 */
#define UGLY 0x77777777
sub1()
{
	struct zztop zz;
	zz.a = UGLY;
	sub2(zz);
}
sub2()
{
	struct zztop zz;
	zz.b = UGLY;
	return(UGLY);
}
main()
{
	struct zztop zz;
	sub1(&zz);
}
--
The real problem is not whether machines think, but whether men do.
                                        --- B.F. Skinner
-- 
Wayne Throop      <the-known-world>!mcnc!rti!xyzzy!throopw

friedl@vsi.COM (Stephen J. Friedl) (12/17/88)

In article <44200023@uicsrd.csrd.uiuc.edu>, mcdaniel@uicsrd.csrd.uiuc.edu writes
> I'm not a Gwyn/Torek/Harris-level guru, but I'll give it a shot. [...]

Hey, what about Henry? :-)

-- 
Stephen J. Friedl        3B2-kind-of-guy            friedl@vsi.com
V-Systems, Inc.                                 attmail!vsi!friedl
Santa Ana, CA  USA       +1 714 545 6442    {backbones}!vsi!friedl
Nancy Reagan on my new '89 Mustang GT Convertible: "Just say WOW!"