Date: Wed, 20 May 2015 04:02:28 +1000 (EST) From: Ian Smith <smithi@nimnet.asn.au> To: Polytropon <freebsd@edvax.de> Cc: freebsd-questions@freebsd.org, andrew clarke <mail@ozzmosis.com>, Trev Roydhouse <trev@sentry.org> Subject: Re: Strange return codes from old but good C program Message-ID: <20150520032402.F69409@sola.nimnet.asn.au> In-Reply-To: <mailman.80.1431950401.17662.freebsd-questions@freebsd.org> References: <mailman.80.1431950401.17662.freebsd-questions@freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
In freebsd-questions Digest, Vol 572, Issue 1, Message: 22
On Mon, 18 May 2015 13:55:07 +0200 Polytropon <freebsd@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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20150520032402.F69409>
