崩溃时非法访问地址直接来自info registers中的寄存器值(如rip、rax)或ASan报告的精确地址(如0x602000000038),结合dmesg segfault日志的at字段与ip字段,可准确定位违规内存位置。

崩溃时直接看 segfault 地址和寄存器值
Linux 下多线程程序因访问违规(如 segfault)崩溃,内核会终止进程并输出信号信息。关键不是“找地址”,而是**确认崩溃瞬间访问了哪个非法地址**——它通常就在 gdb 的 info registers 或 bt 输出里。
常见现象:程序突然退出,终端显示 Segmentation fault (core dumped),但没给出具体地址;或 gdb ./a.out core 后 bt 显示栈帧不完整、?? 多。
- 用
gdb ./program core加载 core 文件后,先执行info registers,重点关注rip(崩溃指令地址)和rdi/rsi/rax等寄存器——其中某个很可能就是非法访问的指针值 - 若崩溃线程在系统调用中(如
pthread_mutex_lock),bt可能停在__lll_lock_wait,此时需切到对应线程(thread 2)再查bt和x/10gx $rsp看栈上保存的原始参数 - 确保编译时加了
-g -fno-omit-frame-pointer,否则bt无法还原完整调用链,地址也难以映射回源码行
AddressSanitizer 报告里的 0x... 就是违规地址
ASan 不只报错,它把每次非法访问的**精确内存地址、读写类型、访问偏移、分配/释放堆栈全打出来**。这个地址不是“猜测值”,而是 CPU 实际尝试访问的物理(或虚拟)地址。
典型输出片段:
立即学习“C++免费学习笔记(深入)”;
==12345==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000038 at pc 0x0000004012ab bp 0x7ffeedc9a8d0 sp 0x7ffeedc9a8c8 READ of size 4 at 0x602000000038 thread T1
这里 0x602000000038 就是线程 T1 试图读取的已释放内存地址,READ of size 4 说明是 4 字节读操作。
- 地址末尾数字(如
38)常暗示越界偏移量,结合上一行的allocated by堆栈,可反推原 buffer 大小和索引错误位置 - 若地址落在
[0x000000000000, 0x00000000ffff]区间,大概率是空指针解引用(0x0或附近) - 若地址是奇数(如
0x...1)、或末两位为0xc/0x8,可能涉及未对齐访问或 padding 区域误读
多线程下地址冲突必须结合线程上下文看
同一个地址在不同线程中含义可能完全不同:线程 A 的栈变量地址,对线程 B 来说就是无效地址;一个线程刚 delete 的指针,另一个线程还在用——这时 ASan 报的地址是真实的,但根源在线程间生命周期不同步。
定位步骤要闭环:
- 用
gdb附加运行中进程(gdb -p $(pidof yourapp)),执行info threads查所有线程状态,标记出处于sleep、mutex或running的线程 - 对疑似问题线程(比如阻塞在
std::vector::operator[]),切换过去(thread 3),用print &vec[100]看实际计算出的地址,再x/4wd &vec[100]验证是否越界 - 若怀疑是共享
std::vector被并发修改,直接检查该 vector 的data()返回值是否被其他线程resize过——ASan 会报heap-buffer-overflow,地址指向 realloc 后的新区域外
别依赖 valgrind --tool=memcheck 查违规地址
Valgrind 的 memcheck 擅长报“非法访问”,但默认不显示**CPU 执行时真正访存的地址**,而是抽象成“block offset + size”。它告诉你“访问了已释放内存的第 8 字节”,但不会打印 0x602000000038 这种原始地址。
想让它输出类似 ASan 的地址格式,必须加参数:
-
--freelist-vol=1000000提高释放块追踪精度 -
--show-leak-kinds=all配合--leak-check=full,在泄漏报告里附带分配地址 - 但即便如此,它仍无法像 ASan 那样在 crash 瞬间捕获并打印
READ/WRITE at 0x...——这是设计差异,不是配置问题
真正需要地址级定位时,优先用 gdb + ASan 组合。Valgrind 更适合查“谁分配没释放”或“跨线程竞争”,而不是“这一条指令到底碰了哪块内存”。


















