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.