Segmentation fault
中文叫做段错误,非常令人头疼的问题,默认没有任何提示信息。可能导致段错误的原因有:
参考:https://www.cnblogs.com/kuliuheng/p/11698378.html
- 解除引用一个包含非法值
- 解除引用一个空指针(常常由函数返回,并未经检查就使用)
- 在未得到正确的权限时进行访问。例如,试图往一个只读的文本段储存值就会引发段错误。
- 用完了栈或者堆空间(虚拟内存虽然巨大,但也有可能使用殆尽)
生成coredump文件
# 查看当前coredump文件大小限制
$ ulimit -c
# 如果为0,则需要解除限制,注意只对当前shell进程生效
$ ulimit -c unlimited
# 生成coredump文件的命名格式
$ cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport %p %s %c %P
# 更改文coredump文件命名规则
$ sudo vi /etc/sysctl.conf
kernel.core_pattern=/var/crash/%E.%p.%t.%s
$ sudo sysctl -p
我们设置 core dump 目录为/var/crash
,core dump 的命名方式为%E.%p.%t.%s
,它们的含义:
%E
:程序文件的完整路径(路径中的/
会被!
替代)%p
:进程 ID%t
:进程崩溃的时间戳%s
:哪个信号让进程崩溃
在获取coredump文件后,执行gdb进行调试
$ gdb <file> <file.coredump>
(gdb) backtrace # 打印调用栈
使用coredumpctl info
可查找coredump文件位置。
Signal handler
产生段错误时一般会触发一个SIGSEGV信号,我们可以添加该信号的处理函数,在程序退出之前记录一些信息。我们甚至可以使用backtrace(3)函数来保存当前栈内容。
#include <csignal>
#include <execinfo.h>
#define SIZE 100
void dump(int signo)
{
fprintf(stderr,"catch Segmentation fault!!!\n");
FILE *fh;
if(!(fh = fopen("/tmp/dbg_msg.log", "w+")))
exit(0);
void *buffer[100];
int nptrs;
nptrs = backtrace(buffer,SIZE);
backtrace_symbols_fd(buffer, nptrs, fileno(fh));
fflush(fh);
exit(-1);
}
main (void)
{
signal(SIGSEGV, &dump);
*((int*)NULL) = 0;
return 0;
}