Valgrind 能检测 Linux 下带调试信息的动态链接 ELF 二进制,不支持 shell 脚本、静态链接(尤其 musl)、stripped 文件或 setuid/setgid 程序;需编译加 -g -O0、保留符号、禁用 strip,并用 --tool=memcheck --leak-check=full 运行。

Valgrind 能直接检查任何可执行文件,包括命令行工具 —— 关键是它必须是 Linux 下编译的、带调试信息的二进制,且不能是静态链接或 stripped 的。
为什么 valgrind ./mytool 报错“can't execute binary file”
常见于以下情况:
- 你的
mytool是 shell 脚本(不是 ELF 可执行文件),valgrind 只能运行原生二进制,需先用file mytool确认类型; - 它是静态链接的(尤其含
musl或自建交叉编译链),valgrind 对部分静态链接支持有限,会拒绝加载; - 二进制被
strip过,虽不影响运行,但 valgrind 依赖符号和调试段定位问题,--leak-check=full会失效或报错; - 目标程序用了
setuid或setgid,valgrind 默认禁止执行这类程序,加--allow-mismatching-sonames=yes无效,必须去掉权限位再测。
如何让命令行工具适配 valgrind 检测
核心就两条:编译时留符号,运行时不绕过检查机制。
- 重新编译时务必加
-g,若用 CMake,设CMAKE_BUILD_TYPE=Debug; - 禁用优化(
-O0)更稳妥,避免内联或寄存器优化掩盖未初始化变量; - 不要用
strip mytool,哪怕发布前才 strip,调试阶段保留原始二进制; - 如果工具依赖动态库(如
libjson-c.so.5),确保这些库没被删/替换,valgrind 需要完整加载所有依赖; - 若工具本身接受命令行参数(如
./mytool --input file.txt -v),直接追加在 valgrind 命令末尾:valgrind --tool=memcheck --leak-check=full ./mytool --input file.txt -v。
常见输出里哪些行真该立刻处理
valgrind 输出冗长,盯住这三类即可:
-
Invalid read of size X或Invalid write of size X:几乎肯定是越界或访问已free内存,调用栈顶的那行代码就是根因; -
Use of uninitialised value of size X:尤其出现在条件判断或 memcpy 参数中,--track-origins=yes能指出这个值最初从哪读来的; -
definitely lost: X bytes in Y blocks:程序退出时指针彻底丢失,new/malloc 后没配对 delete/free,比possibly lost更确定要修。
实际跑起来慢是必然的 —— 不是 bug,是代价。别试图在 CI 里全量跑 valgrind,它只适合本地验证关键路径或复现 crash 前的内存异常。另外,如果你的命令行工具 fork 出子进程并长期运行,valgrind 默认只跟踪主进程,子进程内存问题会被忽略,这时得用 --trace-children=yes 显式开启追踪。


















