-
Notifications
You must be signed in to change notification settings - Fork 14.5k
Description
Reproduced using clang15 and 18 in Amazon Linux 2023 and clang20 in Fedora42
When building a program with BTI (typically in my case -mbranch-protection=standard
, the program crashes in C++ exception processing.
I've pinpointed the cause to clang not putting a bti instruction at the beginning of the exception "catching" code. Older libgcc (I tested gcc11) work fine because they use a ret
instruction at the end of __builtin_eh_return()
when jumping to the catch handler. With gcc 14 (at least using the version in Amazon Linux 2023) however I get a br
instruction which expects the destination to have the appropriate bti instruction.
It works fine with g++
A simple test program demonstrates the issue:
#include <iostream>
int main()
{
std::cout << "Foo\n";
try {
throw 1;
} catch (int a)
{
std::cout << "Bar\n";
}
return 0;
}
Compile with:
$ clang++ -O0 -g2 -mbranch-protection=standard -o test test.cpp`
$ ./test
Foo
Illegal instruction (core dumped)
$ ./test
Foo
Bar
You can see in the generated assembly:
000000000041030c <main>:
41030c: d503233f paciasp
410310: d100c3ff sub sp, sp, #0x30
410314: a9027bfd stp x29, x30, [sp, #32]
410318: 910083fd add x29, sp, #0x20
41031c: b81fc3bf stur wzr, [x29, #-4]
410320: 90000180 adrp x0, 440000 <__cxa_begin_catch@CXXABI_1.3>
410324: 91020000 add x0, x0, #0x80
410328: 90000081 adrp x1, 420000 <_IO_stdin_used>
41032c: 91004021 add x1, x1, #0x10
410330: 97ffff56 bl 410088 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
410334: d2800080 mov x0, #0x4 // #4
410338: 97ffff48 bl 410058 <__cxa_allocate_exception@plt>
41033c: 52800028 mov w8, #0x1 // #1
410340: b9000008 str w8, [x0]
410344: f0000161 adrp x1, 43f000 <GCC_except_table1+0x1ee20>
410348: 9136a021 add x1, x1, #0xda8
41034c: aa1f03e2 mov x2, xzr
410350: 97ffff72 bl 410118 <__cxa_throw@plt>
410354: 14000022 b 4103dc <_fini>
__cxa_throw ends up jumping here:
410358: 2a0103e8 mov w8, w1 <---- not a BTI instruction, boom !
41035c: f9000be0 str x0, [sp, #16]
410360: b9000fe8 str w8, [sp, #12]
410364: 14000001 b 410368 <main+0x5c>
.../...
The same code generated by gcc (11 in this case):
000000000041028c <main>:
41028c: d503233f paciasp
410290: a9bd7bfd stp x29, x30, [sp, #-48]!
410294: 910003fd mov x29, sp
410298: f9000bf3 str x19, [sp, #16]
41029c: 90000080 adrp x0, 420000 <_IO_stdin_used>
4102a0: 91004001 add x1, x0, #0x10
4102a4: 90000180 adrp x0, 440000 <__cxa_begin_catch@CXXABI_1.3>
4102a8: 91020000 add x0, x0, #0x80
4102ac: 97ffff77 bl 410088 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
4102b0: d2800080 mov x0, #0x4 // #4
4102b4: 97ffff69 bl 410058 <__cxa_allocate_exception@plt>
4102b8: 52800021 mov w1, #0x1 // #1
4102bc: b9000001 str w1, [x0]
4102c0: d2800002 mov x2, #0x0 // #0
4102c4: f0000161 adrp x1, 43f000 <__FRAME_END__+0x1ee50>
4102c8: 9136a021 add x1, x1, #0xda8
4102cc: 97ffff93 bl 410118 <__cxa_throw@plt>
__cxa_throw ends up jumping here:
4102d0: d503249f bti j <--- here's our BTI
4102d4: f100043f cmp x1, #0x1
4102d8: 54000040 b.eq 4102e0 <main+0x54> // b.none
4102dc: 97ffff95 bl 410130 <_Unwind_Resume@plt>
.../...