-
Notifications
You must be signed in to change notification settings - Fork 289
Description
Description
LTO seems to mess up stack unwinding when exception handlers are nested across function calls. This causes a segfault while unwinding the stack. Without LTO, the stack is correctly unwound.
The following code reproduces the crash
#include <iostream>
#include <stdexcept>
#include <string>
std::string thrower() {
throw std::out_of_range("nope");
}
std::string __attribute__((noinline)) wrapper() {
try {
return thrower();
} catch (std::out_of_range&) {
throw;
} catch (...) {
return "";
}
}
int main() {
try {
auto s = wrapper();
std::cout << "Wrapper returned: " << s << std::endl;
} catch (std::out_of_range&) {
std::cout << "Got a std::out_of_range" << std::endl;
} catch (...) {
std::cout << "Got some other exception" << std::endl;
}
return 0;
}
NOTE: The __attribute((noinline)) is required to keep the optimizer from inlining the wrapper which also makes the segfault go away. Having the nested handlers across function calls seems to be a requirement for this particular problem.
Building with ndk-27b, WITHOUT lto, and pushing to an emulator running Android 11
./android-ndk-r27b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ --target=x86_64-none-linux-android30 --sysroot=./android-ndk-r27b/toolchains/llvm/prebuilt/linux-x86_64/sysroot -g -O2 -std=gnu++14 -o atest_no_lto main.cpp
adb push atest_no_lto ./android-ndk-r27b/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so /data/local/tmp
adb logcat -c
adb shell "LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/atest_no_lto"
Gives the output
Got a std::out_of_range
Building with ndk-27b, WITH lto, and pushing to an emulator running Android 11
./android-ndk-r27b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ --target=x86_64-none-linux-android30 --sysroot=./android-ndk-r27b/toolchains/llvm/prebuilt/linux-x86_64/sysroot -g -O2 -flto -std=gnu++14 -o atest_lto main.cpp
adb push atest_lto ./android-ndk-r27b/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so /data/local/tmp
adb logcat -c
adb shell "LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/atest_lto"
adb logcat -d
Gives the output (and logcat)
Segmentation fault
--------- beginning of crash
09-16 09:36:38.133 9973 9973 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 9973 (atest_lto), pid 9973 (atest_lto)
--------- beginning of main
09-16 09:36:38.142 9976 9976 I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstone
09-16 09:36:38.143 299 299 I tombstoned: received crash request for pid 9973
09-16 09:36:38.143 9976 9976 I crash_dump64: performing dump of process 9973 (target tid = 9973)
09-16 09:36:38.143 9976 9976 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
09-16 09:36:38.143 9976 9976 F DEBUG : Build fingerprint: 'google/sdk_gslim_x86_64/generic_x86_64:11/RSR1.210722.030/10147527:userdebug/dev-keys'
09-16 09:36:38.143 9976 9976 F DEBUG : Revision: '0'
09-16 09:36:38.144 9976 9976 F DEBUG : ABI: 'x86_64'
09-16 09:36:38.144 9976 9976 F DEBUG : Timestamp: 2024-09-16 09:36:38-0400
09-16 09:36:38.144 9976 9976 F DEBUG : pid: 9973, tid: 9973, name: atest_lto >>> /data/local/tmp/atest_lto <<<
09-16 09:36:38.144 9976 9976 F DEBUG : uid: 0
09-16 09:36:38.144 9976 9976 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
09-16 09:36:38.144 9976 9976 F DEBUG : Cause: null pointer dereference
09-16 09:36:38.144 9976 9976 F DEBUG : rax 00007ffe572bbdf8 rbx 00007ffe572bb910 rcx 0000784a2d780510 rdx 0000000000000001
09-16 09:36:38.144 9976 9976 F DEBUG : r8 00007ffe572bbd00 r9 0000000000000028 r10 00005733a90621e8 r11 00005733a9062800
09-16 09:36:38.144 9976 9976 F DEBUG : r12 00007ffe572bba00 r13 0000784a2d780510 r14 00007ffe572bbd00 r15 0000000000000002
09-16 09:36:38.144 9976 9976 F DEBUG : rdi 00007ffe572bbd00 rsi 00007ffe572bb910
09-16 09:36:38.144 9976 9976 F DEBUG : rbp 0000000000000002 rsp 00007ffe572bb8f8 rip 0000000000000000
09-16 09:36:38.146 9976 9976 F DEBUG : backtrace:
09-16 09:36:38.146 9976 9976 F DEBUG : #00 pc 0000000000000000 <unknown>
09-16 09:36:38.146 9976 9976 F DEBUG : #01 pc 0000000000125fc9 /data/local/tmp/libc++_shared.so (__unw_get_proc_info+9) (BuildId: 734ab2eaa203afbb89147d313e46146617bd1a2c)
09-16 09:36:38.146 9976 9976 F DEBUG : #02 pc 000000000000150f [anon:scudo:primary]
09-16 09:36:38.146 9976 9976 F DEBUG : #03 pc 0000000000125dcb /data/local/tmp/libc++_shared.so (_Unwind_GetLanguageSpecificData+11) (BuildId: 734ab2eaa203afbb89147d313e46146617bd1a2c)
09-16 09:36:38.149 0 0 D logd : logdr: UID=0 GID=0 PID=9976 n tail=50 logMask=8 pid=9973 start=0ns timeout=0ns
09-16 09:36:38.150 0 0 D logd : logdr: UID=0 GID=0 PID=9976 n tail=50 logMask=1 pid=9973 start=0ns timeout=0ns
09-16 09:36:38.150 0 0 D logd : logdr: UID=0 GID=0 PID=9976 n tail=0 logMask=8 pid=9973 start=0ns timeout=0ns
09-16 09:36:38.151 0 0 D logd : logdr: UID=0 GID=0 PID=9976 n tail=0 logMask=1 pid=9973 start=0ns timeout=0ns
09-16 09:36:38.153 0 0 I init : Untracked pid 9976 exited with status 0
09-16 09:36:38.153 0 0 I init : Untracked pid 9978 exited with status 0
--------- beginning of system
09-16 09:36:38.154 543 813 W NativeCrashListener: Couldn't find ProcessRecord for pid 9973
09-16 09:36:38.154 299 299 E tombstoned: Tombstone written to: /data/tombstones/tombstone_44
I'm attaching the full tombstone file in case it helps.
tombstone_44.zip
This also happens with ndk-26c and clang-17, which is where I first ran into it. I tried reproducing this problem directly on ubuntu 22.04 using clang-17 but was unsuccessful.
While digging around LLVM's bugtracker I found the following issue that may be relevant: llvm/llvm-project#56825
Affected versions
r26, r27
Canary version
No response
Host OS
Linux
Host OS version
Ubuntu 22.04
Affected ABIs
x86_64
Build system
ndk-build
Other build system
No response
minSdkVersion
n/a
Device API level
30