bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: GCC optimizes integer overflow: bug or feature?


From: Matthew Woehlke
Subject: Re: GCC optimizes integer overflow: bug or feature?
Date: Thu, 21 Dec 2006 16:03:23 -0600
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.9) Gecko/20061206 Thunderbird/1.5.0.9 Mnenhy/0.7.4.0

Dave Korn wrote:
On 20 December 2006 21:42, Matthew Woehlke wrote:
That said, I've seen even stranger things, too. For example:

foo->bar = make_a_bar();
foo->bar->none = value;

being rendered as:

call make_a_bar
foo->bar->none = value
foo->bar = <result of make_a_bar()>

So what was wrong with my C code in that instance? :-)

  You'd have to show me the actual real code before I could tell you whether
there was a bug in your code or you hit a real bug in the compiler.  Either is
possible; the virtual machine definition in the standard AKA the 'as-if' rule
is what decides which is correct and which is wrong.

I no longer have the exact code, and I am not able to reproduce it with the STC I wrote. But it would have either looked something like what follows, or it pre-dated the "funky" code, in which case it would be the same, except no 'make_node' and the 'make_node' line would instead be "list->head = (PNODE)malloc(sizeof(NODE))"...

typedef struct _NODE {
    struct _NODE * prev;
    struct _NODE * next;
    void * data;
} NODE, * PNODE;

typedef struct {
    PNODE head;
    PNODE tail;
    BOOL funky;
} LIST, * PLIST;

static void make_node(PLIST list, PNODE* node)
{
    NODE dummy;
    if (list->funky)
        *node = &dummy;
    else
        *node = (PNODE)malloc(sizeof(NODE));
}

void init_list(PLIST list, BOOL funky)
{
    list->funky = funky;

    make_node(list, &(list->head));
    list->head->next = list->head;
    list->head->prev = list->head;
    list->head->data = NULL;
    list->tail = list->head;
}

...and, as I said, what was happening is it would call make_node/malloc, leave the result sitting in a register (I *suspect* it was broken before make_node, but if not, obviously make_node is being inlined for the problem to occur), then would happily dereference 'list->head->next' in order to assign that value, while 'list->head' is still in an undefined state. And it would do this *again*, starting with 'list' and making the two needed dereferences, to assign 'list->head->prev'. Then after doing that, it put the new node's pointer in memory. Obviously, the result was a SEGV trying to dereference list->head.

However, I should also note that I *think* the compiler at the time was gcc 3.2.3 so chances are this was fixed a long time ago (if it truly is a compiler bug).

AFAIK nothing is declared 'volatile', but even if list->head *was* (which would explain why the compiler doesn't cache list->head... or (ahem) use the new value that is already in a register), I would still argue that the compiler botched handling of it.

Case in point: I've seen gcc do some strange things. :-)

I'd be interested if you consider anything in the above code to be "broken", because we probably do stuff like the above all over the place.

--
Matthew
We interrupt this e-mail to bring you a lame signature attempting to be witty.





reply via email to

[Prev in Thread] Current Thread [Next in Thread]