最准最快定位段错误的方式是用gdb直接运行带-g编译的程序,崩溃时自动停在出错源码行;需禁用strip、慎用优化,辅以bt、p等命令分析,或结合core dump、dmesg与addr2line离线定位。

直接用 gdb 运行带调试信息的程序,段错误触发时它会自动停在出错行——这是最准、最快的第一响应方式,不需要猜、不依赖日志、不靠运气。
编译时必须加 -g,否则 gdb 看不到源码行号
没有 -g,gdb 只能显示汇编指令和内存地址,无法定位到 .c 文件哪一行。常见错误是只加了 -O2 或 -Wall 就以为够了。
-
gcc -g -O0 test.c -o test:推荐新手用-O0关闭优化,避免变量被优化掉或指令重排干扰判断 -
gcc -g -O2 test.c -o test:线上复现问题时可用,但要注意某些越界可能被优化掩盖 - 别用
-s或strip处理二进制,会直接删掉调试符号,gdb退化为“盲调”
gdb ./test 启动后直接 r,崩溃点就是真实出错位置
不用设断点、不用单步,gdb 在收到 SIGSEGV 信号时会自动中断,并高亮显示触发语句。例如:
Program received signal SIGSEGV, Segmentation fault. 0x0000555555555164 in dummy_function () at test.c:4 4 *ptr = 0x00;
这时立刻执行 bt(backtrace)看调用栈,确认是哪一层传入了坏指针;用 p ptr 查看指针值,常能一眼发现是 0x0、已释放地址或明显越界的值。
- 如果
bt显示栈帧不全(比如只有??),说明没加-rdynamic或链接了未带调试信息的库 - 若程序跑一会儿才崩,可先
catch signal SIGSEGV,再r,让gdb在信号发出瞬间就捕获,而非等默认 handler 终止进程
段错误不总在 gdb 里必现?开 core dump 离线分析
有些段错误依赖特定内存布局或竞态条件,在 gdb 下因环境变化反而不触发。这时要靠 core 文件还原现场。
- 先运行
ulimit -c unlimited,确保系统允许生成完整 core 文件 - 崩溃后当前目录出现
core或core.xxx,用gdb ./test core加载 - 进
gdb后直接输where(等价于bt),效果和运行时捕获一致 - 注意:core 文件默认权限是
600,若用非 root 用户生成,切换用户后可能打不开,需提前chmod
崩溃时没源码或只有地址?用 dmesg + addr2line 定位
当无法启动 gdb(如嵌入式环境、容器无调试工具),dmesg 是唯一能拿到原始错误上下文的系统级入口。
执行 dmesg | tail -n 5,找类似这行:
[12345.678901] test[1234]: segfault at 0 ip 0000555555555164 sp 00007fffffffe4a0 error 6 in test[555555555000+1000]
关键字段:at 是非法访问地址,ip 是指令指针(即崩溃位置),error 6 表示写操作访问不可写页。
- 提取
ip值(这里是0000555555555164),减去映像基址([555555555000+1000]中的555555555000),得偏移0x164 - 运行
addr2line -e test 0x164,输出test.c:4 - 若程序用了 PIE(
-fPIE -pie),基址每次不同,dmesg中的ip就是真实地址,不用减
真正难的不是定位,而是理解为什么那个地址非法——比如 ip 指向的是 libc 内部,说明你传给 strcpy 的参数错了,得回溯你自己的调用链。


















