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!"