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

            Bug ID: 92821
           Summary: Miscompilation when passing 8-bit enum to extern
                    function
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: emilio at crisal dot io
  Target Milestone: ---

Created attachment 47427
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=47427&action=edit
Test-case that reproduces the bug with gcc 7.4 and -Os

We've seen a miscompilation of Firefox in GCC 7.4 when compiled with -Os, when
we pass an `enum class : uint8_t` to an extern function. See
https://bugzilla.mozilla.org/show_bug.cgi?id=1600735 for all the details.

It seems fixed in GCC 8. Bisection by redi (thanks!) points to
https://gcc.gnu.org/PR82260 as the culprit for the fix, which seems just a
missed optimization opportunity (thus me filing this bug).

The basic setup is just calling an extern function with an `enum class :
uint8_t` argument, and having that extern function compiled by LLVM (in this
case, by the Rust compiler). LLVM seems to rely on the caller zero-extending
the enum to 32 bits. Per bug 46942 it seems gcc also does something like this
usually (and it does happen to be the case for non -Os builds).

In the bad case, GCC uses a single `mov sil,bl` to set up the argument, which
means garbage on the rest of the register remains that LLVM assumes to be
zeroed.

It seems either GCC should probably always zero-extend when calling an extern
function, or LLVM should never rely on this zero-extension... I don't know what
the relevant ABI specifications say, but I'm happy to file an LLVM bug if this
is deemed not to be a GCC bug per se.

Reply via email to