The only portable way to determine if two memory ranges overlap is:

int overlap_p(void *a, void *b, size_t n)
{
    char *x = a, *y =  b;
    for (i=0; i<n; i++) if (x+i==y || y+i==x) return 1;
    return 0;
}

This is because comparison of pointers with the relational operators is undefined unless they point into the same array. In reality, the comparison does work on most real-world implementations, so you could do something like:

int overlap_p(void *a, void *b, size_t n)
{
    char *x = a, *y =  b;
    return (x<=y && x+n>y) || (y<=x && y+n>x);
}

I hope I got that logic right; you should check it. You can simplify it even more if you want to assume you can take differences of arbitrary pointers.

Answer from R.. GitHub STOP HELPING ICE on Stack Overflow
Top answer
1 of 3
14

The only portable way to determine if two memory ranges overlap is:

int overlap_p(void *a, void *b, size_t n)
{
    char *x = a, *y =  b;
    for (i=0; i<n; i++) if (x+i==y || y+i==x) return 1;
    return 0;
}

This is because comparison of pointers with the relational operators is undefined unless they point into the same array. In reality, the comparison does work on most real-world implementations, so you could do something like:

int overlap_p(void *a, void *b, size_t n)
{
    char *x = a, *y =  b;
    return (x<=y && x+n>y) || (y<=x && y+n>x);
}

I hope I got that logic right; you should check it. You can simplify it even more if you want to assume you can take differences of arbitrary pointers.

2 of 3
2

What you want to check is the position in memory of the source relatively to the destination:

If the source is ahead of the destination (ie. source < destination), then you should start from the end. If the source is after, you start from the beginning. If they are equal, you don't have to do anything (trivial case).

Here are some crude ASCII drawings to visualize the problem.

|_;_;_;_;_;_|          (source)
      |_;_;_;_;_;_|    (destination)
            >-----^    start from the end to shift the values to the right

      |_;_;_;_;_;_|    (source)
|_;_;_;_;_;_|          (destination)
^-----<                 start from the beginning to shift the values to the left

Following a very accurate comment below, I should add that you can use the difference of the pointers (destination - source), but to be on the safe side cast those pointers to char * beforehand.

In your current setting, I don't think that you can check if the operation will fail. Your memcpy prototype prevents you from doing any form of checking for that, and with the rule given above for deciding how to copy, the operation will succeed (outside of any other considerations, like prior memory corruption or invalid pointers).

Top answer
1 of 5
29

I believe you mean memmove which takes care of memory overlapping as oppose to memset. but what is memory overlapping anyway?

suppose we have an array of 5 chars, where each char is a byte long

+++++++++++++++++++++++++++++++
| 'a' | 'b' | 'c' | 'd' | 'e' |
+++++++++++++++++++++++++++++++
 0x100 0x101 0x102 0x103 0x104

now according to the man page of memcpy, it takes 3 arguments, a pointer to the destination block of memory, a pointer to the source block of memory, and the size of bytes to be copied.

what if the destination is 0x102, the source is 0x100 and the size is 3? memory overlapping happens here. that is, 0x100 would be copied into 0x102, 0x101 would be copied into 0x103 and 0x102 would be copied into 0x104.

notice that we first copied into 0x102 then we copied from 0x102 which means that the value which was originally in 0x102 was lost as we overwrote it with the value we copied into 0x102 before we copy from it. so we would end up with something like

+++++++++++++++++++++++++++++++
| 'a' | 'b' | 'a' | 'b' | 'a' |
+++++++++++++++++++++++++++++++
 0x100 0x101 0x102 0x103 0x104

instead of

+++++++++++++++++++++++++++++++
| 'a' | 'b' | 'a' | 'b' | 'c' |
+++++++++++++++++++++++++++++++
 0x100 0x101 0x102 0x103 0x104

how does a function like memmove take care of memory overlapping? according to its man page, it first copies the bytes to be copied into a temporary array then pastes them into the destination block as oppose to a function like memcpy which copies directly from the source block to the destination block.

2 of 5
1

Lets see:

memset: sets a memory segment to a constant value, so, there is no "overlapping" possible here, because there is just a unique, contiguous, memory segment to "set".

memcpy: you are reading from one memory segment and, well, copying it to another memory segment. If the memory segments coincide at some point, a "overlapping" would occur. Imagine a memory segment starts at address 0x51, and the other starts at address 0x70, and you try to copy 50 bytes from 0x51 to 0x70... at some point, the process will start reading from address at 0x70, and copying to address 0x8F. This is most likely not what you wanted to do.

At a lower level, in assembly, you should be able to find several ways of doing this, including MMX, SSE2 and other SIMD instructions. If you download glibc source code (https://www.gnu.org/software/libc/download.html), you will see some implementations done in assembly.

C is a "high-level" language, but is quite close to assembly, you can get memory address for variables and even for functions, so, it is quite powerful, allowing you to do all kind of things, like reading/writing an array after its "official" end (the OS will stop you once you try to access memory outside your process' memory), so, yes, memory overlapping is totally possible in C. Something like this would create two potentially overlapping memory "segments" (actually, the same segment, that I am manually dividing and assigning to two pointers).

This is a funny-behaving program, it is definitely, and intentionally buggy, just to show what kind of odd things can happen if memory do overlap with memcpy:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
        char *a,*b;
        a=malloc(100*sizeof(char));
        b=(a+25);
        strcpy(a,"This is just a test");
        strcpy(b,"And this is another test, longer test string.");
        printf("a: %s\nb: %s\n",a,b);
        printf("Now, I am copying b in a, and lets see what happen...\n");
        memcpy(a,b,75);
        printf("a: %s\nb: %s\n",a,b);
}

Save it to a .c file, like test.c, and compile it using gcc, like this:

gcc -O0 -o test test.c

Run it and then try again compiling like that:

gcc -O2 -o test test.c

It will (most likely) behave differently.

Try replacing memcpy with strncpy and see what happen.

I hope the example is useful.

Discussions

c - Meaning of overlapping when using memcpy - Stack Overflow
But it's not typically implemented that way in practice. 2022-11-17T21:56:59.16Z+00:00 ... @urvi_189 sounds like copying with a reverse iterator has not yet been invented [case 2 in Jabberwocky's answer]. 2024-11-25T11:41:15.623Z+00:00 ... Save this answer. Show activity on this post. *) The main difference between memcpy and memmove is,memcpy works on the same string but memmove works in separate memory by taking a copy of the string. *) Due to this,overlapping ... More on stackoverflow.com
🌐 stackoverflow.com
What is memcpy in c?
I always thought of it as a fairly ... it to the destination. This prevents problems if the source and destination blocks overlap each other. Memcpy vs memmove in c | memmove implementation | own code... More on experts-exchange.com
🌐 experts-exchange.com
September 8, 2022
How does memmove allow the copying to be done in a non-destructive manner unlike memcpy?
Your question is a bit hard to understand. A naive memmove operation could copy source to some temp buffer and then copy that temp buffer to dest. Ofcourse, you can make it wayy more optimized, but creating a safe and correct memmove is not that hard. More on reddit.com
🌐 r/C_Programming
38
3
May 14, 2023
c - memcpy() vs memmove() - Stack Overflow
In general, memcpy is implemented in a simple (but fast) manner. Simplistically, it just loops over the data (in order), copying from one location to the other. This can result in the source being overwritten while it's being read. memmove does more work to ensure it handles the overlap correctly. More on stackoverflow.com
🌐 stackoverflow.com
🌐
Aticleworld
aticleworld.com › home › implementation of memcpy in c language
Implementation of memcpy in C language - Aticleworld
December 11, 2023 - 1.The memcpy() declares in the header file <string.h>. 2. The size of the destination buffer must be greater than the number of bytes you want to copy. 3. If copying takes place between objects that overlap, the behavior is undefined.
🌐
Medium
medium.com › @caruychen_48871 › the-curious-case-of-memcpy-bd93936e5136
The curious case of memcpy()
December 9, 2021 - The memcpy() function copies n bytes from memory area src to memory area dst. If dst and src overlap, behavior is undefined.
🌐
Equestionanswers
equestionanswers.com › c › memcpy-vs-memmove.php
Memcpy vs memmove in c | memmove implementation | own code
Memmove copies memory blocks from source location to destination location like memcpy but it also takes care of the overlapping. Copy of the memory bytes are done in non-destructive manner. ... You have viewed 1 page out of 252. Your C learning is 0.00% complete.
🌐
Quora
quora.com › What-does-it-mean-that-the-address-of-source-and-destination-can-overlap-in-memcpy-function-What-is-overlap-exactly
What does it mean that the address of source and destination can overlap in memcpy function? What is overlap exactly? - Quora
The source and destination overlap if the span of bytes for the destination has any bytes in common with the span of bytes for the source. For memcpy()/memmove(), if you interprete source and dest as pointer-to-T ye, the source occupies [source, ...
🌐
Quora
quora.com › What-happens-when-the-source-and-destination-address-overlaps-in-memcpy-call
What happens when the source and destination address overlaps in memcpy call? - Quora
Answer: The result is formally undefined, and the implementation may generate different results on different compilers, systems, or processors. Generally speaking, you get garbage and destroy your data, although you may luck out and get something ...
Find elsewhere
🌐
Ubuntu
manpages.ubuntu.com › manpages › focal › en › man3 › memcpy.3.html
Ubuntu Manpage: memcpy - copy memory area
For an explanation of the terms used in this section, see attributes(7). ┌──────────────────────────┬─────────┐ │ Interface │ Attribute │ Value │ ├───────────┼───────────────┼─────────┤ │ memcpy() │ Thread safety │ MT-Safe │ └───────────┴───────────────┴─────────┘ · POSIX.1-2001, POSIX.1-2008, C89, C99, SVr4, 4.3BSD. Failure to observe the requirement that the memory areas do not overlap has been the source of significant bugs.
🌐
Cprogramming
cboard.cprogramming.com › c-programming › 158242-memory-overlap-memcpy-function.html
Memory Overlap and memcpy function.
July 21, 2013 - Memory Overlap and memcpy function. ... Hello everybody. ... #include<stdio.h> #include<string.h> int main(void) { char str[20] = "HELLOSIR"; memcpy( str + 2 , str + 1 , 4 ); puts( str ); return 0; } If I have understood well the above code can be a typical example that decribes a memory overlap.
🌐
Rip Tutorial
riptutorial.com › copying overlapping memory
C Language Tutorial => Copying overlapping memory
A wide variety of standard library functions have among their effects copying byte sequences from one memory region to another. Most of these functions have undefined behavior when the source and destination regions overlap. For example, this ... #include <string.h> /* for memcpy() */ char str[19] = "This is an example"; memcpy(str + 7, str, 10);
🌐
TechOnTheNet
techonthenet.com › c_language › standard_library_functions › string_h › memcpy.php
C Language: memcpy function (Copy Memory Block)
In the C Programming Language, the memcpy function copies n characters from the object pointed to by s2 into the object pointed to by s1. It returns a pointer to the destination. The memcpy function may not work if the objects overlap.
🌐
Experts Exchange
experts-exchange.com › questions › 29246258 › What-is-memcpy-in-c.html
Solved: What is memcpy in c? | Experts Exchange
September 8, 2022 - The above "memcpy()" call throws an errors because you are copying 20 bytes, but starting at byte 5 of a 20-byte array - you are writing 5 bytes beyond the end of the array. Using memcpy() with overlapping sections *may* be safe! I believe that some versions check for overlapping source and destination arrays, and make sure that the copy is done in the right direction so that the data is clean.
🌐
Reddit
reddit.com › r/c_programming › how does memmove allow the copying to be done in a non-destructive manner unlike memcpy?
r/C_Programming on Reddit: How does memmove allow the copying to be done in a non-destructive manner unlike memcpy?
May 14, 2023 -

Edit: Thank you so much.

Please help.

I understand that overlapping of src and dest is allowed in memmove but not how.

If I understood correctly, it will copy up or down (depending on whether src is shorter or longer than dst) but why does that matter and how does it prevent undefined behavior?

I've read through all this but I'm still struggling to understand the implementation of memmove. 1, 2, 3, 4, 5.

I tried to test it according to the second top answer from link 1 but there is no undefined behaviour. Can someone show me a way of testing it to see the differences? I have also tried different lengths of both strings but I think I'm not testing it correctly.

Top answer
1 of 3
18

I've done some research on this in the past... on Linux, up until fairly recently, the implementation of memcpy() worked in a way that was similar enough to memmove() that overlapping memory wasn't an issue, and in my experience, other UNIXs were the same. This doesn't change the fact that this is undefined behavior according to the standard, and you are just lucky that on some platforms it sometimes works -- and memmove() is the standard-supported right answer.

However, in 2010, the glibc maintainers rolled out a new, optimized memcpy() that changed the behavior of memcpy() for some Intel core types where the C standard library is compiled to be faster, but no longer works like memmove() [1]. (I seem to recall also that this is new code triggered only for memory segments larger than 80 bytes). Interestingly, this caused things like the Linux version of Adobe's Flash player to break[2], as well as several other open-source packages (back in 2010 when Fedora Linux became the first to adopt the changed memcpy() in glibc).

  • [1] https://sourceware.org/bugzilla/show_bug.cgi?id=12518
  • [2] https://bugzilla.redhat.com/show_bug.cgi?id=638477
2 of 3
14

memcpy() doesn't support overlapping memory. This allows for optimizations that won't work if the buffers do overlap.

There's not much to really look into, however, because C provides an alternative that does support overlapping memory: memmove(). Its usage is identical to memcpy(). You should use it if the regions might overlap, as it accounts for that possibility.

🌐
Reddit
reddit.com › r/c_programming › how does memcpy( ) work in c lang?
r/C_Programming on Reddit: How does memcpy( ) work in C lang?
October 16, 2020 -

Long time ago when i was a wee little lad learning C, before I was learning pointers, I learned how to swap values between two variables ;

uint32_t x=1;
uint32_t y=2;
uint32_t tmp;

tmp = y;
y=x;
x=tmp;

Of-course, with pointers, we can do ;

void xorSwap (int* x, int* y) {
    if (x != y) {
       *x ^= *y;
       *y ^= *x;
       *x ^= *y;
    }
}

Yesterday at work, we write bare metal C for fw i had this uniquely weird issue, we work in RISC V environment,

where i have to use memcpy() something similar to a

memcpy( uint32_t * dest, const uint32_t * source, size_t sz );

and the issue was that, in the linker I had specified maximum buffer size too, so it should've worked.

This below is actual code:

memcpy(sample_waveform, (void *)(0x7C000), sizeof(sample_waveform));

and when i had sample_waveform which was a signed double GLOBAL array of 3K bytes, it won't copy, However it did was able to copy first 500 bytes though when I made the sample_waveform size smaller.

but when I made sample_waveform local on the stack which took a stack space of 3K, I was able to do memcpy( ).

I can't explain why this is so? I didn't want to copy and take/use that much space on the stack.

Has this happened to anyone?

How does memcpy( ) work? Does it copy to temp somewhere and then copy to your destination, or does it copy like that pointer method. How is this different from memmove()?

Thanks!

Top answer
1 of 8
11
memcpy() does not copy data to a temporary location: that's why memmove() and memcpy() are different functions, memmove() copies to a temporary location, memcpy() doesn't. (Well, memcpy() will copy to a register, but that doesn't really count) What compiler and libc are you using? What is the nature of 0x7C000? Is it "real" memory, or is it a mmio device? glibc on desktop will do virtual address magic to delay actually performing a copy, but this doesn't work for mmio devices. This code path should probably be disabled in embedded environments. What is the declaration of sample_waveform? double sample_waveform[384]; is much different from double* sample_waveform; /* remember to 'sample_waveform = malloc(3072);' in init() */ Does it work if you do memcpy(sample_waveform, (void*)0x7C000, sizeof(*sample_waveform) * NUMBER_OF_ELEMENTS);? (where NUMBER_OF_ELEMENTS is 384 for a 3kB array of doubles, obviously) Does the source memory address have limitations about what order you're allowed to read it in? It's not defined whether memcpy() will read front to back, or back to front, or in a seemingly nonsensical order. Does stepping through it in the debugger yield any surprises? If you roll your own memcpy() does it work? Side note: void xorSwap (int* x, int* y) { if (x != y) { *x ^= *y; *y ^= *x; *x ^= *y; } } Don't do that. Don't ever do that. It's measurably slower than doing it the naive way with a "temporary variable" that will be optimized out by the compiler. xor swap is a waste of both time and memory. Your code is bad and you should feel bad. If you use xor swap in production you do not deserve love.
2 of 8
6
sizeof(sample_waveform) returns the size of the first element of the array pointer ( u/OldWolf2 corrected this). So you will be copying the first 8 bytes size of a pointer and that is it. If you know the size of the array (in bytes) use this value instead. EDIT: Ok, I made the assumption that sample_waveform is a pointer and you allocated it by malloc, if the array is static, i.e, know at compile time sizeof(sample_waveform) should give you the array size. EDIT2: Check u/OldWolf2 comment bellow, he got it right.
🌐
Mycal's Lab
blog.mycal.net › when-memcpy-betrays-you-a-lesson-in-overlapping-buffers-and-ancient-toolchains
When memcpy Betrays You: A Lesson in Overlapping Buffers and Ancient Toolchains
July 15, 2025 - Until it doesn’t. Modern implementations of memcpy() are smart — they detect overlap and internally call memmove(), or they implement memory-safe back-to-front copies using SIMD and cache prefetch tricks.
🌐
Cplusplus
cplusplus.com › reference › cstring › memcpy
memcpy
The function does not check for any terminating null character in source - it always copies exactly num bytes. To avoid overflows, the size of the arrays pointed to by both the destination and source parameters, shall be at least num bytes, and should not overlap (for overlapping memory blocks, ...
Top answer
1 of 2
2

I'm trying to reproduce the behaviour of memcpy.

Bug: Wrong return value

When n == 0, memcpy() returns dest. OP's code should perform likewise.

// if (src == NULL || n == 0)
//        return (NULL);
if (src == NULL) // memcpy(..., NULL, ...) is not defined.  Do whatever you want.
  return NULL;  // or maybe `n = 0;`
if (n == 0) 
  return dest;

Bug: Insufficient space

With char buffer[] = "Overlap Test";, ft_memcpy(buffer + 3, buffer, strlen(buffer) + 1); is a problem as buffer + 3 does not have enough room for strlen(buffer) + 1 characters. @chqrlie


How is memcpy.c supposed to react to memory overlap?
Would such a result be expected in case of memory overlap?

Given the 2 restrict in the function signature, using overlapping buffers is undefined behavior (UB). There are no expected results.

void *memcpy(void * restrict s1, const void * restrict s2, size_t n);

Even if OP's ft_memcpy() functioned just like OP's compiler's memcpy() today, it is not certain it will tomorrow or on some other machine. It is UB.

I recommend to not test for equivalent functionality with overlapping buffers - since it is UB.
Notice, that focus on this issue missed proper behavior when n == 0.


Consider instead "How is memcpy.c memmove() supposed to react to memory overlap?"

That is trickier.

Copying takes place as if the n characters from the object pointed to by s2 are first copied into a temporary array of n characters that does not overlap the objects pointed to by s1 and s2, and then the n characters from the temporary array are copied into the object pointed to by s1.
C23dr § 7.26.2.3 2

OP's code needs changes to meet that. To do well is a challenge as the usual approach is to compare addresses. Depending on which is greater, copy from the beginning or end of the source buffer. Yet for user code, there is no defined way to compare arbitrary addresses for order. Various tricks abound that usually work.

The below does not have UB, yet may not compile nor function exactly like memmove() on all machines.

#include <stdlib.h>
#include <stdint.h>

void *ft_memmove(void *dst, const void *src, size_t n) {
  // Not needed as passing `NULL` for either pointer parameter is UB in memmove().
  if (dst == NULL || src == NULL) {
    n = 0;
  }
  // Weakness: uintptr_t is an optional type.
  uintptr_t d = (uintptr_t) dst;
  uintptr_t s = (uintptr_t) src;
  // Weakness: `d < s` is not a defined order compare of the pointers.
  if (d < s) {
    for (size_t i = 0; i < n; i++) {
      ((char*)dst)[i] = ((const char*)src)[i];
    }
  } else {
    while (n > 0) {
      n--;
      ((char*)dst)[n] = ((const char*)src)[n];
    }
  }
  return dst;
}
2 of 2
2

I'm trying to reproduce the behaviour of memcpy. However when I try it with overlapping memory tests, instead of a trace trap I receive a different result.

In this case (by the C standard) the result of memcpy is undefined.

Would such a result be expected in case of memory overlap?

No, as it is UNDEFINED and you should have not been expecting anything.

I did put the restrict keywords in the function declaration, and I don't understand why the compiler wouldn't put it as a trace trap in this case.

Because restrict does not work this way. It does not add any checks. It is your promise that your function will behave a certain way, allowing compiler to do more aggressive optimizations.


Nonsense UB deliberations:

Also, many x86 glibc memcpy implementations do not use single-byte copy, so your (naive) function will not be able to reproduce their behaviour.