[llvm-dev] Placement new and TBAA
Daniel Berlin via llvm-dev
llvm-dev at lists.llvm.org
Fri Nov 25 22:03:01 PST 2016
The position most compilers take is the the access must be visibly through
a union if you want it to work. Otherwise, it's not possible to use tbaa
really at all. Move your function f to another file, for example, and you
simply could never tell. Some will give you a little more, but you are
pushing your luck
This was discussed in depth in the thread I quoted, and has GCC mailing
list threads going back to before llvm existed :).
Note that there are rules about touching members in a union other than the
first one you set, but pretty much everyone guarantees type punning through
unions to work.
On Fri, Nov 25, 2016, 9:07 PM Sanjoy Das <sanjoy at playingwithpointers.com>
wrote:
> Hi,
>
> On Sat, Nov 26, 2016 at 9:53 AM, Mehdi Amini <mehdi.amini at apple.com>
> wrote:
> > The PR says "passes with -fno-strict-aliasing”, my understanding is that
> it
> > is failing only with the TBAA indeed.
> >
> > You don’t need the main and the union to reproduce, extracting foo()
> alone
> > in its single own file is enough:
> >
> > void *operator new(decltype(sizeof 0), void *) noexcept;
> > float *qq;
> > void foo(int *p, int *q, long unk) {
> > for (long i = 0; i < unk; ++i) {
> > ++*p;
> > qq = new (static_cast<void *>(&q[i])) float(42);
> > }
> > }
> >
> > LICM will get the store to p out of the loop, conceptually turning it
> into:
> >
> > void foo(int *p, int *q, long unk) {
> > for (long i = 0; i < unk; ++i) {
> > qq = new (static_cast<void *>(&q[i])) float(42);
> > }
> > ++*p;
> > }
> >
> >
> > Now I don’t know if the use of placement new in this example is legal in
> the
> > first place. I thought calling delete before using placement new was
> > mandatory.
>
> So if you:
>
> 1. override operator delete to do nothing for that type (so that the
> placement new actually has unfreed backing storage to re-use).
> 2. have an empty destructor.
>
> and have the source program be
>
> void *operator new(decltype(sizeof 0), void *) noexcept;
> float *qq;
> void foo(int *p, int *q, long unk) {
> // unk = 1
> for (long i = 0; i < unk; ++i) {
> ++*p;
> delete &q[i]; // since i is only ever 0, this does not
> // delete a derived pointer
> qq = new (static_cast<void *>(&q[i])) float(42);
> }
> }
>
> then I suspect we'll have the same problem after the destructor and
> the operator delete for that type has been inlined away.
>
> > CC Sanjoy, since he looked into TBAA recently and it reminds me a similar
> > test case he mentioned, not with placement new but with a call to a
> function
> > taking int * and float *, and passing the same address (call site was
> > union).
>
> The case I was talking about was something like:
>
> // C11 source file.
>
> union S {
> int i;
> float f;
> };
>
> void f(int* i, float *f) {
> *i = 20;
> *f = 40.0;
> }
>
> void g() {
> union S s;
> f(&s.i, &s.f);
> }
>
>
> At least cursorily this looked well defined in C++ to me -- f should
> first write int(20) and then float(40.0) to the same location legally.
> However clang emits tbaa such that LLVM concludes that in f, the store
> to i and the store to f don't alias.
>
> However, I'm not very confident in the "this looked well defined"
> reading. I did not consult the standard, but instead relied on second
> hand stackoverflow answers, so I won't be surprised to hear that I was
> wrong about this. Actually I'm never surprised to hear that I'm
> wrong, but I'll be especially less surprised in this case. :)
>
> Thanks!
> -- Sanjoy
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20161126/0d9ae5ee/attachment-0001.html>
More information about the llvm-dev
mailing list