Why is Linux memmove() implemented the way it is?

MarcDefiant picture MarcDefiant · Nov 12, 2012 · Viewed 14.3k times · Source

From the Linux manpage for memmove(3)

The memmove() function copies n bytes from memory area src to memory area dest. The memory areas may overlap: copying takes place as though the bytes in src are first copied into a temporary array that does not overlap src or dest, and the bytes are then copied from the temporary array to dest.

Instead of allocating a temporary array and copy the values twice we could just do the following:

void *my_memmove(void *dest, const void *src, size_t n) {
  signed char operation;
  size_t end;
  size_t current;

  if(dest != src) {
    if(dest < src) {
      operation = 1;
      current = 0;
      end = n;
    } else {
      operation = -1;
      current = n - 1;
      end = -1;
    }

    for( ; current != end; current += operation) {
      *(((unsigned char*)dest) + current) = *(((unsigned char*)src) + current);
    }
  }
  return dest;
}

In this implementation we simply take care of the position where we begin to copy.

Is there a drawback in my implementation?

Note: I won't actually use my implementation. I'm just curious.

Answer

cegfault picture cegfault · Nov 12, 2012

You can look at some source code for memmove here, here, here, and here.

What you'll notice is that they don't actually make a temporary array. The man pages are written to help you understand what it is doing logically, not actually. Hence, they say "as though".

What memmove() actually does is copy the bytes from src to dest, and it copies forward if dest < src (which is essentially the same thing as memcpy), and backwards otherwise.

The difference between memcpy and memmove is that memcpy blindly copies forward - which is why dest and src should not overlap. But memmove takes the precaution of ensuring the overlap will not screw up the end result.