如何调试段错误
Calendar 2025 年 11 月 25 日
Edit 共 481 字,阅读需要 1 分钟

如何调试段错误 #

段错误是非常常见的一种错误. 主要是内存导致的, 比如数组越界, double free, 解引用空指针等.

假设有一个简单的 C++ 代码如下:

// broken.cpp

int main() {
  int *ptr = nullptr;
  int value = *ptr;
  return 0;
}

编译并运行:

g++ ./broken.cpp -o broken -g
./broken

不出意外的会报段错误:

$ ./broken
Segmentation fault (core dumped)

生成 coredump 文件 #

什么是 coredump 文件

在 Linux 系统中,常将主内存称为核心 (core), 而核心映像 (core image) 就是进程 (process) 执行当时的内存内容. 当进程发生错误或收到信号 (signal) 而终止执行时,系统会将核心映像写入一个文件,以作为调试之用,这就是所谓的核心转储 (core dump).

coredump 文件实际上是一个特殊的 ELF 文件.

首先查看一下允许生成的 core dump 文件的最大大小, 运行 ulimit -a:

$ ulimit -a
real-time non-blocking time  (microseconds, -R) unlimited
core file size              (blocks, -c) 0
...

可以看到大小是 0, 将其设置为 unlimited:

$ ulimit -c unlimited

对于某些发行版, 这样设置就足够了. 当出现 Segmentation fault 时当前目录会自动生成 coredump 文件.

但对于我用的 Ubuntu 还需要手动打开一下. 查看一下 core_pattern:

$ cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport -p%p -s%s -c%c -d%d -P%P -u%u -g%g -F%F -- %E

发现会将 core dump 传给 apport. 将其修改为直接写入 core 文件:

$ sudo sysctl -w kernel.core_pattern=core

再次运行 broken 文件就可以得到 coredump.

调试 coredump 文件 #

一般使用 gdb 调试 coredump 文件:

gdb ./broken core

对应的输出:

Core was generated by `./broken'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x000058f79b7a413d in main () at ./broken.cpp:3
3         int value = *ptr;

可以看到定位到了出错在第 3 行. 剩下的就跟正常使用 gdb 调试差不多了.