一行简单的 C++字符串处理代码引发的血案

4 天前
 vfx666
原谅我标题党……
但这个事确实很蹊跷。起初是客户反映程序在几小时后会闪退,调试了很久,终于定位到问题
xid.erase(xid.end() - 2, xid.end());
( xid 是 std string 类型的全局变量)
就这么一行简单的代码,会导致程序在正常运行几小时后触发崩溃。即使该行代码并没有执行(并且这行代码也不会触发崩溃),但只要编译时有这行代码,程序刚开始一切正常,过了几小时后必崩。删了这行重新编译就一切正常。
不知道各位大佬怎么看……难不成是编译器的 bug ?
797 次点击
所在节点    程序员
13 条回复
bfjm
4 天前
xid 大小是否超过了 2 xid 是否有线程安全问题
vfx666
4 天前
@bfjm 都没有
bfjm
4 天前
@vfx666 用 valgrind 跑一下 可以把堆栈信息贴出来
billccn
3 天前
你是怎么定位到这行代码的?

这代码看上去人畜无害,除非编译器认为 xid.size()必定小于 2 ,于是编译了个 undefined behavior 进去?

当然编译问题也是有可能的,你有保留这行代码然后 clean 编译过一次吗?
vfx666
3 天前
@billccn 一点点排除定位到的问题,因为测试了软件之前的发行版没有问题,这就可以把范围缩小到具体的代码段了。然后进一步缩小排除,最后发现就是这么一行

保留这行代码,即使此代码并没有被执行(写一个 if 判断故意跳过这行)还是会触发问题。你说的 clean 编译是指的那个“重新编译…”选项吗
w568w
3 天前
@vfx666 怎么“故意跳过”的? if(false)?

说实话我觉得可能性更大的是定位错了问题位置。具体闪退有 dump 吗?有试过删除这行代码就好了吗?
vfx666
3 天前
@w568w 就是试过,删了就好了。所以很离谱
araraloren
3 天前
haha
Promtheus
3 天前
每个程序员都经历过这种看不出问题只能一个个代码删掉试试看的情况。哈哈哈 我在想是不是火箭飞船这些上面的代码也有这种情况
realpg
3 天前
先改写这一行
xid.erase(xid.end() - 2, xid.end());

拆语句成

tmp_a = xid.end()
tmp_b = tmp_a -2
log tmp_a, tmp_b to logfile with current timestamp
xid.erase(tmp_b,tmp_a)
lixile
3 天前
大概率 overflow 了 只是这行代码所在参与编译后 导致崩溃的内存位置被 overflow 到了
不参与时 overflow 位置 没有涉及关键内存
billccn
3 天前
@vfx666 等等,一楼问你 xid 大小有没有超过 2 ,你二楼回答没有。那 xid 的大小会不会不到 2 ?你加的 if 是检测 xid 的长度吗?不是的话能不能加一个试试?可能其他部分就有 bug ,导致 xid 偶尔不到 2 个长,之前没有做 erase 所以没有发现?

然后,11 楼说的是很有可能的,因为你这行代码虽然不执行,但是为了能执行这行代码,编译器可能改变了堆栈帧的长度,或者初始化了某些信息,这导致其他(已有的)代码 overflow 到了更关键的地方。

但我们这都是凭空猜测,你要想方设法弄到个 stack 。
vfx666
3 天前
@lixile 这行代码改为
xid = xid.substr(0, xid.size() - 2);
程序就一切正常了。。。

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

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

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

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

© 2021 V2EX