------- Comment #28 from matz at gcc dot gnu dot org  2010-01-31 20:34 -------
fejj: To see how your initial code is broken, I've transformed it a bit to
show you how it already is "miscompiled" with earlier compilers.  I've manually
unrolled the loop, and hoisted the two malloc calls to the front.
You hopefully agree that the function then is completely equivalent
to your initial testcase (assuming validity to start with).  Like so:

% cat broken.c
#include <stdio.h>
#include <stdlib.h>

typedef struct _node {
        struct _node *next;
        int value;
} Node;

int main (int argc, char **argv)
{
        Node *list, *node, *tail;
        Node *n1, *n2;
        int i;

        n1 = malloc (sizeof (Node));
        n2 = malloc (sizeof (Node));

        list = NULL;
        tail = (Node *) &list;

        node = n1;
        node->next = NULL;
        node->value = 0;
        tail->next = node;
        tail = node;

        node = n2;
        node->next = NULL;
        node->value = 2;
        tail->next = node;
        tail = node;

        if (list == NULL)
                printf ("oops, list is null???\n");
        return 0;
}

Compile this with e.g. gcc-4.3 -O2 and see it broken too.  From your blog
entry I gather that you think this has something to do with the recent gcc@
discussion about interpreting the C standard regarding accesses through unions
or similar.  This is not the case.  The code as written simply is completely
unspecified in _any_ interpretation of the standard.  To see this, add this
statement into the list:

    tail->value = tail->value;

This statement must be harmless iff tail indeed points to enough memory to
have a value member.  But in the first iteration tail points to list, a Node*,
hence it holds only enough memory for one pointer.  I.e. would you change
the order of the struct members ('value' first, 'next' second) already the
access to ->next in your original testcase would overwrite non-existing
memory (and depending on circumstance for instance valgrind would complain). 
The list variables simply is only one pointer long, not two.

I hope you see now that we don't even need to invoke aliasing arguments to
show that the testcase was invalid: In the first iteration tail points to
something that doesn't even have enough space to contain a whole Node.  We
don't even need to argue about the type of it.


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42907

Reply via email to