Bug 23482 - Identical code folding can break C++ exception handling invariants
Summary: Identical code folding can break C++ exception handling invariants
Status: RESOLVED DUPLICATE of bug 21066
Alias: None
Product: binutils
Classification: Unclassified
Component: gold (show other bugs)
Version: 2.32
: P2 normal
Target Milestone: ---
Assignee: Cary Coutant
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-08-04 00:57 UTC by Joshua Oreman
Modified: 2018-08-06 20:19 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
Reproducer for reported issue (7.38 KB, application/octet-stream)
2018-08-04 00:59 UTC, Joshua Oreman
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Joshua Oreman 2018-08-04 00:57:50 UTC
Recent versions of GCC at reasonable optimization levels will automatically split predicted-rarely-taken portions of a function into a separate "funcname.cold" symbol, which goes in a different executable section so as to improve locality of frequently-used code. (This happens on GCC 8 at -O2 or higher; the specific flag is -freorder-blocks-and-partition.) Suppose that two functions with different stack frame layouts happen to have identical .cold fragments split off, the .cold fragment throws an exception (common due to GCC considering exception throwing unlikely), and identical code folding is enabled with eg --icf=safe. Then the one merged .cold fragment can only be associated with one unwinding state, so at least one of the functions will crash or otherwise misbehave when it throws.

I previously reported this to GCC (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86854) and they claim it's gold's bug: "the eh/unwind information from GCC is correct for the landing location but --icf=safe does not take into account the difference in landing locations before merging them".

The attached tarball contains three small C++ source files that reproduce the issue when compiled and linked together using GCC 8, as well as the assembly and object files produced by that compilation, plus the resulting working (without --icf=safe) and failing (with --icf=safe) binaries. The issue was observed on an x86_64 Linux system with gold 1.14 from binutils 2.29.1, and is also seen on a gold built from latest sources today.

Binaries produced using:

$ gold --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt{1,i}.o /usr/lib/gcc/x86_64-linux-gnu/8/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/8 -L/usr/lib/x86_64-linux-gnu t{1,2,m}.o -lstdc++ -lgcc_s -lgcc -lc /usr/lib/gcc/x86_64-linux-gnu/8/crtend.o /usr/lib/x86_64-linux-gnu/crtn.o -o t.nofold

$ gold --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt{1,i}.o /usr/lib/gcc/x86_64-linux-gnu/8/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/8 -L/usr/lib/x86_64-linux-gnu t{1,2,m}.o -lstdc++ -lgcc_s -lgcc -lc /usr/lib/gcc/x86_64-linux-gnu/8/crtend.o /usr/lib/x86_64-linux-gnu/crtn.o -o t.fold --icf=safe

Demonstration:

$ ./t.nofold
caught 1
caught 2

$ ./t.fold
caught 1
Segmentation fault (core dumped)
Comment 1 Joshua Oreman 2018-08-04 00:59:40 UTC
Created attachment 11162 [details]
Reproducer for reported issue
Comment 2 Cary Coutant 2018-08-06 20:19:34 UTC
I think this is the same issue as PR 21066. Gold is not considering the LSDA when comparing the contents of the functions (or function fragments, as in this case).

*** This bug has been marked as a duplicate of bug 21066 ***