[Bug gold/23482] New: Identical code folding can break C++ exception handling invariants
https://sourceware.org/bugzilla/show_bug.cgi?id=23482 Bug ID: 23482 Summary: Identical code folding can break C++ exception handling invariants Product: binutils Version: 2.32 (HEAD) Status: UNCONFIRMED Severity: normal Priority: P2 Component: gold Assignee: ccoutant at gmail dot com Reporter: oremanj at gmail dot com CC: ian at airs dot com Target Milestone: --- 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) -- You are receiving this mail because: You are on the CC list for the bug. ___ bug-binutils mailing list bug-binutils@gnu.org https://lists.gnu.org/mailman/listinfo/bug-binutils
[Bug gold/23482] Identical code folding can break C++ exception handling invariants
https://sourceware.org/bugzilla/show_bug.cgi?id=23482 --- Comment #1 from Joshua Oreman --- Created attachment 11162 --> https://sourceware.org/bugzilla/attachment.cgi?id=11162&action=edit Reproducer for reported issue -- You are receiving this mail because: You are on the CC list for the bug. ___ bug-binutils mailing list bug-binutils@gnu.org https://lists.gnu.org/mailman/listinfo/bug-binutils
[Bug gold/21066] icf folds template functions with different exception handling semantics
https://sourceware.org/bugzilla/show_bug.cgi?id=21066 --- Comment #4 from Joshua Oreman --- As I pointed out in PR 23482, hot/cold function splitting (the new gcc -freorder-blocks-and-partition optimization) can make this an issue even without any LSDA at all. Seems a full fix will need to consider the CIE/FDE contents that are relevant to the function as well. Example uses asm for clarity, but I can obtain analogous issues using gcc-produced code, as demonstrated on the above PR. $ g++ -o t.nofold t.cc -fuse-ld=gold $ g++ -o t.fold t.cc -fuse-ld=gold -Wl,--icf=safe $ ./t.nofold caught 1: 42 caught 2: 42 $ ./t.fold caught 1: 42 terminate called after throwing an instance of 'int' Aborted (core dumped) $ cat t.cc extern "C" int printf(const char *fmt, ...); void throw_it() { throw 42; } extern void call_1(void(*)()); extern void call_2(void(*)()); asm(R"( .section .text._Z6call_1PFvvE,"ax",@progbits .globl _Z6call_1PFvvE .type _Z6call_1PFvvE, @function _Z6call_1PFvvE: .cfi_startproc pushq %rbx .cfi_def_cfa_offset 16 .cfi_offset 3, -16 jmp _Z6call_1PFvvE.cold .cfi_endproc .section .text.unlikely._Z6call_1PFvvE,"ax",@progbits .type _Z6call_1PFvvE.cold, @function _Z6call_1PFvvE.cold: .cfi_startproc .cfi_def_cfa_offset 16 .cfi_offset 3, -16 call*%rdi .cfi_endproc .section .text._Z6call_2PFvvE,"ax",@progbits .globl _Z6call_2PFvvE .type _Z6call_2PFvvE, @function _Z6call_2PFvvE: .cfi_startproc subq$24, %rsp .cfi_def_cfa_offset 32 jmp _Z6call_2PFvvE.cold .cfi_endproc .section .text.unlikely._Z6call_2PFvvE,"ax",@progbits .type _Z6call_2PFvvE.cold, @function _Z6call_2PFvvE.cold: .cfi_startproc .cfi_def_cfa_offset 32 call*%rdi .cfi_endproc )"); int main() { try { call_1(throw_it); } catch (int val) { printf("caught 1: %d\n", val); } try { call_2(throw_it); } catch (int val) { printf("caught 2: %d\n", val); } } -- You are receiving this mail because: You are on the CC list for the bug. ___ bug-binutils mailing list bug-binutils@gnu.org https://lists.gnu.org/mailman/listinfo/bug-binutils
[Bug gold/21066] icf folds template functions with different exception handling semantics
https://sourceware.org/bugzilla/show_bug.cgi?id=21066 --- Comment #5 from Joshua Oreman --- Created attachment 11278 --> https://sourceware.org/bugzilla/attachment.cgi?id=11278&action=edit Proposed fix I believe this patch fixes all the issues described in this thread. I also submitted it to the mailing list: https://sourceware.org/ml/binutils/2018-09/msg00346.html -- You are receiving this mail because: You are on the CC list for the bug. ___ bug-binutils mailing list bug-binutils@gnu.org https://lists.gnu.org/mailman/listinfo/bug-binutils