Clang 4.0.1 C++ code generation issue (bug?)

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Clang 4.0.1 C++ code generation issue (bug?)

Boris Kolpackov via cfe-dev
Greetings Clangers,

SUMMARY:
I’m experiencing a C++ code generation difference between clang 3.9.0 & 4.0.1 that is resulting in unexpected behaviour in my code.  The difference also exhibits between -O1 & -O2/3 with clang 4.0.1.
(I’ve seen this issue for i386 & x86_64 on OSX, but it probably affects all OSes.)

DISCLAIMER:
I’m not entirely sure if this is a bug in clang or some kind of undefined behaviour.
(I can’t fully get my head around the class.union section of the C++ standard to determine its secret meaning.)
I don’t know if the problem is located in clang’s code or LLVM’s code.  (But I’m reporting it here.)
Using -std=c++14 or -std=c++1z makes no difference.

HISTORY:
I recently upgraded to clang 4.0.1 (using http://releases.llvm.org/4.0.1/clang+llvm-4.0.1-x86_64-apple-darwin.tar.xz).  Most things seem to be fine (~2MLOC & ~150 binaries) apart from one problem that only exhibits itself in a release build.  (The problem exhibited as corrupted documents & crashes … during testing.)  The original code has been in use for > 15 years & was previously compiled, successfully, using clang 3.9.0 & 3.6.1, gcc 4.2.1 & CodeWarrior for PPC, PPC-64, i386 & x86-64 (in various combinations).

CODE:
I have spent several days distilling, reducing & refining the code that exhibits the problem to the following:

// TestClang.cpp - Test clang 4.0.1 code generation issue

#include <cstdio>
#include <cstring>

struct B {
    char t;
    union { char c; int x; void* p; };
#ifndef FIX
    B& operator= (const B& rhs) { t = rhs.t; p = rhs.p; return *this; }
#endif
};

union U { union { int f; char s[8]; } n; B b; };

struct D {
    const int size;
    B e[8];

    __attribute__((noinline)) D (int count, const U objs[]) : size(count)
    {
        U tmp{ .b.t = 1, .b.x = 0x123400 }; // b.x set to help see problem
        #pragma clang loop unroll(disable)  // Shortens generated code
        for (auto* it = e; count--; ++it)
        {
            const U* val = objs++;
            if (val->n.s[0] > 32)
            {
                tmp.b.x = val->n.f;         // <<<<< PROBLEM IS AROUND HERE <<<<<
                val = &tmp;
    //          if (!size) std::puts(tmp.n.s); // Also fixes code
            }
            *it = val->b;
        }
    }
};

int main (int argc, const char* argv[])
{
    const char* args[] = { "one!", "two!" };
    int count = argc ? 2    : argc - 1;     // Prevent over optimisation
    auto    s = argc ? args : argv + 1;

    U us[8];
    for (int i = 0; i < count; ++i)
        std::strncpy(us[i].n.s, *s++, 8);

    const D dict(count, us);
    for (int i = 0; i < dict.size; ++i)
    {
        auto& n = dict.e[i];
        std::printf("  %u. '%.4s' [%u:$%08X]\n", i, &n.c, n.t, n.x);
    }
}

// end


TESTS:
When the following line is executed:
    clang -arch i386 -O2 -Wall -std=c++14 -stdlib=libc++ TestClang.cpp && ./a.out
the output is:
  0. '' [1:$00123400]
  1. '' [1:$00123400]
The output should be:
  0. 'one!' [1:$21656E6F]
  1. 'two!' [1:$216F7774]

Adding the option `-DFIX` generates the expected output.
Removing the `-O2` option with clang 4.0.1 generates the expected output without `-DFIX`.
Uncommenting line 31 also generates the expected output with clang 4.0.1.
(Line 31 does nothing - other than tricking the optimiser.)

Using `-arch x86_64` and/or `-std=c++1z` with clang 4.0.1 makes no difference.
Using `-Weverything` provides no useful output!  (I know C++14 != C++98.)
Using clang 3.9.0 instead of 4.0.1 generates the expected output with all the above variations.

The problem appears to be related to the B::operator= code and code (possibly loop) optimisation.

ASSEMBLER:
The relevant parts of the code (the loop from lines 24-34) generate the following with clang 4.0.1.

The GOOD code (-DFIX):
LBB2_2:                                 ## =>This Inner Loop Header: Depth=1
        decl %eax
        cmpb $33, (%edx)
        movl %edx, %edi
        jl LBB2_4
## BB#3:                                ##   in Loop: Header=BB2_2 Depth=1
        movl (%edx), %edi
        movl %edi, -12(%ebp)
        movl %esi, %edi
LBB2_4:                                 ##   in Loop: Header=BB2_2 Depth=1
        addl $8, %edx
        movsd (%edi), %xmm0           ## xmm0 = mem[0],zero
        movsd %xmm0, (%ecx)
        addl $8, %ecx
        testl %eax, %eax
        jne LBB2_2

The BAD code (no -DFIX):
LBB2_2:                                 ## =>This Inner Loop Header: Depth=1
        decl %eax
        movzbl (%edx), %ebx
        cmpb $33, %bl
        movl %edx, %edi
        jl LBB2_4
## BB#3:                                ##   in Loop: Header=BB2_2 Depth=1
        movl (%edx), %esi
        movb $1, %bl
        leal -24(%ebp), %edi
LBB2_4:                                 ##   in Loop: Header=BB2_2 Depth=1
        addl $8, %edx
        movb %bl, (%ecx)
        movl 4(%edi), %edi
        movl %edi, 4(%ecx)
        addl $8, %ecx
        testl %eax, %eax
        jne LBB2_2
## BB#5:
        movl %esi, -20(%ebp)

This last line looks problematic (if I’m reading it correctly).
It’s storing %esi only once although it is loaded each time round the loop at BB#3.
It appears to be generated by `tmp.b.x = val->n.f;` which has migrated outside the loop & after tmp is read.

QUESTIONS:
So my questions are:
  Is this a bug in clang/LLVM?
  Does anyone else see this?
  Do clang 4.0.0 and/or clang 3.9.1 exhibit this problem?
  Is this caused by a rare code combination or is it going to silently break lots of code?
  Is this serious enough to warrant/require a clang 4.0.2?
  Do you need any further info to help fix this?
  Is someone willing to, please, fix it?

Thanks,

CHRIS


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Clang 4.0.1 C++ code generation issue (bug?)

Boris Kolpackov via cfe-dev
Hi Chris,

See https://bugs.llvm.org/show_bug.cgi?id=31928 for a similar story.

Short answer: do not write to one member of a union, then read from another, since that is "implementation defined" behavior, and this was broken going from clang 3.9.0 to 4.0.0 (or maybe it was always broken, and it did not optimize "enough" to be of influence).

If your code really must write one union member and read another, and you do not want to refactor these accesses using memcpy, you will have to use -fno-strict-aliasing.

-Dimitry

> On 11 Jul 2017, at 10:10, via cfe-dev <[hidden email]> wrote:
>
> Greetings Clangers,
>
> SUMMARY:
> I’m experiencing a C++ code generation difference between clang 3.9.0 & 4.0.1 that is resulting in unexpected behaviour in my code.  The difference also exhibits between -O1 & -O2/3 with clang 4.0.1.
> (I’ve seen this issue for i386 & x86_64 on OSX, but it probably affects all OSes.)
>
> DISCLAIMER:
> I’m not entirely sure if this is a bug in clang or some kind of undefined behaviour.
> (I can’t fully get my head around the class.union section of the C++ standard to determine its secret meaning.)
> I don’t know if the problem is located in clang’s code or LLVM’s code.  (But I’m reporting it here.)
> Using -std=c++14 or -std=c++1z makes no difference.
>
> HISTORY:
> I recently upgraded to clang 4.0.1 (using http://releases.llvm.org/4.0.1/clang+llvm-4.0.1-x86_64-apple-darwin.tar.xz).  Most things seem to be fine (~2MLOC & ~150 binaries) apart from one problem that only exhibits itself in a release build.  (The problem exhibited as corrupted documents & crashes … during testing.)  The original code has been in use for > 15 years & was previously compiled, successfully, using clang 3.9.0 & 3.6.1, gcc 4.2.1 & CodeWarrior for PPC, PPC-64, i386 & x86-64 (in various combinations).
>
> CODE:
> I have spent several days distilling, reducing & refining the code that exhibits the problem to the following:
>
> // TestClang.cpp - Test clang 4.0.1 code generation issue
>
> #include <cstdio>
> #include <cstring>
>
> struct B {
>    char t;
>    union { char c; int x; void* p; };
> #ifndef FIX
>    B& operator= (const B& rhs) { t = rhs.t; p = rhs.p; return *this; }
> #endif
> };
>
> union U { union { int f; char s[8]; } n; B b; };
>
> struct D {
>    const int size;
>    B e[8];
>
>    __attribute__((noinline)) D (int count, const U objs[]) : size(count)
>    {
>        U tmp{ .b.t = 1, .b.x = 0x123400 }; // b.x set to help see problem
>        #pragma clang loop unroll(disable)  // Shortens generated code
>        for (auto* it = e; count--; ++it)
>        {
>            const U* val = objs++;
>            if (val->n.s[0] > 32)
>            {
>                tmp.b.x = val->n.f;         // <<<<< PROBLEM IS AROUND HERE <<<<<
>                val = &tmp;
>    //          if (!size) std::puts(tmp.n.s); // Also fixes code
>            }
>            *it = val->b;
>        }
>    }
> };
>
> int main (int argc, const char* argv[])
> {
>    const char* args[] = { "one!", "two!" };
>    int count = argc ? 2    : argc - 1;     // Prevent over optimisation
>    auto    s = argc ? args : argv + 1;
>
>    U us[8];
>    for (int i = 0; i < count; ++i)
>        std::strncpy(us[i].n.s, *s++, 8);
>
>    const D dict(count, us);
>    for (int i = 0; i < dict.size; ++i)
>    {
>        auto& n = dict.e[i];
>        std::printf("  %u. '%.4s' [%u:$%08X]\n", i, &n.c, n.t, n.x);
>    }
> }
>
> // end
>
>
> TESTS:
> When the following line is executed:
>    clang -arch i386 -O2 -Wall -std=c++14 -stdlib=libc++ TestClang.cpp && ./a.out
> the output is:
>  0. '' [1:$00123400]
>  1. '' [1:$00123400]
> The output should be:
>  0. 'one!' [1:$21656E6F]
>  1. 'two!' [1:$216F7774]
>
> Adding the option `-DFIX` generates the expected output.
> Removing the `-O2` option with clang 4.0.1 generates the expected output without `-DFIX`.
> Uncommenting line 31 also generates the expected output with clang 4.0.1.
> (Line 31 does nothing - other than tricking the optimiser.)
>
> Using `-arch x86_64` and/or `-std=c++1z` with clang 4.0.1 makes no difference.
> Using `-Weverything` provides no useful output!  (I know C++14 != C++98.)
> Using clang 3.9.0 instead of 4.0.1 generates the expected output with all the above variations.
>
> The problem appears to be related to the B::operator= code and code (possibly loop) optimisation.
>
> ASSEMBLER:
> The relevant parts of the code (the loop from lines 24-34) generate the following with clang 4.0.1.
>
> The GOOD code (-DFIX):
> LBB2_2:                                 ## =>This Inner Loop Header: Depth=1
> decl %eax
> cmpb $33, (%edx)
> movl %edx, %edi
> jl LBB2_4
> ## BB#3:                                ##   in Loop: Header=BB2_2 Depth=1
> movl (%edx), %edi
> movl %edi, -12(%ebp)
> movl %esi, %edi
> LBB2_4:                                 ##   in Loop: Header=BB2_2 Depth=1
> addl $8, %edx
> movsd (%edi), %xmm0           ## xmm0 = mem[0],zero
> movsd %xmm0, (%ecx)
> addl $8, %ecx
> testl %eax, %eax
> jne LBB2_2
>
> The BAD code (no -DFIX):
> LBB2_2:                                 ## =>This Inner Loop Header: Depth=1
> decl %eax
> movzbl (%edx), %ebx
> cmpb $33, %bl
> movl %edx, %edi
> jl LBB2_4
> ## BB#3:                                ##   in Loop: Header=BB2_2 Depth=1
> movl (%edx), %esi
> movb $1, %bl
> leal -24(%ebp), %edi
> LBB2_4:                                 ##   in Loop: Header=BB2_2 Depth=1
> addl $8, %edx
> movb %bl, (%ecx)
> movl 4(%edi), %edi
> movl %edi, 4(%ecx)
> addl $8, %ecx
> testl %eax, %eax
> jne LBB2_2
> ## BB#5:
> movl %esi, -20(%ebp)
>
> This last line looks problematic (if I’m reading it correctly).
> It’s storing %esi only once although it is loaded each time round the loop at BB#3.
> It appears to be generated by `tmp.b.x = val->n.f;` which has migrated outside the loop & after tmp is read.
>
> QUESTIONS:
> So my questions are:
>  Is this a bug in clang/LLVM?
>  Does anyone else see this?
>  Do clang 4.0.0 and/or clang 3.9.1 exhibit this problem?
>  Is this caused by a rare code combination or is it going to silently break lots of code?
>  Is this serious enough to warrant/require a clang 4.0.2?
>  Do you need any further info to help fix this?
>  Is someone willing to, please, fix it?
>
> Thanks,
>
> CHRIS
>
>
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

signature.asc (230 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Clang 4.0.1 C++ code generation issue (bug?)

Boris Kolpackov via cfe-dev
Thanks, Dimitry, for your rapid reply.

On 11 Jul 17, at 09:39:55, Dimitry Andric <[hidden email]> wrote:

> See https://bugs.llvm.org/show_bug.cgi?id=31928 for a similar story.

Ouch!
(I tried searching bugs.llvm.org, but there were too many unresolved issues & 31928’s title didn’t seem relevant.)

As this has changed from Clang 3.9.1 to 4.0.0 it should be in the release notes.  It is not.  Why not?
This is going to silently bite may users.  (scan-build also reports nothing.)
A very quick check shows this may well break CoreFoundation (CFByteOrder.h) and sqlite (shell.c).  There are very probably many, many more.


> Short answer: do not write to one member of a union, then read from another, since that is "implementation defined" behavior, and this was broken going from clang 3.9.0 to 4.0.0 (or maybe it was always broken, and it did not optimize "enough" to be of influence).

I agree that this may be “implementation defined”.  The C++ standard appears to state that it is defined behaviour.  Where is this behaviour defined for Clang?  Why has it changed?
Also “implementation defined” means it should behave the same with & without -O2.  With Clang 4.0 it does not.  Therefore it is now “undefined behaviour”.  Thus, Clang 4.0 is broken.


> If your code really must write one union member and read another, and you do not want to refactor these accesses using memcpy, you will have to use -fno-strict-aliasing.

Where is -fstrict-aliasing/-fno-strict-aliasing defined for clang?
For that matter where is it stated that -O2 also sets -fstrict-aliasing?

Clang is stated to be “GCC compatible”.  GCC explicitly states that “type-punning” using a union is allowed with -fstrict-aliasing <https://gcc.gnu.org/onlinedocs/gcc-7.1.0/gcc/Optimize-Options.html>.

Therefore, I now assert that Clang 4.0.0 & 4.0.1 are broken.  Please will someone fix it.
(I doubt most people are using Clang 4.0 yet.  This may change when Xcode 9.0 ships.  That would be bad.)

Regards,

CHRIS

PS Further testing shows that the issue also affects clang 4.0.1 with -std=c++11.


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Clang 4.0.1 C++ code generation issue (bug?)

Boris Kolpackov via cfe-dev
In reply to this post by Boris Kolpackov via cfe-dev
Hello,

my research shows that issue seems to be fixed by this commit: https://reviews.llvm.org/rL303851
which is not part of 4.0.1 unfortunately.

Reagrds,
Serge.

11.07.2017, 15:40, "Dimitry Andric via cfe-dev" <[hidden email]>:

> Hi Chris,
>
> See https://bugs.llvm.org/show_bug.cgi?id=31928 for a similar story.
>
> Short answer: do not write to one member of a union, then read from another, since that is "implementation defined" behavior, and this was broken going from clang 3.9.0 to 4.0.0 (or maybe it was always broken, and it did not optimize "enough" to be of influence).
>
> If your code really must write one union member and read another, and you do not want to refactor these accesses using memcpy, you will have to use -fno-strict-aliasing.
>
> -Dimitry
>
>>  On 11 Jul 2017, at 10:10, via cfe-dev <[hidden email]> wrote:
>>
>>  Greetings Clangers,
>>
>>  SUMMARY:
>>  I’m experiencing a C++ code generation difference between clang 3.9.0 & 4.0.1 that is resulting in unexpected behaviour in my code. The difference also exhibits between -O1 & -O2/3 with clang 4.0.1.
>>  (I’ve seen this issue for i386 & x86_64 on OSX, but it probably affects all OSes.)
>>
>>  DISCLAIMER:
>>  I’m not entirely sure if this is a bug in clang or some kind of undefined behaviour.
>>  (I can’t fully get my head around the class.union section of the C++ standard to determine its secret meaning.)
>>  I don’t know if the problem is located in clang’s code or LLVM’s code. (But I’m reporting it here.)
>>  Using -std=c++14 or -std=c++1z makes no difference.
>>
>>  HISTORY:
>>  I recently upgraded to clang 4.0.1 (using http://releases.llvm.org/4.0.1/clang+llvm-4.0.1-x86_64-apple-darwin.tar.xz). Most things seem to be fine (~2MLOC & ~150 binaries) apart from one problem that only exhibits itself in a release build. (The problem exhibited as corrupted documents & crashes … during testing.) The original code has been in use for > 15 years & was previously compiled, successfully, using clang 3.9.0 & 3.6.1, gcc 4.2.1 & CodeWarrior for PPC, PPC-64, i386 & x86-64 (in various combinations).
>>
>>  CODE:
>>  I have spent several days distilling, reducing & refining the code that exhibits the problem to the following:
>>
>>  // TestClang.cpp - Test clang 4.0.1 code generation issue
>>
>>  #include <cstdio>
>>  #include <cstring>
>>
>>  struct B {
>>     char t;
>>     union { char c; int x; void* p; };
>>  #ifndef FIX
>>     B& operator= (const B& rhs) { t = rhs.t; p = rhs.p; return *this; }
>>  #endif
>>  };
>>
>>  union U { union { int f; char s[8]; } n; B b; };
>>
>>  struct D {
>>     const int size;
>>     B e[8];
>>
>>     __attribute__((noinline)) D (int count, const U objs[]) : size(count)
>>     {
>>         U tmp{ .b.t = 1, .b.x = 0x123400 }; // b.x set to help see problem
>>         #pragma clang loop unroll(disable) // Shortens generated code
>>         for (auto* it = e; count--; ++it)
>>         {
>>             const U* val = objs++;
>>             if (val->n.s[0] > 32)
>>             {
>>                 tmp.b.x = val->n.f; // <<<<< PROBLEM IS AROUND HERE <<<<<
>>                 val = &tmp;
>>     // if (!size) std::puts(tmp.n.s); // Also fixes code
>>             }
>>             *it = val->b;
>>         }
>>     }
>>  };
>>
>>  int main (int argc, const char* argv[])
>>  {
>>     const char* args[] = { "one!", "two!" };
>>     int count = argc ? 2 : argc - 1; // Prevent over optimisation
>>     auto s = argc ? args : argv + 1;
>>
>>     U us[8];
>>     for (int i = 0; i < count; ++i)
>>         std::strncpy(us[i].n.s, *s++, 8);
>>
>>     const D dict(count, us);
>>     for (int i = 0; i < dict.size; ++i)
>>     {
>>         auto& n = dict.e[i];
>>         std::printf(" %u. '%.4s' [%u:$%08X]\n", i, &n.c, n.t, n.x);
>>     }
>>  }
>>
>>  // end
>>
>>  TESTS:
>>  When the following line is executed:
>>     clang -arch i386 -O2 -Wall -std=c++14 -stdlib=libc++ TestClang.cpp && ./a.out
>>  the output is:
>>   0. '' [1:$00123400]
>>   1. '' [1:$00123400]
>>  The output should be:
>>   0. 'one!' [1:$21656E6F]
>>   1. 'two!' [1:$216F7774]
>>
>>  Adding the option `-DFIX` generates the expected output.
>>  Removing the `-O2` option with clang 4.0.1 generates the expected output without `-DFIX`.
>>  Uncommenting line 31 also generates the expected output with clang 4.0.1.
>>  (Line 31 does nothing - other than tricking the optimiser.)
>>
>>  Using `-arch x86_64` and/or `-std=c++1z` with clang 4.0.1 makes no difference.
>>  Using `-Weverything` provides no useful output! (I know C++14 != C++98.)
>>  Using clang 3.9.0 instead of 4.0.1 generates the expected output with all the above variations.
>>
>>  The problem appears to be related to the B::operator= code and code (possibly loop) optimisation.
>>
>>  ASSEMBLER:
>>  The relevant parts of the code (the loop from lines 24-34) generate the following with clang 4.0.1.
>>
>>  The GOOD code (-DFIX):
>>  LBB2_2: ## =>This Inner Loop Header: Depth=1
>>          decl %eax
>>          cmpb $33, (%edx)
>>          movl %edx, %edi
>>          jl LBB2_4
>>  ## BB#3: ## in Loop: Header=BB2_2 Depth=1
>>          movl (%edx), %edi
>>          movl %edi, -12(%ebp)
>>          movl %esi, %edi
>>  LBB2_4: ## in Loop: Header=BB2_2 Depth=1
>>          addl $8, %edx
>>          movsd (%edi), %xmm0 ## xmm0 = mem[0],zero
>>          movsd %xmm0, (%ecx)
>>          addl $8, %ecx
>>          testl %eax, %eax
>>          jne LBB2_2
>>
>>  The BAD code (no -DFIX):
>>  LBB2_2: ## =>This Inner Loop Header: Depth=1
>>          decl %eax
>>          movzbl (%edx), %ebx
>>          cmpb $33, %bl
>>          movl %edx, %edi
>>          jl LBB2_4
>>  ## BB#3: ## in Loop: Header=BB2_2 Depth=1
>>          movl (%edx), %esi
>>          movb $1, %bl
>>          leal -24(%ebp), %edi
>>  LBB2_4: ## in Loop: Header=BB2_2 Depth=1
>>          addl $8, %edx
>>          movb %bl, (%ecx)
>>          movl 4(%edi), %edi
>>          movl %edi, 4(%ecx)
>>          addl $8, %ecx
>>          testl %eax, %eax
>>          jne LBB2_2
>>  ## BB#5:
>>          movl %esi, -20(%ebp)
>>
>>  This last line looks problematic (if I’m reading it correctly).
>>  It’s storing %esi only once although it is loaded each time round the loop at BB#3.
>>  It appears to be generated by `tmp.b.x = val->n.f;` which has migrated outside the loop & after tmp is read.
>>
>>  QUESTIONS:
>>  So my questions are:
>>   Is this a bug in clang/LLVM?
>>   Does anyone else see this?
>>   Do clang 4.0.0 and/or clang 3.9.1 exhibit this problem?
>>   Is this caused by a rare code combination or is it going to silently break lots of code?
>>   Is this serious enough to warrant/require a clang 4.0.2?
>>   Do you need any further info to help fix this?
>>   Is someone willing to, please, fix it?
>>
>>  Thanks,
>>
>>  CHRIS
>>
>>  _______________________________________________
>>  cfe-dev mailing list
>>  [hidden email]
>>  http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>
> ,
>
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Clang 4.0.1 C++ code generation issue (bug?)

Boris Kolpackov via cfe-dev
In reply to this post by Boris Kolpackov via cfe-dev
Хорошие новости - я полазил по баг-трекеру, ревьюшнице и коммитнице LLVM и, похоже, проблему починили вот этим коммитом:

https://reviews.llvm.org/rL303851

К сожалению этот коммит не вошёл в 4.0.1 (я проверил по их svn), так что если решим перейти на 4.0.1 этот патч неплохо было бы забрать, ну или ждать 4.0.2.

-- 
Сергей Прейс
stuff/spreis


12.07.2017, 08:01, "via cfe-dev" <[hidden email]>:

> Thanks, Dimitry, for your rapid reply.
>
> On 11 Jul 17, at 09:39:55, Dimitry Andric <[hidden email]> wrote:
>
>>  See https://bugs.llvm.org/show_bug.cgi?id=31928 for a similar story.
>
> Ouch!
> (I tried searching bugs.llvm.org, but there were too many unresolved issues & 31928’s title didn’t seem relevant.)
>
> As this has changed from Clang 3.9.1 to 4.0.0 it should be in the release notes. It is not. Why not?
> This is going to silently bite may users. (scan-build also reports nothing.)
> A very quick check shows this may well break CoreFoundation (CFByteOrder.h) and sqlite (shell.c). There are very probably many, many more.
>
>>  Short answer: do not write to one member of a union, then read from another, since that is "implementation defined" behavior, and this was broken going from clang 3.9.0 to 4.0.0 (or maybe it was always broken, and it did not optimize "enough" to be of influence).
>
> I agree that this may be “implementation defined”. The C++ standard appears to state that it is defined behaviour. Where is this behaviour defined for Clang? Why has it changed?
> Also “implementation defined” means it should behave the same with & without -O2. With Clang 4.0 it does not. Therefore it is now “undefined behaviour”. Thus, Clang 4.0 is broken.
>
>>  If your code really must write one union member and read another, and you do not want to refactor these accesses using memcpy, you will have to use -fno-strict-aliasing.
>
> Where is -fstrict-aliasing/-fno-strict-aliasing defined for clang?
> For that matter where is it stated that -O2 also sets -fstrict-aliasing?
>
> Clang is stated to be “GCC compatible”. GCC explicitly states that “type-punning” using a union is allowed with -fstrict-aliasing <https://gcc.gnu.org/onlinedocs/gcc-7.1.0/gcc/Optimize-Options.html>.
>
> Therefore, I now assert that Clang 4.0.0 & 4.0.1 are broken. Please will someone fix it.
> (I doubt most people are using Clang 4.0 yet. This may change when Xcode 9.0 ships. That would be bad.)
>
> Regards,
>
> CHRIS
>
> PS Further testing shows that the issue also affects clang 4.0.1 with -std=c++11.
>
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Clang 4.0.1 C++ code generation issue (bug?)

Boris Kolpackov via cfe-dev
Please disregard this. This was from internal discussion of the issue - wrong addressees :(

Sorry.


12.07.2017, 12:29, "Serge Preis" <[hidden email]>:

> Хорошие новости - я полазил по баг-трекеру, ревьюшнице и коммитнице LLVM и, похоже, проблему починили вот этим коммитом:
>
> https://reviews.llvm.org/rL303851
>
> К сожалению этот коммит не вошёл в 4.0.1 (я проверил по их svn), так что если решим перейти на 4.0.1 этот патч неплохо было бы забрать, ну или ждать 4.0.2.
>
> --
> Сергей Прейс
> stuff/spreis
>
> 12.07.2017, 08:01, "via cfe-dev" <[hidden email]>:
>>  Thanks, Dimitry, for your rapid reply.
>>
>>  On 11 Jul 17, at 09:39:55, Dimitry Andric <[hidden email]> wrote:
>>
>>>   See https://bugs.llvm.org/show_bug.cgi?id=31928 for a similar story.
>>
>>  Ouch!
>>  (I tried searching bugs.llvm.org, but there were too many unresolved issues & 31928’s title didn’t seem relevant.)
>>
>>  As this has changed from Clang 3.9.1 to 4.0.0 it should be in the release notes. It is not. Why not?
>>  This is going to silently bite may users. (scan-build also reports nothing.)
>>  A very quick check shows this may well break CoreFoundation (CFByteOrder.h) and sqlite (shell.c). There are very probably many, many more.
>>
>>>   Short answer: do not write to one member of a union, then read from another, since that is "implementation defined" behavior, and this was broken going from clang 3.9.0 to 4.0.0 (or maybe it was always broken, and it did not optimize "enough" to be of influence).
>>
>>  I agree that this may be “implementation defined”. The C++ standard appears to state that it is defined behaviour. Where is this behaviour defined for Clang? Why has it changed?
>>  Also “implementation defined” means it should behave the same with & without -O2. With Clang 4.0 it does not. Therefore it is now “undefined behaviour”. Thus, Clang 4.0 is broken.
>>
>>>   If your code really must write one union member and read another, and you do not want to refactor these accesses using memcpy, you will have to use -fno-strict-aliasing.
>>
>>  Where is -fstrict-aliasing/-fno-strict-aliasing defined for clang?
>>  For that matter where is it stated that -O2 also sets -fstrict-aliasing?
>>
>>  Clang is stated to be “GCC compatible”. GCC explicitly states that “type-punning” using a union is allowed with -fstrict-aliasing <https://gcc.gnu.org/onlinedocs/gcc-7.1.0/gcc/Optimize-Options.html>.
>>
>>  Therefore, I now assert that Clang 4.0.0 & 4.0.1 are broken. Please will someone fix it.
>>  (I doubt most people are using Clang 4.0 yet. This may change when Xcode 9.0 ships. That would be bad.)
>>
>>  Regards,
>>
>>  CHRIS
>>
>>  PS Further testing shows that the issue also affects clang 4.0.1 with -std=c++11.
>>
>>  _______________________________________________
>>  cfe-dev mailing list
>>  [hidden email]
>>  http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev