为何Valgrind Memcheck未检测到memcpy内存重叠错误?
为什么Valgrind Memcheck没检测到memcpy的内存重叠?
背景
Valgrind的Memcheck工具文档提到:
以下C库函数会在内存块间复制数据:memcpy、strcpy、strncpy、strcat、strncat,其src和dst指针指向的内存块不允许重叠。POSIX标准规定重叠复制行为未定义,因此Memcheck会对此进行检查。
基于此,我认为用memcpy处理重叠内存地址时Memcheck应该报错,于是编写了以下C++和C代码:
// C++版本 int main() { int * x = new int[3]{1, 2, 3}; memcpy(x + 1, x, 2); }
// C版本 int main() { void * y = malloc(10); memset(y, 0, 10); memcpy(y + 1, y, 2); }
使用命令运行:
valgrind --tool=memcheck --leak-check=full --track-origins=yes ./tt
但运行后只得到内存泄漏报告,完全没有触发内存重叠错误提示:
==33771== Memcheck, a memory error detector ==33771== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==33771== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info ==33771== Command: ./tt ==33771== ==33771== ==33771== HEAP SUMMARY: ==33771== in use at exit: 10 bytes in 1 blocks ==33771== total heap usage: 2 allocs, 1 frees, 72,714 bytes allocated ==33771== ==33771== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==33771== at 0x4C29F73: malloc (vg_replace_malloc.c:309) ==33771== by 0x4006C8: main ==33771== ==33771== LEAK SUMMARY: ==33771== definitely lost: 10 bytes in 1 blocks ==33771== indirectly lost: 0 bytes in 0 blocks ==33771== possibly lost: 0 bytes in 0 blocks ==33771== still reachable: 0 bytes in 0 blocks ==33771== suppressed: 0 bytes in 0 blocks ==33771== ==33771== For lists of detected and suppressed errors, rerun with: -s ==33771== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
我想知道:为什么没触发内存重叠错误?以及在何种场景下Valgrind会输出内存重叠错误?
原因分析
内存重叠检查默认未完全启用:
Memcheck的内存重叠检查默认是partial模式,该模式仅对字符串操作函数(如strcpy、strcat)做严格检查,对memcpy这类通用内存复制函数的检查非常有限,甚至不触发。必须手动开启完整检查模式才能检测memcpy的重叠问题。复制长度导致重叠范围未被检测:
你代码中的memcpy调用复制长度仅为2字节,重叠区域非常小,即使在partial模式下也很难触发检查逻辑。这类小范围重叠通常不在默认检查的范围内。
触发内存重叠错误的场景
要让Memcheck检测到memcpy的内存重叠,需要满足两个条件:
- 启用完整重叠检查:运行Valgrind时添加
--overlap-check=full选项,完整命令示例:valgrind --tool=memcheck --leak-check=full --track-origins=yes --overlap-check=full ./tt - 存在有效重叠区域:确保memcpy的源、目标内存区域重叠部分覆盖了实际被复制的字节。比如修改代码中的复制长度为更大的值,例如将C版本中的
memcpy(y + 1, y, 2);改为memcpy(y + 1, y, 5);,此时源区域[y, y+4]和目标区域[y+1, y+5]存在4字节的有效重叠,会触发检查。
启用完整检查后,运行修改后的代码会得到类似如下的错误提示:
==XXXX== Source and destination overlap in memcpy(0xXXXXXX, 0xXXXXXX, 5) ==XXXX== at 0x4C2B06F: memcpy (vg_replace_strmem.c:1039) ==XXXX== by 0x4006D8: main (tt.c:6)
内容的提问来源于stack exchange,提问作者calvin
相关产品推荐
相关产品推荐

