0

In Valgrind's Memcheck tool, it says

The following C library functions copy some data from one memory block to another (or something similar): memcpy, strcpy, strncpy, strcat, strncat. The blocks pointed to by their src and dst pointers aren't allowed to overlap. The POSIX standards have wording along the lines "If copying takes place between objects that overlap, the behavior is undefined." Therefore, Memcheck checks for this.

So I think if I use memcpy to copy between overlapped addresses, I can get this error from valgrind memcheck.

So I write the following code. However, either in the C++ version or the C version, I can't make valgrind memcheck for a overlap error.

int main()
{
    // The C++ version
    int * x = new int[3]{1, 2, 3};
    memcpy(x + 1, x, 2);
}

int main()
{
    // The C version 
    void * y = malloc(10);
    memset(y, 0, 10);
    memcpy(y + 1, y, 2);
}

In fact, if I run by the following command

valgrind --tool=memcheck --leak-check=full --track-origins=yes ./tt

Then I will get

==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)

I wonder why, and in what situation can valgrind output an overlap error?

calvin
  • 2,125
  • 2
  • 21
  • 38
  • 2
    `memcpy(x + 1, x, 2);` -- You are copying 2 bytes, not 2 ints. `int * y = (int*)malloc(10);` -- You are allocating 10 bytes, not 10 integers. In both scenarios, was this your intent to use 2 and 10 bytes, or actually 2 ints and 10 ints? – PaulMcKenzie Jan 23 '23 at 08:56
  • 1
    `sizeof y` is the size of the pointer, not the size of the array. – pmacfarlane Jan 23 '23 at 08:57
  • There are obvious errors and/or misconceptions of how `malloc`, `memcy`, and `sizeof` actually work. Correct those first, and then retest. – PaulMcKenzie Jan 23 '23 at 08:59
  • You don't cast the void * in c. – Allan Wind Jan 23 '23 at 09:02
  • @PaulMcKenzie I don't know why the C++ version is wrong, the `x` has type `int *`, so `x + 1` is the next int in the array. – calvin Jan 23 '23 at 09:03
  • @PaulMcKenzie Also, I think I have fixed the C version. Seems still not work. – calvin Jan 23 '23 at 09:07
  • Doing pointer arithmetic on a `void *` is undefined, I believe. You might [get away with it](https://stackoverflow.com/questions/15228723/c-void-pointer-arithmetic), [depending on your compiler](https://stackoverflow.com/questions/6449935/increment-void-pointer-by-one-byte-by-two). – pmacfarlane Jan 23 '23 at 09:11
  • 1
    Can you switch from `memcpy(y + 1, y, 2);` to `memcpy(y + 1, y, 100);` and see the output of valgrind? If you get something like `Invalid write of size 1 at 0x484EA7E: memmove ...` it means that `memcpy` is an alias of `memmove` on your platform (regions can overlap) – David Ranieri Jan 23 '23 at 09:18

1 Answers1

3

Even with just a debug build the compiler sees that it's more efficient not to make a call to memcpy:

https://godbolt.org/z/P9s664Gx8

GCC is similar. I don't get a call to memcpy until 12 bytes are copied.

Paul Floyd
  • 5,530
  • 5
  • 29
  • 43
  • 4
    Compiling with `-fno-builtin-memcpy` (or just `-fno-builtin`) prevents the inlining of `memcpy` and might get diagnosed (assuming the copy is actually made to work on 2 integers rather than 2 bytes). – Hasturkun Jan 23 '23 at 11:16
  • And just for fun, the compiler can also replace an assignment with a call to memcpy. – Paul Floyd Jan 23 '23 at 15:02