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;
}

References

  1. http://senlinzhan.github.io/2017/12/31/coredump/
  2. 段错误(Segmentation fault)产生的原因以及调试方法
  3. https://www.cnblogs.com/linux-37ge/p/12781176.html
  4. https://www.cnblogs.com/kuliuheng/p/11698378.html