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

            Bug ID: 127313
           Summary: Empty FDEs for `__builtin_unreachable`-only functions
                    collide on lld/ld64 (PR109267 not on GCC 15)
           Product: gcc
           Version: 15.2.0
            Status: UNCONFIRMED
          Keywords: EH, link-failure, wrong-code
          Severity: normal
          Priority: P3
         Component: middle-end
          Assignee: unassigned at gcc dot gnu.org
          Reporter: 220255623 at seu dot edu.cn
                CC: 220245569 at seu dot edu.cn, jianhao.xu at seu dot edu.cn
  Target Milestone: ---

Created attachment 65552
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65552&action=edit
Minimal C++ reproducer, preprocessed input, build script, expected behavior,
compiler/linker version details, and observed GCC 15.2.0/16.1.0/17.0.0 test
logs for the PR109267 GCC 15 backport gap. Text

This is a backport/release-branch coverage report for the existing public bug
PR middle-end/109267. It is not a new root cause.

GCC 15.2.0 emits an externally visible function whose only body is
__builtin_unreachable() as a zero-length text region with a zero-length FDE.
When the next real function starts at the same address, GNU ld discards the
empty FDE, but lld retains it. A valid C++ program that throws from the real
function is caught when linked with GNU ld, but terminates with lld.

Reproducer:

  extern "C" void empty() { __builtin_unreachable(); }
  extern "C" __attribute__((noinline, cold)) void real() { throw 1; }
  int main() { try { real(); } catch (int) { return 0; } return 1; }

Exact commands:

  g++ -O2 -fcf-protection=none -fasynchronous-unwind-tables \
      -fuse-ld=lld repro.ii -o repro-lld
  ./repro-lld; echo exit=$?

  g++ -O2 -fcf-protection=none -fasynchronous-unwind-tables \
      -fuse-ld=bfd repro.ii -o repro-bfd
  ./repro-bfd; echo exit=$?

Observed with GCC 15.2.0 x86_64-pc-linux-gnu:

  lld: terminate called after throwing an instance of 'int'; exit=134
  GNU ld: exit=0

The object contains `empty` with size 0 and an FDE with
pc_begin == pc_end. `real` starts at the same address on GCC 15.2.0. The
exception unwinder therefore uses a conflicting FDE record with lld and does
not find the expected catch. GNU ld incidentally drops the zero-address-range
FDE, which masks the compiler output defect.

GCC 16 fixed this in r16-2429
(31e8896dcd87279be73674e8f2258db26d7a6e1e) by changing the sole
__builtin_unreachable call to a trap, or to an infinite loop when no trap is
available. The same program exits 0 with GCC 16.1.0 and the GCC 17.0.0
20260531 snapshot when linked with lld. The current releases/gcc-15 branch
still lacks the fix and pr109267 tests.

Please decide whether r16-2429 should be backported to releases/gcc-15.

The attached archive contains the minimal repro.ii, repro.cpp, build script,
expected result, complete compiler/linker version information, and observed
15.2.0/16.1.0/17.0.0 text logs. It contains no object files or binaries.

Reply via email to