假设我有一个导致分段错误的代码。
char * ptr = NULL;
*ptr = "hello"; /* this will cause a segmentation fault */
如何在运行时上打印,内存中发生分段错误的地址,以及分段错误的原因(访问禁止内存区域或其他内容)。
我读到了关于核心转储文件,但我不确定它是否是正确的解决方案。
我该怎么做?
PS ,我知道我可以通过使用gdb或其他调试器来实现这一目标,但目的是通过使用代码和仅代码来实现这一目的。
答案 0 :(得分:4)
如果您想了解原因,可以注册信号处理程序,例如:
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\n", info->si_addr);
switch (info->si_code) {
case SEGV_MAPERR:
fprintf(stderr, "Address not mapped.\n");
break;
case SEGV_ACCERR:
fprintf(stderr, "Access to this address is not allowed.\n");
break;
default:
fprintf(stderr, "Unknown reason.\n");
break;
}
/* unregister and let the default action occur */
sigaction(SIGSEGV, &action, NULL);
}
然后在某个地方你需要注册它:
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时触发的信号,并且你会得到一些额外的信息,引用手册页:
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错误的前兆),因此请求分页工作正常。
答案 1 :(得分:2)
正如这里已经回答:How to generate a stacktrace when my gcc C++ app crashes
你可以(至少使用Linux / BSD的GCC)这样做很容易:
示例代码:
#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:\n", 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 */
}
示例输出:
# 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