llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.68k stars 11.86k forks source link

Clang miscompiles placement-new #29137

Open hubert-reinterpretcast opened 8 years ago

hubert-reinterpretcast commented 8 years ago
Bugzilla Link 28767
Version trunk
OS All
CC @asl,@DougGregor,@hfinkel,@nemanjai,@sanjoy

Extended Description

In the following program, the only iteration of the loop increments the int object pointed-to by p, and then replaces said object via q using placement-new.

Clang miscompiles at -O1 at least on x86_64-unknown-linux-gnu and powerpc64le-unknown-linux-gnu.

Observation: passes with -fno-strict-aliasing.

Observation: -mllvm -print-before-all is indistinguishable between the placement-new and the commented-out reinterpret_cast.

Online compiler: http://melpon.org/wandbox/permlink/h0aEUwT90gAnbGtv

SOURCE (<stdin>):

void *operator new(decltype(sizeof 0), void *) noexcept;
extern "C" void abort();

typedef int A;
typedef float B;

B *qq;

void foo(A *p, A *q, long unk) {
   for (long i = 0; i < unk; ++i) {
      ++*p;
      qq = new (static_cast<void *>(&q[i])) B(42);
      // Note: the following is a TBAA violation.
      //qq = &(*reinterpret_cast<B *>(static_cast<void *>(&q[i])) = B(42));
   }
}

void (*volatile fp)(A *, A *, long);

int main(void) {
   union { A x; B f; } u = { 0 };
   fp = foo;
   fp(&u.x, &u.x, 1);
   if (*qq != 42) abort();
}

COMMANDS TO REPRODUCE:

clang -O1 -o ./a.out -x c++ -std=c++11 -
./a.out

EXPECTED OUTPUT:

(rc=0)

ACTUAL OUTPUT:

Aborted (core dumped)
Return:  0x86:134

COMPILER VERSION INFO (clang -v):

clang version 4.0.0 (trunk 276983) (llvm/trunk 276982)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/local/llvm-head/bin
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.6
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.6.3
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.6
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Selected multilib: .;@m64
wheatman commented 1 year ago

This appears to still be an issue https://godbolt.org/z/73aoY656E

The shorted code which runs as expected with gcc is

// compile with -O1 -std=c++11
#include <new>
extern "C" void abort();

float foo(int *p, int *q, long unk) {
    float *qq;
   for (long i = 0; i < unk; ++i) {
      ++*p;
      qq = new (static_cast<void *>(&q[i])) float(42);
   }
   return *qq;
}

int main(void) {
   int x = 0;
   float q = foo(&x, &x, 1);
   if (q != 42) abort();
}

One thing that might be relevant is that when I tried to see if it was just undefined behavior by running with -fsanitize=undefined the code just behaved properly