Description
Bugzilla Link | 35229 |
Version | 5.0 |
OS | Linux |
Depends On | #33896 |
Blocks | #39717 |
CC | @comex,@efriedma-quic,@hfinkel,@jrmuizel,@jplatte,@aqjune,@sunfishcode,@nunoplopes,@regehr,@rnk |
Extended Description
Clang/LLVM currently miscompiles the following program:
// gvnbug.c
#include <stdio.h>
#include <stdint.h>
int foo();
void test(int* gp1, int* gp2)
{
int g = 0;
int a = 0, b = 0;
int x = 7777, y = 6666; // also try swapping these
int* p = &g;
int* q = &g;
int* r = &g;
if (foo()) {
a = 1;
p = &y+1;
q = &x;
}
*gp1 = (uintptr_t)p+1;
if (q == p) {
b = 1;
*gp2 = (uintptr_t)q+1;
r = q;
}
*r = 42;
printf("a = %d, b = %d, x = %d\n", a, b, x);
}
int main() {
int gp1 = 0;
int gp2 = 0;
test(&gp1, &gp2);
return 0;
}
// aux.c
int foo() { return 1; }
$ clang-5.0 aux.c gvnbug.c -o gvnbug -O3 && ./gvnbug
a = 1, b = 1, x = 7777
This result is not allowed. If a
and b
are both 1
, the branch q == p
must have been taken, so r
was set to &x
(via q
), so x
cannot be 7777
.
I think this issue has already come up in #33896, but so far there was no example showing that the bug arises independent of the incorrect inttoptr-simplification.
What is happening here (if my analysis is correct) is that GVN sees the equality q == p
and uses that to replace q
by p
in the then-branch. Next, LLVM notices that because p
is derived from y
, writing to r
(which will either have value &g
or p
in the line where the assignment happens) cannot possibly affect x
, and hence the initial value of x
can be propagated into the printf
. GVN is wrong to perform this kind of replacement; just because the bit representations of two pointers are equal, that doesn't mean that their provenance information is equal.
Test case by Gil Hur.