macOS v.s 上的回溯信息不同。 Linux
Backtrace info different on macOS v.s. Linux
这是 C++ 中的测试代码(改编自 Whosebug post 但我找不到它):
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <unistd.h>
void handler(int sig) {
void *array[10];
size_t size;
// get void*'s for all entries on the stack
size = backtrace(array, 10);
// print out all the frames to stderr
fprintf(stderr, "Error: signal %d:\n", sig);
backtrace_symbols_fd(array, size, STDERR_FILENO);
exit(1);
}
void baz() {
int *foo = (int*)-1; // make a bad pointer
printf("%d\n", *foo); // causes segfault
}
void bar() { baz(); }
void foo() { bar(); }
int main(int argc, char **argv) {
signal(SIGSEGV, handler); // install our handler
foo(); // this will call foo, bar, and baz. baz segfaults.
}
这是编译和链接步骤(在 macOS 上,g++
实际上是 clang++
):
g++ backtrace_example.cc -c -O0
g++ -rdynamic backtrace_example.o -o bt_example
这是在 macOS 上打印的回溯信息:
$ ./bt_example
Error: signal 11:
0 bt_example 0x000000010dd39dbf handler + 31
1 libsystem_platform.dylib 0x00007fff5e0b7b3d _sigtramp + 29
2 ??? 0x0000000117f6a7c7 0x0 + 4697008071
3 bt_example 0x000000010dd39eb9 _Z3barv + 9
4 bt_example 0x000000010dd39ec9 _Z3foov + 9
5 bt_example 0x000000010dd39efe main + 46
6 libdyld.dylib 0x00007fff5dece085 start + 1
7 ??? 0x0000000000000001 0x0 + 1
这是打印在 Linux 上的回溯信息:
$ ./bt_example
Error: signal 11:
./bt_example(handler+0x2b)[0x400982]
/lib/x86_64-linux-gnu/libc.so.6(+0x354b0)[0x7f2aefc534b0]
./bt_example(_Z3bazv+0x14)[0x4009db]
./bt_example(_Z3barv+0x9)[0x4009fa]
./bt_example(_Z3foov+0x9)[0x400a06]
./bt_example(main+0x23)[0x400a2c]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f2aefc3e830]
./bt_example(_start+0x29)[0x4008a9]
除了格式上的差异,还有一个关键的区别:macOS版本根本没有提到函数baz()
,但显然段错误是由baz()
.[=22=引起的]
为什么?这是 macOS 实施 backtrace_symbol_fd()
的缺陷,还是有意为之(如果是,如何)?
Reference: GNU documentation on glibc's backtraces. macOS is a different OS and has its own C library, but it has the same backtracing API in this regard since 10.5.
首先,您在 handler
中调用的函数中有 none 可以有效地从信号处理程序调用。因此,您完全处于未定义的行为领域。
其次,这并不是 backtrace
中的缺陷,因为它只是两个操作系统中信号处理机制的差异。 macOS 在调用信号处理程序时临时更改堆栈。如果信号处理程序returns(并且处理程序甚至有机会修改它),它已经保存了足够的上下文信息来恢复它。可以看到实现here.
这是 C++ 中的测试代码(改编自 Whosebug post 但我找不到它):
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <unistd.h>
void handler(int sig) {
void *array[10];
size_t size;
// get void*'s for all entries on the stack
size = backtrace(array, 10);
// print out all the frames to stderr
fprintf(stderr, "Error: signal %d:\n", sig);
backtrace_symbols_fd(array, size, STDERR_FILENO);
exit(1);
}
void baz() {
int *foo = (int*)-1; // make a bad pointer
printf("%d\n", *foo); // causes segfault
}
void bar() { baz(); }
void foo() { bar(); }
int main(int argc, char **argv) {
signal(SIGSEGV, handler); // install our handler
foo(); // this will call foo, bar, and baz. baz segfaults.
}
这是编译和链接步骤(在 macOS 上,g++
实际上是 clang++
):
g++ backtrace_example.cc -c -O0
g++ -rdynamic backtrace_example.o -o bt_example
这是在 macOS 上打印的回溯信息:
$ ./bt_example
Error: signal 11:
0 bt_example 0x000000010dd39dbf handler + 31
1 libsystem_platform.dylib 0x00007fff5e0b7b3d _sigtramp + 29
2 ??? 0x0000000117f6a7c7 0x0 + 4697008071
3 bt_example 0x000000010dd39eb9 _Z3barv + 9
4 bt_example 0x000000010dd39ec9 _Z3foov + 9
5 bt_example 0x000000010dd39efe main + 46
6 libdyld.dylib 0x00007fff5dece085 start + 1
7 ??? 0x0000000000000001 0x0 + 1
这是打印在 Linux 上的回溯信息:
$ ./bt_example
Error: signal 11:
./bt_example(handler+0x2b)[0x400982]
/lib/x86_64-linux-gnu/libc.so.6(+0x354b0)[0x7f2aefc534b0]
./bt_example(_Z3bazv+0x14)[0x4009db]
./bt_example(_Z3barv+0x9)[0x4009fa]
./bt_example(_Z3foov+0x9)[0x400a06]
./bt_example(main+0x23)[0x400a2c]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f2aefc3e830]
./bt_example(_start+0x29)[0x4008a9]
除了格式上的差异,还有一个关键的区别:macOS版本根本没有提到函数baz()
,但显然段错误是由baz()
.[=22=引起的]
为什么?这是 macOS 实施 backtrace_symbol_fd()
的缺陷,还是有意为之(如果是,如何)?
Reference: GNU documentation on glibc's backtraces. macOS is a different OS and has its own C library, but it has the same backtracing API in this regard since 10.5.
首先,您在 handler
中调用的函数中有 none 可以有效地从信号处理程序调用。因此,您完全处于未定义的行为领域。
其次,这并不是 backtrace
中的缺陷,因为它只是两个操作系统中信号处理机制的差异。 macOS 在调用信号处理程序时临时更改堆栈。如果信号处理程序returns(并且处理程序甚至有机会修改它),它已经保存了足够的上下文信息来恢复它。可以看到实现here.