[comp.lang.c] IBM RT compiler weirdness

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.