求助大神! C++程序异常挂断

2019-08-14 17:17:20 +08:00
 tengtengking

程序会异常断掉。用 gdb 运行 core 文件,通过 bt 命令定位到 movdqu 指令,原因不明。 哪位大神可以指导下,有什么手段或者方法,可以帮助定位到程序异常原因。

core 文件 bt 输出如下:

gdb ./a.out core.out

………………
………………

Program terminalted with signal 11, segmentation fault.
#0 __memmove_ssse3_back () at ../sysdeps/x86_64/multiarch/memcpy-ssse3-back.S:1658
1658		movdqu -0x40(%rsi),%xmm4
(gdb) bt
#0 __memmove_ssse3_back () at ../sysdeps/x86_64/multiarch/memcpy-ssse3-back.S:1658
#1 0x0000000000000000 in ?? ()
(gdb) quit

5400 次点击
所在节点    C++
40 条回复
nvioue
2019-08-14 20:23:52 +08:00
好了 楼主这个事情本身就证明了用 c/cpp 开发程序是多么的痛苦; 用 java/.net 基本不会遇到这种鬼事情. 系统及其友好的抛出完整栈给你.

以下来自一个刚转 java 的 7 年 cpp 一线人员的排查经验

1 先确定 core 文件和程序文件是否对应. core 文件很多,一般需要确定这个 core 文件是你的程序生成并且是最近一次的. 这一步要是弄错了你后面怎么查都没用. 是不是很刺激

2 这个 bt 基本毫无价值, 请确认是否有多线程. info thread (好像是这个?), 如果有多线程请依次确认每个线程的 bt 是否能帮助你

3 如果是单线程,我可以 100%告诉你这个是栈 stack 被破坏导致 gdb 的栈回溯功能失效. 这个 core 文件基本没有太大帮助信息了, 如果有其他大佬有方法欢迎分享.

接下来说遇到这种 stack 被破坏如何解决. 基本表现为 bt 信息乱七八糟, 或者直接就是一大排问号.
正常的栈信息最底层基本是 main 函数开始并且函数信息完整.
除非你的代码有使用到协程,内联汇编等黑魔法.
此类问题原因多种多样, 因为栈上的内存含有 cpp 函数栈调用信息, 一旦 rbp 的值被破坏就 GG

因为有阵子不搞 cpp 了 , 不太记得所有招式了.
1 用 valgrind 带程序跑, 尝试重现. 如果你知道 valgrind 是干啥的,应该能解决了, 记得用合适的参数, 不然他的输出信息多到看不完
2 如果#1 无法重现, 寻找重现方法, 找到对应的功能代码做 review (非常难)
3 增加编译选项 -g -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 祝你好运(我以前基本是用这个,成功率较高)
4 使用 cpplint 等强静态检查工具尝试找出可疑代码
LitostCheng
2019-08-14 20:36:28 +08:00
[backtrace 了解一下]
在 Linux 中如何利用 backtrace 信息解决问题:
https://blog.csdn.net/jxgz_leo/article/details/53458366
tengtengking
2019-08-14 21:30:04 +08:00
@nvioue 非常感谢。 方法 1 已经尝试过了 , 发现 用上 valgrind 后运行变得十分缓慢,生产环境影响比价大,没能复现。
tengtengking
2019-08-14 21:31:07 +08:00
@nvioue 我去学习下你的这几个编译参数,尝试一下
laminux29
2019-08-14 21:57:02 +08:00
我建议题主应该学点 java 软件工程的方法,这样就不至于那么难堪,居然要搬出 gdb 对着一堆啥玩意来调试。

第一步,建议题主找一款靠谱的日志框架,先把日志框架搭起来。

第二步,通过日志判断出问题的大概位置,然后对这区域的代码,进行源码调试。
boywhp
2019-08-14 22:05:21 +08:00
写一个 memcpy 封装函数, 每次调用时 printf 参数到屏幕或日志, 尤其注意检查 len 是否异常
lingxi27
2019-08-14 22:51:15 +08:00
这种问题试试日志配合单元测试
SPACELAN
2019-08-15 00:16:35 +08:00
sse 指令,,看看栈和超操作的地址有没有对齐 16 字节
Chenamy2017
2019-08-15 09:08:31 +08:00
1.dmesg 看程序出错的位置
2.objdump -d xxx 找到这个地址,基本能确定是哪个函数的那行代码了
tengtengking
2019-08-15 09:28:34 +08:00
@laminux29 日志用的 glog,出错的地方也没什么信息
eliteYang
2019-08-15 09:37:49 +08:00
至少吧完整栈和最后一行可读代码贴出来啊
whi147
2019-08-15 09:56:25 +08:00
可能是指针生命周期结束了
tengtengking
2019-08-15 10:21:21 +08:00
@eliteYang 我也想定位到你说的这两个地方。可是定位不到呀
hsuehsen
2019-08-15 10:35:51 +08:00
bt 这样的信息,说明跑的不是 debug 版; 编译个 debug 版本,然后尝试重现问题

最重要的问题是,
1. 重现问题
2. 重现问题
3. 重现问题

若无法重现,那只能是过代码。通过楼上一些提供的方法,确定初步位置,然后前后过一边所有 memcpy 相关的操作。大概率呢,是两种可能,
1. 内存越界(这种比较坑)
但是可怀疑的地方也好确定

2. 空指针
这个大概率是某个流程处理的问题,比如某个判断失败还是继续往下走
tengtengking
2019-08-15 11:30:24 +08:00
@hsuehsen 这是 debug 版本的
hsuehsen
2019-08-15 14:33:11 +08:00
@tengtengking
你这 bt 的符号都没有,明显不是 debug 版,或者部分以来的库或子模块是没有调试符号的。要么就是把符号都去掉了
tengtengking
2019-08-15 19:44:29 +08:00
@Chenamy2017 dmesg 看到看到的 ip, 在 objdump 的输出里看不到,这是怎么回事? dmesg 显示错在 libc-2.12.so
Chenamy2017
2019-08-16 17:19:07 +08:00
恰巧我也刚遇到了在 C 库的错误,我的问题是空指针引起。
peiqing9003ah
2020-01-10 15:46:34 +08:00
@tengtengking 兄弟, 能不能告诉我你的解决方案 是怎么用 valgrind attach 到服务程序的, 这是运行的服务进程呐!
tengtengking
2020-02-04 10:36:30 +08:00
@peiqing9003ah 直接用 valgrind 运行程序。valgrind --leak-check=full --show-reachable=yes --trace-children=yes --log-file=./valgrind.log ./a.out

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/591884

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX