gdb本身无法自动检测use-after-free,需结合断点、观察点和asan辅助:在free处设断点记录地址,用awatch监控已释放内存,或更可靠地用-g -fsanitize=address编译后由asan触发崩溃再用gdb分析堆栈。

gdb 怎么发现 use-after-free(释放后使用)
直接用 gdb 本身无法自动检测 use-after-free,它不拦截内存释放后的非法访问——除非程序因此触发 SIGSEGV 或 SIGABRT。但你可以通过组合断点、观察点和堆状态检查,在崩溃前后锁定问题源头。
在 free 调用处设置断点并记录指针值
关键不是“发现”,而是“捕获释放动作并标记可疑地址”。你需要让 GDB 记住哪些指针刚被释放,再在后续访问时比对。
-
break free,然后用commands自动保存被释放的地址:(gdb) break free (gdb) commands silent printf "free(%p) called\n", $rdi # x86-64 下参数在 rdi set $last_freed = $rdi continue end
- 后续若发生崩溃,检查
$last_freed是否与出错地址一致:print/x $rdi(访问时的寄存器)、x/10xb $last_freed看是否已变成脏数据或全零 - 注意:
$last_freed是全局变量,多线程下会互相覆盖;如需线程安全,改用$_thread或配合thread apply all分别检查
用 watch 监控已释放内存区域的读写
如果知道某块内存大概会在哪被再次访问,可在 free 后立即对它的起始地址设读写观察点。但必须确保该地址尚未被分配器重用,否则会误触发。
- 先执行
free(ptr),确认ptr值(比如是0x7ffff7f012a0) - 立刻加观察点:
awatch *0x7ffff7f012a0(读写都停) - 继续运行:
continue,一旦有代码读或写这个地址,GDB 会中断并显示调用栈 - 风险:如果分配器很快把这块内存重新分配给别的对象,观察点会干扰正常逻辑;建议只在单线程、低负载、短路径场景下用
配合 AddressSanitizer 编译 + gdb 联调
纯 GDB 效率低、漏报高;ASan 才是 detect use-after-free 的主力。GDB 的作用是接手 ASan 触发的崩溃现场。
- 编译时加:
gcc -g -fsanitize=address -fno-omit-frame-pointer - 运行时报错时会打印完整堆栈,并停在出错行;此时用
gdb ./a.out core加载 core 文件 - 进 GDB 后:
bt看崩溃位置,info registers查访问地址,x/20gx $rdx(假设是读$rdx)验证是否落在 ASan 的 redzone 区域 - ASan 会在释放后把内存标记为不可访问,所以 GDB 捕获的是“第一次非法访问”,而非“释放动作”——这才是最准的时机
真正难的不是定位某次 use-after-free,而是复现它:这类问题往往依赖内存布局、分配顺序和时间差。不要指望一次 run 就命中,要结合 ASan 编译、gdb 断点控制、以及重复运行缩小触发条件。











