You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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会输出内存重叠错误?


原因分析

  1. 内存重叠检查默认未完全启用:
    Memcheck的内存重叠检查默认是partial模式,该模式仅对字符串操作函数(如strcpy、strcat)做严格检查,对memcpy这类通用内存复制函数的检查非常有限,甚至不触发。必须手动开启完整检查模式才能检测memcpy的重叠问题。

  2. 复制长度导致重叠范围未被检测:
    你代码中的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 02:40:26