coredump 堆栈被写坏问题定位
独家号 ftom 作者 ftom原文链接
问题描述
游戏后台有一个导号工具,主要是把外网玩家账号数据导入到内部环境供调试使用。 但是在导到有家族的账号的时候,脚本会core掉并且退出。 脚本运行是每次请求的时候拉起,执行完毕之后释放资源,无法在线进行gdb attach 上去断点看问题。
查问题第一步当然是尽可能的收集遇到的问题。 查看coredump 文件,bt堆栈如下所示:发生了Segment Fault 段错误,但是函数堆栈被写坏了 没有进一步可以帮助到的信息。
不过方法总比问题多。 我们可以在编译新的可执行文件时开启以下gcc 编译选项
-
-fstack-protector-all (https://www.ibm.com/developerworks/cn/linux/l-cn-gccstack/index.html) 该选项旨在通过Canaries检测来判断栈是否被破坏,在破坏前让程序抛异常退出。 当然还有另外一个目的是提高栈溢出攻击的成本。有兴趣的可以了解下原理。通过这种方式来进行堆栈保护
- -g 加上g选项后编译器会做如下额外操作
- 创建符号表,生成的文件包含符号表内容。生成的core文件也会附带符号表相关内容
- 关闭优化机制,程序严格按照原来的代码执行,避免定位问题对应代码带来的偏移干扰
- 开启-O0 选项避免参数和函数inline。 生产环境建议开启为-O2 。这里为了方便定位问题,临时调整成该选项。
执行完上述步骤之后,采用新的二进制文件执行,程序coredump文件堆栈 如下所示:
出现_stack_chk_fail 毫无疑问是栈空间被写坏了。bt查看函数栈桢底部丢失,第#6函数桢丢失, 可以推断是上一桢函数把自己的返回地址搞丢了。可以重点排查下SaveTbFamily上 申请的栈变量以及内存拷贝赋值相关的代码
如果逻辑比较复杂,可以把该函数内申请的所有栈变量【主要是自定义类型】替换成堆变量。 再编一个版本出去,栈溢出可以肯定也能把对应的堆变量整溢出,堆溢出不至于把函数栈弄坏。
重新修改一个版本之后,重新执行获取到的core文件如下:这里终于借助堆溢出把完整的函数栈打印出来了。 接下来的事情就是常规的coredump问题定位了。
当然上述步骤仅限于在内网操作,如果是现网,最好隔离出一台机子,放少量流量进来复现。 定位问题不以要影响现网服务为首要原则 目前仅遇到上述场景,有其他好的方法,欢迎交流
扩展阅读:
- https://blog.csdn.net/mergerly/article/details/80523750
- https://blog.csdn.net/oscarjulia/article/details/74256997