usenet@calyx.UUCP (USENET admin) (08/28/87)
Keywords:missing semicolons, lint, silent! <eat this, line-eater!> I recently ran into a problem with an IBM RT running AIX. I had a program like the following: ___ #include <stdio.h> struct junk { int a; int b; } main(argc,argv) int argc; char **argv; { int i; for (i=0; i<argc; i++) { fprintf(stderr,"argv[%d] is now <%s>\n",i,argv[i]); } exit(0); } ___ It compiled fine. Lint said nothing. But the output was garbage: it seems that the missing semi-colon after the struct definition caused argc to be given the value of argv, and argv got the value of the environment varible pointer. Now the kicker is that this doesn't occur *anywhere else* (NCR Tower XP running some SYSV-ish release, uVax II under Ultrix V1.2A, various Xenix systems we have lying around). The program runs beautifully, even though it shouldn't. Lint doesn't complain on these other systems, either. It wouldn't be so bad, but in a program of a few thousand lines, where the original problem turned up, it's a real nuisance! Has anyone else had similar experiences with the RT? Is this just IBM's bizarrity? Better yet, is there some way to make lint tell me about this? _____ Ariel Glenn {ihnp4,rutgers}!uwvax!uwmcsd1!calyx!ariel (uucp) calyx!ariel@csd1.milw.wisc.edu (Internet)
ark@alice.UUCP (08/29/87)
In article <261@calyx.UUCP>, usenet@calyx.UUCP writes: > Keywords:missing semicolons, lint, silent! > #include <stdio.h> > > struct junk { > int a; > int b; > } > > main(argc,argv) > int argc; > char **argv; > { [ program body deleted ] > It compiled fine. Lint said nothing. But the output was garbage: it seems > that the missing semi-colon after the struct definition caused argc > to be given the value of argv, and argv got the value of the environment > varible pointer. No, the missing semi-colon after the struct definition said that your program returns a "struct junk". From your description, it appears that your compiler handles structure returns by passing an extra argument to the function in question, presumably to hold the address of memory in which to place the returned structure. This is a legitimate way of doing it -- and in fact has some advantages over the way most C compilers seem to work -- but does have the disadvantage that some invalid programs which work by coincidence on most implementations will blow up on this one. In particular, a function which returns a different type from the type declared for it will result in just about the kind of problem you've described. Since main() is supposed to return an int, and you've made it return a struct, you're out of luck.
chris@mimsy.UUCP (Chris Torek) (08/30/87)
In article <261@calyx.UUCP> usenet@calyx.UUCP (USENET admin) writes: [program had] >struct junk { > int a; > int b; >} main(argc,argv) ... [due to a missing semicolon] >It compiled fine. Lint said nothing. But the output was garbage: it seems >that the missing semi-colon after the struct definition caused argc >to be given the value of argv, and argv got the value of the environment >varible pointer. This declares `main' as a structure-valued function. It is not surprising that lint did not notice anything odd about this; some improved lints may understand that main should return an integer, or not return at all, but these are no doubt rare. >Now the kicker is that this doesn't occur *anywhere else* (NCR Tower XP >running some SYSV-ish release, uVax II under Ultrix V1.2A, various Xenix >systems we have lying around). The program runs beautifully, even though >it shouldn't. Why? The only reason it did not run on the RT is that the parameter passing mechanism for structure-valued functions differs there. On these other machines, the compilers use local static memory for the structure return value, so that the call sequence works even if the caller neglects to declare a function properly. (This has other disadvantages, though.) >Better yet, is there some way to make lint tell me about this? Try including #ifdef lint thing_to_call_main() { exit(main(0, (char **)0); } #endif somewhere in the program so that lint will compare the return value of main with the argument type for exit(). -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) Domain: chris@mimsy.umd.edu Path: seismo!mimsy!chris
karl@haddock.ISC.COM (Karl Heuer) (08/31/87)
In article <8258@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >Try including > #ifdef lint > thing_to_call_main() { exit(main(0, (char **)0); } > #endif >somewhere in the program so that lint will compare the return value >of main with the argument type for exit(). Interesting idea. You should also declare "extern void exit();" (except on BSD systems where exit is misdeclared in llib-lc!) to minimize the number of new warnings. Also, some of us consider it perfectly valid practice to define main() with no arguments and/or no return value. This would elicit a warning or two if your suggested function is in place. I'd say the best thing to do is to add it to lint. There is already a partial precedent, in that some versions of lint recognize "main" as a special case so they can warn about falling off the bottom of the function. In my view, there are nine correct models for main, represented by the Cartesian product of { "main()", "main(argc, argv)", "main(argc, argv, envp)" } with { "void main()", "int main() { ... }", "int main() { ... return VALUE; }".% Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint %In the two cases where main does not return a value, it is presumed that it does not return at all. It would be nice if lint would verify this, too, but that's a separate issue.