This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug tree-optimization/22591] [4.0/4.1 Regression] std::swap() followed by list::erase() produces incorrect list::begin()
- From: "steven at gcc dot gnu dot org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: 26 Jul 2005 11:18:48 -0000
- Subject: [Bug tree-optimization/22591] [4.0/4.1 Regression] std::swap() followed by list::erase() produces incorrect list::begin()
- References: <20050721155650.22591.Simon.Finn@reify.co.uk>
- Reply-to: gcc-bugzilla at gcc dot gnu dot org
------- Additional Comments From steven at gcc dot gnu dot org 2005-07-26 11:18 -------
My version of t.c:
===========================================
void abort ();
typedef struct _Node
{
struct _Node *next, *prev;
} Node;
void __attribute__ ((noinline)) append (Node * q, Node * p)
{
p->next = q;
p->prev = q;
q->next = p;
q->prev = p;
}
inline void
swap (Node ** a, Node ** b)
{
Node *tmp = *a;
*a = *b;
*b = tmp;
}
/* Miscompilation seems to happen here. If one removes the if condition
(which should be true) the program works fine. */
void
ListSwap (Node * x, Node * y)
{
Node *tmp;
if (x->next)
{
swap (&x->next, &y->next);
swap (&x->prev, &y->prev);
x->next->prev = x->prev->next = x;
y->next->prev = y->prev->next = y;
}
}
int
main ()
{
Node A, A1, B, B1;
append (&A, &A1);
append (&B, &B1);
ListSwap (&A, &B);
if (&A != A.next->prev)
abort ();
}
===========================================
compiled with:
$ ./xgcc -B. t.c -O2 -m32 -march=pentium4 -da -fdump-tree-vars
gives me this for ListSwap:
===========================================
ListSwap (x, y)
{
struct Node * * a;
struct Node * * b;
struct Node * tmp;
struct Node * * a;
struct Node * * b;
struct Node * tmp;
struct _Node * D.1621;
struct _Node * D.1614;
<bb 0>:
D.1614 = x->next;
if (D.1614 != 0B) goto <L0>; else goto <L1>;
<L0>:;
a = &x->next;
b = &y->next;
tmp = *a;
*a = *b;
*b = tmp;
a = &x->prev;
b = &y->prev;
tmp = *a;
*a = *b;
*b = tmp;
x->prev->next = x;
D.1614->prev = x;
D.1621 = y->next;
y->prev->next = y;
D.1621->prev = y;
<L1>:;
return;
}
===========================================
Look at D.1614. It is loaded befoe the conditional, and later there is
a store to D.1614->prev. But isn't x->next already something else by
then? After all, x->next and y->next are swapped. I checked with Serge
Belyshev and he agrees this looks fishy:
/QUOTE/
> a = &x->next;
> b = &y->next;
...
> *a = *b;
this changes x->next
> D.1614->prev = x;
but this still uses old value of x->next
/QUOTE/
--
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22591