Fix memmove and memcpy
authorJon Medhurst <tixy@linaro.org>
Wed, 15 Jan 2014 18:22:34 +0000 (18:22 +0000)
committerDan Handley <dan.handley@arm.com>
Thu, 30 Jan 2014 17:55:31 +0000 (17:55 +0000)
memmove needs to allow for overlapping memory regions and, together
with memcpy, should return the input destination pointer, not the
address after the end of the copied data.

fixes ARM-software/tf-issues#18

Signed-off-by: Jon Medhurst <tixy@linaro.org>
lib/stdlib/mem.c

index 145d651ca1cf2be335eda7bb49a7c0324d130392..f1f335a6c1f5fd3b8613a884d29bf128d74cc512 100644 (file)
@@ -63,29 +63,47 @@ int memcmp(const void *s1, const void *s2, size_t len)
        return 0;
 }
 
-
 /*
- * Move @len bytes from @src to @dst
+ * Copy @len bytes from @src to @dst
  */
-void *memmove(void *dst, const void *src, size_t len)
+void *memcpy(void *dst, const void *src, size_t len)
 {
        const char *s = src;
        char *d = dst;
 
        while (len--)
                *d++ = *s++;
-       return d;
+
+       return dst;
 }
 
 /*
- * Copy @len bytes from @src to @dst
+ * Move @len bytes from @src to @dst
  */
-void *memcpy(void *dst, const void *src, size_t len)
+void *memmove(void *dst, const void *src, size_t len)
 {
-       return memmove(dst, src, len);
+       /*
+        * The following test makes use of unsigned arithmetic overflow to
+        * more efficiently test the condition !(src <= dst && dst < str+len).
+        * It also avoids the situation where the more explicit test would give
+        * incorrect results were the calculation str+len to overflow (though
+        * that issue is probably moot as such usage is probably undefined
+        * behaviour and a bug anyway.
+        */
+       if ((size_t)dst - (size_t)src >= len) {
+               /* destination not in source data, so can safely use memcpy */
+               return memcpy(dst, src, len);
+       } else {
+               /* copy backwards... */
+               const char *end = dst;
+               const char *s = (const char *)src + len;
+               char *d = (char *)dst + len;
+               while (d != end)
+                       *--d = *--s;
+       }
+       return dst;
 }
 
-
 /*
  * Scan @len bytes of @src for value @c
  */