Strange return codes from old but good C program

Ian Smith smithi at nimnet.asn.au
Tue May 19 18:02:46 UTC 2015


In freebsd-questions Digest, Vol 572, Issue 1, Message: 22
On Mon, 18 May 2015 13:55:07 +0200 Polytropon <freebsd at edvax.de> wrote:

 > On Sun, 17 May 2015 19:45:09 +0000 (UTC), Will Parsons wrote:
 > > I don't have the actual C standard, but Harbison & Steele's "C - A
 > > Reference Manual" (which I think can be relied on) states "If the end
 > > of the body of *main* is reached without returning, it is treated as
 > > if *return 0;* were executed".
 > 
 > In that case, no random return codes should appear. It also
 > doesn't meet the little test I've wrote (which again matches
 > with the initially described problem).

Quite closely I think, exiting after an executed for loop.

 > I have written (haha) the following "test case":
 > 
 > % cat returntest.c
 > main() {
 >         int i, j;
 >         for(i = 0, j = 0; i < 100; i++)
 >                 j += i;
 > }
 > 
 > There are two "error" in it: main() doesn't have a return
 > type assigned, so per standard (int) will be assumed. And
 > there is no return statement.
 > 
 > Compiler is system's gcc (older system, obviously):
 > 
 > % cc -Wall -o returntest returntest.c 
 > returntest.c:1: warning: return type defaults to 'int'
 > returntest.c: In function 'main':
 > returntest.c:5: warning: control reaches end of non-void function
 > 
 > This is what we expect.
 > 
 > But the program can be run, and we see:
 > 
 > % ./returntest ; echo $?
 > 99
 > 
 > The return code is somehow assigned to the 'i' variable.
 > Why? Probably because it's stored in a register, and this
 > register is being used by the exit() and _exit() chain to
 > represent the return code.
 > 
 > Funnily, when the program is modified:
 > 
 > main() {
 >         int i, j;
 >         for(i = 0, j = 0; i > -100; i--)
 >                 j += i;
 > }
 > 
 > The compiler warnings are the same. This is the result now:
 > 
 > % ./returntest ; echo $?
 > 157

Not funnily, indicatively; 157 = 0x9d. -99 = 0xffffff9d, as an int.
Exit codes would thus appear to be truncated to 0-255 unsigned.

If you swapped assignments of i and j, I suspect you may get
the unsigned value of the low byte of j as exit code instead?

 > None of them looks like an implicit "return 0;". I am not
 > judging Harbison & Steele, I'm just observing things. :-)

Real Code beats 'should' every time :)  Thanks for this, and your 
earlier reply.

Of course, one could track down which register it is by disassembling 
the binary or - likely easier - by asking $CC for a listing, if it goes 
as far as exiting without heading off into a library call .. but I'm not 
going down that rabbit hole for mere curiosity :)

cheers, Ian


More information about the freebsd-questions mailing list