print the segmentation fault reason
本问题已经有最佳答案,请猛点这里访问。
假设我有一个导致分段错误的代码。
1 2 | char * ptr = NULL; *ptr ="hello"; /* this will cause a segmentation fault */ |
如何在运行时打印,分段错误发生在内存中的地址,以及分段错误的原因(访问禁止的内存区域或其他内容)。
我读过核心转储文件,但我不确定它是否是正确的解决方案。
我该怎么做?
另外,我知道我可以通过使用gdb或其他调试器来实现这一点,但目的是通过使用代码和仅使用代码来实现这一点。
如果您想知道原因,可以注册一个信号处理程序,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | void handler(int signum, siginfo_t *info, void *context) { struct sigaction action = { .sa_handler = SIG_DFL, .sa_sigaction = NULL, .sa_mask = 0, .sa_flags = 0, .sa_restorer = NULL }; fprintf(stderr,"Fault address: %p ", info->si_addr); switch (info->si_code) { case SEGV_MAPERR: fprintf(stderr,"Address not mapped. "); break; case SEGV_ACCERR: fprintf(stderr,"Access to this address is not allowed. "); break; default: fprintf(stderr,"Unknown reason. "); break; } /* unregister and let the default action occur */ sigaction(SIGSEGV, &action, NULL); } |
然后你需要在某个地方注册它:
1 2 3 4 5 6 7 8 9 10 11 12 | struct sigaction action = { .sa_handler = NULL, .sa_sigaction = handler, .sa_mask = 0, .sa_flags = SA_SIGINFO, .sa_restorer = NULL }; if (sigaction(SIGSEGV, &action, NULL) < 0) { perror("sigaction"); } |
基本上,当sigsegv被发送时,您注册一个触发的信号,并获得一些附加信息,引用手册页:
1
2
3
4
5 The following values can be placed in si_code for a SIGSEGV signal:
SEGV_MAPERR address not mapped to object
SEGV_ACCERR invalid permissions for mapped object
这些映射到出现SEG错误的两个基本原因——要么您访问的页面根本没有映射,要么您不被允许执行您试图执行的任何操作。
这里,在信号处理程序激发之后,它将注销自身并替换默认操作。这将导致无法再次执行的操作,以便被正常路由捕获。这是页面错误(获得SEG错误的前兆)的正常行为,因此像需求分页这样的事情可以工作。
正如这里已经回答的:当我的GCC C++应用程序崩溃时,如何生成堆栈跟踪
您可以(至少在使用Linux/BSD的gcc中)非常容易地做到这一点:
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include <stdio.h> #include <execinfo.h> #include <signal.h> #include <stdlib.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: ", sig); backtrace_symbols_fd(array, size, 2); exit(1); } int main(int argc, char **argv) { signal(SIGSEGV, handler); // install our handler char * ptr = NULL; *ptr ="hello"; /* this will cause a segmentation fault */ } |
实例输出:
1 2 3 4 5 6 7 8 | # gcc -g -rdynamic -o test test.c # ./test Error: signal 11: 0 test 0x000000010e99dcfa handler + 42 1 libsystem_c.dylib 0x00007fff95c1194a _sigtramp + 26 2 ??? 0x0000000000000000 0x0 + 0 3 libdyld.dylib 0x00007fff8fa177e1 start + 0 4 ??? 0x0000000000000001 0x0 + 1 |