应优先修复invalid read/write和use of uninitialised value,因其是更上游的错误,易导致崩溃、状态污染和误报;而definitely lost仅缓慢耗尽资源,且调用栈不指明释放责任方。

优先修 Invalid read / Invalid write 和 Use of uninitialised value,而不是先盯着 definitely lost
为什么不能先修内存泄漏?
内存泄漏(definitely lost)是程序退出时还持有的、已无指针可达的堆内存。它本身不导致崩溃,只缓慢耗尽资源。但 Invalid read 或 Use of uninitialised value 往往是更上游的错误——比如越界写覆盖了邻近变量、未初始化指针被当有效地址解引用、或释放后继续使用(use-after-free)。这类错误会污染内存状态,让后续行为不可预测,甚至掩盖真正的问题源头。
常见现象包括:
- 修复一个
definitely lost后,报告里突然冒出多个新的Invalid write——说明原泄漏点其实是某次非法操作的“结果”,而非原因 - 同一行代码在不同运行中报错类型不一致(有时 leak,有时 segfault),本质是未初始化值或越界写引入了随机性
-
definitely lost的调用栈显示分配发生在malloc或new,但没告诉你谁该负责free/delete;而Invalid free会直接指出哪一行调用了错误的释放
Invalid free 和 Mismatched free 必须立即处理
这类错误直接违反 C/C++ 内存管理契约,极大概率引发后续崩溃或静默数据损坏。Valgrind 报告中明确标出函数名和行号,修复路径清晰:
-
Invalid free():对栈变量、文字常量、或非 malloc 分配的地址调用free(例如free("hello")或free(&x)) -
Mismatched free():用free释放new分配的内存,或用delete[]释放new单对象——Valgrind 会提示 “mismatchedfree/delete/delete[]” - 重复
free:同一地址被释放两次,后续任何对该内存的访问都不可信
--track-origins=yes 是查未初始化问题的关键开关
当看到 Use of uninitialised value 时,不加 --track-origins=yes 的报告只告诉你“这里用了未初始化值”,但不告诉你这个值从哪来。加上后,Valgrind 会追溯到变量定义、函数传参、甚至寄存器加载点。实际效果差异极大:
- 没开:报告只停在
if (x > 0)这一行 - 开了:报告会追到
x = buf[i](而buf是malloc未memset)、或foo(x)调用时传入了未初始化的局部变量 - 注意:开启后性能下降约2倍,但对定位根源必不可少;不要在完整 leak-check 场景下默认开启,按需启用
容易被忽略的陷阱:栈上越界读写 Valgrind 不报
Valgrind 的 memcheck 默认不检测栈上越界(如 char buf[10]; buf[15] = 'x';),因为栈布局和保护机制复杂,误报率高。但它会报堆上越界(malloc 分配的数组)、全局变量越界、以及释放后使用(无论堆/栈)。所以当你怀疑栈溢出却没看到 Valgrind 报错,别以为没问题——得换 AddressSanitizer 配合验证。这点很多人卡住很久才意识到。











