linux下定位多线程内存越界问题实践总结( 四 )
文章插图
代码如上图 。 注意 , 处理SIGSEGV的handler函数有一些小技巧(坑很多):
1. SIGSEGV一般是内核处理的(page fault) 。 使用库libsigsegv可以简化用户空间撰写处理函数的难度 。
2. 处理函数中 , 不能调用任何可能再分配内存的函数 , 否则会引起double fault 。 例如 , 在这段处理函数中 , 使用open系统调用打开文件 , 不能使用fopen;buff是从栈上分配的 , 不能从heap上申请;不能使用backtrace_symbols , 它会向glibc动态申请内存 , 而要使用安全的backtrace_symbols_fd把backtrace直接写入文件 。
3. 最重要的 , 在SIGSEGV的处理函数中 , 我们需要恢复引起段错误的内存块为可读写的 。 这样 , 当处理函数返回被中断的代码继续执行时 , 才不能再次引起段错误 。 重新编译代码 , 运行重现脚本 。 查看记录了backtrace的文件sigsegv.bt , 我们看到了熟悉的被篡改的指针地址(一半为0):
文章插图
这个段错误会最终导致程序core掉 , 因为这个SIGSEGV信号不是由我们使用mprotect的保护而产生的 。 查看core文件 , 可以查到被越界的内存(即ptr_)的地址 。 从sigsegv.bt文件中查找 , 果然找到了那一次非法访问:
文章插图
使用addr2line检查上面这个调用栈中的地址 , 我们终于找到了它 。 又经过一番代码review和验证 , 才总算确定了错误原因 。 有一个动态new出来的对象的指针在两个有关联的线程中共享 , 在某种极端情况下 , 其中一个delete了对象之后 , 另一个线程又修改了这个对象 。
小结小结一下 , 遇到棘手的内存越界问题 , 可以使用下面顺序逐个尝试:
1. code review分析代码 。
2. valgrind用起来最简单 , 几乎是傻瓜式的 。 能用尽量用 。
3. glibc的MALLOC_CHECK_使用起来和很简单 , 不需要重现编译代码 。 可以用来发现问题 , 但是其本身无法定位问题 。 和magic number结合起来 , 可以用来定位一类内存越界的问题 。
4. 和electric-fence齐名的还有一个内存调试库叫做dmalloc 。 虽然在本次解决问题的过程中没有用到 , 这个库对于检测内存泄露等其他问题很有用 。 推荐大家学习一下 , 放到自己的工具库中 。
5. electric-fence是定位一类“野指针”访问问题的利器 , 强烈推荐使用 。
6. 如果上述所有工具都帮不了你 , 那么只好在熟悉代码逻辑的基础上 , 使用终极武器了 。
7. code review 。 通过尝试代码库中不同版本编译出来的程序复现bug , 用二分法定位引入bug的最早的一次代码提交 。
- 推新标准建新生态,下载超198亿次金山发力海内外
- 闲鱼|电诉宝:“闲鱼”网络欺诈成用户投诉热点 Q3获“不建议下单”评级
- 王兴称美团优选目前重点是建设核心能力;苏宁旗下云网万店融资60亿元;阿里小米拟增资居然之家|8点1氪 | 美团
- 先别|用了周冬雨的照片,我会成为下一个被告?自媒体创作者先别自乱阵脚
- 丹丹|福佑卡车创始人兼CEO单丹丹:数字领航 驶向下一个十年
- 看过明年的iPhone之后,现在下手的都哭了
- 二维码|村网通?澳大利亚一州推出疫情追踪二维码 还考虑采用人脸识别和地理定位
- 砍单|iPhone12之后,拼多多又将iPhone12Pro拉下水
- 巨头|“社区薇娅”都不够用了 一线互联网巨头全员下场卖菜
- 余额|中兴通讯:现有资金余额仅能确保公司当前经营规模下现金流安全
