C++ 项目,出现了匪夷所思的 bug,在 vector 中添加对象,会导致 vector 崩溃,进而整个程序崩溃。

2023-05-18 15:08:30 +08:00
 villivateur

这个项目很大,我修改了其中一部分代码,出现了一个非常匪夷所思的问题:

这个是出问题的函数:

void SetModuleIdentities(std::vector<uint32_t>& identities)
{
	std::vector<ModuleConfig> testVec;
	for (uint32_t const& identity : identities)
	{
		printf("enter... testVec.size=%ld %ld\n", testVec.size(), testVec.capacity());
		ModuleConfig newModule;
		newModule.identity = identity;
		testVec.push_back(newModule);
		printf("leave... testVec.size=%ld %ld\n", testVec.size(), testVec.capacity());
	}
}

这是 ModuleConfig 的定义:

struct ModuleConfig
{
	ModuleConfig()
	{
		printf("ModuleConfig::constructor\n");
	}
	~ModuleConfig()
	{
		printf("ModuleConfig::destructor\n");
	}
    
	uint32_t identity;
	std::string pdoMapName;
	uint32_t pdoMapInOffset;
	uint32_t pdoMapOutOffset;
};

执行的输出如下:

enter... testVec.size=0 0
ModuleConfig::constructor
leave... testVec.size=3353953467947191204 1
ModuleConfig::destructor
# 然后就崩溃了

这是部分调用栈信息(来源 sighandler ):

15:03:36  ecpanda exit with 11
crash time:Thu May 18 15:03:36 2023

./base/lib-linux/bin/ecpanda-generic(_Z10sigHandleriP9siginfo_tPv+0x96) [0x56266aff3e9a]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x14420) [0x7f528d9d7420]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x20) [0x7f528d50b6f0]
./base/lib-linux/bin/ecpanda-generic(_ZN12ModuleConfigD1Ev+0x2c) [0x56266b0075e6]
./base/lib-linux/bin/ecpanda-generic(_ZN15SlaveFileConfig19SetModuleIdentitiesERSt6vectorIjSaIjEE+0x136) [0x56266b017138]
./base/lib-linux/bin/ecpanda-generic(_Z23ESI_SetModuleIdentitiesiRSt6vectorIjSaIjEE+0x42) [0x56266b01692c]

我就 push_back 了一下,怎么就把 vector 干崩了呢?

6105 次点击
所在节点    C++
73 条回复
corhuan
2023-05-18 17:53:18 +08:00
ModuleConfig 的定义贴全了吗?
loveumozart
2023-05-18 17:54:00 +08:00
还有就是在指针操作前后的地方多打日志,从日志角度运气好的话也可以看到在崩溃之前,就有一些写坏了的数据
tkhmy
2023-05-18 17:55:16 +08:00
@villivateur 试试在构造里把 pdoMapName 初始化一下
anerevol
2023-05-18 17:57:20 +08:00
kkkbbb
2023-05-18 18:58:55 +08:00
原因找到了么?
tomychen
2023-05-18 19:13:07 +08:00
@villivateur #2

如果我没记错,push_back 是个 shallow copy ,也就是说...其实还是指针,这也解释了为什么后改为 new 了不会触发。而如果没有估计错,#4 说的,加个拷贝构造,应该也不会触发。
786375312123
2023-05-18 19:21:07 +08:00
callstack 报错怎么说?
786375312123
2023-05-18 19:22:15 +08:00
刚看到了,你这信息也太少了,在 vs 里跑跑试试。
ashong
2023-05-18 19:28:46 +08:00
leave... testVec.size=3353953467947191204 1

应该是 push 出错, 导致返回 size 异常
加个异常处理看看
MrEatChicken
2023-05-18 19:49:34 +08:00
其他地方的代码把栈写坏了。
加 ASan 检测下哪里写坏了。
https://zhuanlan.zhihu.com/p/360135083
documentzhangx66
2023-05-18 20:21:52 +08:00
不建议用 std::vector ,这玩意在设计阶段就有问题,该提供的功能没有,不需要的特性给你强塞一堆。

建议自己实现一个纯粹的 queue 或 list 。

要不去 github 找个 java 风格的。
lovelylain
2023-05-18 20:59:06 +08:00
检查下代码里有没有#pragma pack(n)对齐指令但没有#pragma pack()恢复默认,多年前遇到过这样一个案例,同事在他的头文件里 pack 对齐但没取消,我的结构体定义在我的头文件里,在不同 cpp 文件,先包含他的头文件再包含我的,和先包含我的或者不包含他的,我那个结构体的大小会不一样,于是也出现了匪夷所思的 crash ,害我 gdb 怼了小半天。
villivateur
2023-05-18 21:42:12 +08:00
@imagecap printf 是因为出问题才加了调试的
GeruzoniAnsasu
2023-05-18 21:48:59 +08:00
@villivateur

> 如果是其他部分的 bug ,但我这里的 testVec 是局部变量。难道是其他地方把堆区破坏了吗?

vector 实际用到的内存一律在堆上,跟对象本身分配在栈上还是堆上无关。
这种崩溃 bug 基本上都是 heap corruption ,建议还是开一下 santinizer 或者 valgrind 看看有没有帮助。



heap corruption 是最难调的…… 因为导致污染的地方和触发 crash 的地方可能相差十万八千里…… 祝好运
villivateur
2023-05-18 22:14:14 +08:00
@e7 只 push 了一次,那个 size 很大说明已经出问题了。

话说已经确认跟 vector 没关系了,问题在 ModuleConfig 的析构函数。
leonshaw
2023-05-18 22:19:04 +08:00
@villivateur 还没解决?直接 gdb watch vector 实现里的 _M_impl._M_start 和 _M_impl._M_finish ,看什么时候写坏的
villivateur
2023-05-18 22:20:10 +08:00
@leonshaw 哈哈,早下班了,明天再看。话说看下附言,已经确定跟 vector 没关系了,是那个 ModuleConfig 的析构函数的问题
felixlong
2023-05-18 22:21:47 +08:00
@villivateur 看看你 ModuleConfig 定义的头文件里是不是有什么宏。导致 ModuleConfig 实现文件里的析构函数看到的 ModuleConfig 和 SetModuleIdentities 这里看到的 size 其实不一样。
leonshaw
2023-05-18 22:22:44 +08:00
@villivateur 但是错误的 size 是析构之前打出来的,析构只是踩到野地址挂了,之前应该就有问题。
mingl0280
2023-05-18 22:29:54 +08:00
高度怀疑你的 std::string 不是 std::string 而是其它的什么东西。

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

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

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

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

© 2021 V2EX