Summary, including machine-specific info that may or may not be
relevant:
a) The hardware traps integer overflow, including address arithmetic
overflow. (C unsigned types use non-trapping instructions, and
in fact, C signed types generally use these as well, but the
pointer-offset address format apparently uses the trapping form
of arithmetic.)
b) The C code in question is somehow obtaining a pointer value that
lies near the end of 32-bit-integer space, 0x7ffffff8 for
instance.
c) The compiler generates non-trapping code when not optimizing, but
trapping code when optimising.
[Someone wrote:][color=blue][color=green]
>> We generally don't know MIPS assembler and as a C programmer, you
>> shouldn't care. If you care to post some C code which exhibits the
>> problem, several people here might be more able to help you.
>>
>> Note that 0x80000000 is -2147483648 or INT_MIN on 32-bit systems.[/color][/color]
In article <25a306f6.0407111302.29bd7e94@posting.google.com >
Sushil <indigodfw@yahoo.com> writes:[color=blue]
>Thanks for your reply Joe and Pete.
>
>The simplified code is like this
>magic_struct *magic_ptr = ((magic_struct *) ((uchar *) ptr + ptr->size))- 1;
>where magic_struct contains two magic ulongs.
>
>The issue is ptr + ptr->size becomes 0x80000000 and -1 after pointer
>arithmetic is 8 bytes since sizeof(magic_struct) is 8. However, the
>compiler does not do the -8 part since it is compiled with -O3 (okay I
>know this is offtopic).[/color]
Actually, it may not be off-topic (although it is not "on" topic
either -- it might just be irrelevant, as far as conformance goes).
[color=blue]
>Instead, when magic_ptr->magic1 is referenced (later) compiler offsets
>-8 from the above address at that point. This is overflowing and
>causing an address exception.[/color]
Specifically, the compiler transforms:
struct S *p;
...
p = (expr) - 1; /* where (expr) has type "struct S *" and
points "just past the end" of an array of "struct S" */
use(p->foo);
into:
p = expr;
use(p[-1].foo);
when asked to optimize (via -O3). When not optimizing, the compiler
actually computes "p = expr - 1" as originally directed, then uses
p[0].foo to access p->foo, generating address offsets of the form
0(reg) instead of -8(reg). When optimizing, the compiler uses the
second form. As it happens, "reg" holds 0x7ffffff8 when offset by
0 (not optimizing) or 0x80000000 when offset by -8 (optimizing).
The former works, and the latter does not.
The expression I have denoted "expr" here has the general form of
"one past the last byte in an object". The C standard explicitly
allows such computations, and you may even use the second form
yourself in your C code. The system is obliged, as if by contract,
to make this work (in Standard C).
If the value in "expr" is obtained by ordinary (and conforming) C
code (see example below), the compiler optimization occurring here
causes the overall system to fail to conform. I suggest that the
bug here is either that the system is handing out "the last address"
-- it should make sure that the expression "expr" never goes "above"
0x7fffffff, i.e., it should never put an object beyond address
0x7ffffffe, and even further back from the edge for objects larger
than 1 byte -- or else the compiler must not perform the optimization
it is doing.
On the other hand, if the value in "ptr" is obtained by something
not part of Standard C, the system as a whole can still conform.
That is, the Standard C part of the system might in fact hand out
address 0x7ffffffe as a valid one-byte object, but be careful to
make sure that all valid forms of address arithmetic -- including
the "one byte past the end" cases -- never exceed 0x7fffffff. In
this case, no matter how big p is, p+1 will be 0x7fffffff at most,
and negative offsets from a register holding p will work.
Assuming the Standard C part of the system conforms (by not handing
out "address smack dab at end of address space"), whether handing
out such an address is a bug in the non-"Standard C" part of the
system is up to the non-"Standard C" part. That is, the Standard
cannot tell you whether this is right or wrong -- only the system's
own documentation about its own special non-standard extensions
and behaviors can say so.
[color=blue]
>The way I fixed it is I rearranged code
>magic_struct *magicptr = ((uchar *) ptr - sizeof(magic_struct)) +
>ptr->size;
>
>Question 1:
>Do you think this trick(the parentheses) will force it to [work] ...[/color]
Not in general, no. (Tricks involving variables marked "volatile"
will, though.)
[color=blue]
>Question 2:
>What does the language say about the address calculation.[/color]
Virtually nothing. The language *does* say that it is legal to
compute an address "one beyond the end" of any object, so if:
char *p;
size_t size;
struct S *q;
...
size = N * sizeof *q; /* where N > 0 */
p = malloc(size);
if (p == NULL) ... handle error ...
p += size;
q = p;
q[-1].field = val;
fails at runtime, the compiler fails to conform. *How* the C system
makes this work -- whether that involves any signedness of addresses,
for instance -- is not specified. On the other hand, as soon as you
write something like:
p = (char *)0x7ffffff8;
you have left the Standard behind in the dust, and can no longer
ask anything from it. You are now at the mercy of your particular
system. If:
p += 8;
q = p;
q[-1].field = val;
subsequently fails, the Standard cannot help. This is true EVEN
IF THIS OCCURS ELSEWHERE IN THE CODE, using a different value in
p! A single occurrence of "undefined behavior" anywhere officially
terminates your "contract" with the C Standard. In practice, of
course, if the original undefined behavior is harmless on your
system, it probably has no effect on "disconnected" code -- which
is handy when debugging -- but strange things can happen. (For
instance, suppose the first bit of "undefined behavior" you invoke
is something like:
_implementation_hook("set time bomb to go off in 5 minutes");
If and when the time bomb does go off, it can affect everything.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it
http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.