能直接定位空指针解引用,前提是可执行文件带调试符号且core文件完整;先用info signals确认SIGSEGV,再用bt和x/i $pc结合info registers查看崩溃指令及寄存器值(如rdi=0),若指令向0地址写入即坐实空指针。

能直接定位,但必须满足两个前提:可执行文件带调试符号(-g),且 core 文件没被截断或损坏。
确认崩溃信号是不是 SIGSEGV 且栈顶在空指针解引用处
启动 GDB 后第一件事就是看崩溃信号和栈顶指令:
-
(gdb) info signals SIGSEGV—— 确认是否为段错误(空指针最常见触发 SIGSEGV) -
(gdb) bt—— 查看调用栈;如果栈顶函数里有类似mov %rax, (%rdi)或movl $0x0,(%rax)这类向寄存器值为 0 的地址写入的指令,基本就是空指针解引用 - 注意:
bt full才能看到局部变量值;若栈帧中某变量显示为$1 = (char *) 0x0,再结合它被当作左值使用(比如str[0] = 'a'),就坐实了
用 x/i $pc 和 info registers 看寄存器实际值
崩溃瞬间的寄存器状态比源码更真实,尤其当优化开启后源码行和汇编不严格对应时:
-
(gdb) x/i $pc—— 显示当前指令(即导致崩溃的那条) -
(gdb) info registers rax rdi rsi rbx—— 重点查参与内存访问的寄存器;若rdi是 0,而指令是mov %eax,(%rdi),那就是向 NULL 写 - 别只信变量名:
p str可能显示优化后的值或已失效,info registers是原始证据
检查指针来源:是未初始化、释放后使用,还是函数返回 NULL 没判断
定位到空指针后,要回溯它怎么来的。常见路径有三类:
- 局部指针未初始化:
char *p;后直接strcpy(p, "abc")→bt full中看p值为0x0,且上层无赋值语句 - malloc/free 不匹配:
p = malloc(10); free(p); strcpy(p, "x")→ 此时p可能仍显示地址(非 0),但x/1bx p会报错或读到异常值;用heap插件或check heap(需 glibc 调试符号)辅助判断 - 系统调用或库函数返回 NULL 没检查:
FILE *f = fopen("missing.txt", "r"); fprintf(f, "...")→p f显示0x0,再查fopen调用前是否有errno输出或日志
真正难的不是看到 (char *) 0x0,而是区分“它本来就是 NULL”和“它本该有值但被意外清零”。这时候得结合上下文逻辑、内存布局(info proc mappings)、甚至重放运行加 watch *(int*)0 —— 但后者仅限开发环境,生产 core 里做不了。


















