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.