https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64037

            Bug ID: 64037
           Summary: Miscompilation with LTO and enum class : char
                    parameter
           Product: gcc
           Version: 4.9.2
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: js at alien8 dot de

Created attachment 34082
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=34082&action=edit
Minimal test case

On Linux with the x86-64 target, code that contains a byte-sized enum class as
a function parameter is miscompiled when -Os and -flto is enabled. A minimal
example is attached. I also attached g++ --verbose --version output for both
compilers where this triggers (4.9.1 and 4.9.2).

To reproduce the problem compile the attached source with:
g++ -std=gnu++11 -Os -flto test.cc -o test

Run ./test and you get this output: deadbe02
Expected output: 00000002

The problem boils down to the fact that the third parameter to foo (see below)
is passed in DL (the rest of RDX is not cleared). In the function, no code is
emitted to clear the rest of RDX, but it is obviously assumed to be zero.

enum class X : unsigned char {
  V = 2,
};

// noinline and noclone are only there to reduce the example. This
// also triggers without these annotations in larger projects.
void foo(unsigned &out, unsigned a, X b) __attribute__((noinline,noclone));

void foo(unsigned &out, unsigned a, X b)
{
  out = static_cast<unsigned>(b);
}

int main()
{
  // Load obvious value into EDX
  unsigned deadbeef = 0xDEADBEEF;
  asm volatile ("" : "+d" (deadbeef));

  unsigned out;
  foo(out, 2, X::V);
...

0000000000400500 <main>:
  400500:    48 83 ec 18              sub    rsp,0x18
  400504:    ba ef be ad de           mov    edx,0xdeadbeef  <- EDX is loaded
with some garbage
  400509:    48 8d 7c 24 0c           lea    rdi,[rsp+0xc]
  40050e:    b2 02                    mov    dl,0x2          <- Parameter is
put in DL, without clearing RDX first
  400510:    be 02 00 00 00           mov    esi,0x2
  400515:    e8 0c 01 00 00           call   400626 <foo(unsigned int&,
unsigned int, X)>


0000000000400626 <foo(unsigned int&, unsigned int, X)>:
  400626:    89 17                    mov    DWORD PTR [rdi],edx  <- EDX still
contains remnants of 0xDEADBEEF here!
  400628:    c3                       ret

Reply via email to