msvcrt: Added memmove_s and memcpy_s implementation.
diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec
index d7d0395..7d170a9 100644
--- a/dlls/msvcr80/msvcr80.spec
+++ b/dlls/msvcr80/msvcr80.spec
@@ -1335,9 +1335,9 @@
@ cdecl memchr(ptr long long) msvcrt.memchr
@ cdecl memcmp(ptr ptr long) msvcrt.memcmp
@ cdecl memcpy(ptr ptr long) msvcrt.memcpy
-@ stub memcpy_s
+@ cdecl memcpy_s(ptr long ptr long) msvcrt.memcpy_s
@ cdecl memmove(ptr ptr long) msvcrt.memmove
-@ stub memmove_s
+@ cdecl memmove_s(ptr long ptr long) msvcrt.memmove_s
@ cdecl memset(ptr long long) msvcrt.memset
@ cdecl modf(double ptr) msvcrt.modf
@ cdecl perror(str) msvcrt.perror
diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec
index 9bfa23d..3eae9a0 100644
--- a/dlls/msvcr90/msvcr90.spec
+++ b/dlls/msvcr90/msvcr90.spec
@@ -1319,9 +1319,9 @@
@ cdecl memchr(ptr long long) msvcrt.memchr
@ cdecl memcmp(ptr ptr long) msvcrt.memcmp
@ cdecl memcpy(ptr ptr long) msvcrt.memcpy
-@ stub memcpy_s
+@ cdecl memcpy_s(ptr long ptr long) msvcrt.memcpy_s
@ cdecl memmove(ptr ptr long) msvcrt.memmove
-@ stub memmove_s
+@ cdecl memmove_s(ptr long ptr long) msvcrt.memmove_s
@ cdecl memset(ptr long long) msvcrt.memset
@ cdecl modf(double ptr) msvcrt.modf
@ cdecl perror(str) msvcrt.perror
diff --git a/dlls/msvcrt/heap.c b/dlls/msvcrt/heap.c
index e40a0c9..7adaf90 100644
--- a/dlls/msvcrt/heap.c
+++ b/dlls/msvcrt/heap.c
@@ -511,3 +511,32 @@
TRACE("(%p, %lu, %lu)\n", memblock, size, alignment);
return _aligned_offset_realloc(memblock, size, alignment, 0);
}
+
+/*********************************************************************
+ * memmove_s (MSVCRT.@)
+ */
+int CDECL memmove_s(void *dest, MSVCRT_size_t numberOfElements, const void *src, MSVCRT_size_t count)
+{
+ TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count);
+
+ if(!count)
+ return 0;
+
+ if(!dest || !src) {
+ if(dest)
+ memset(dest, 0, numberOfElements);
+
+ *MSVCRT__errno() = MSVCRT_EINVAL;
+ return MSVCRT_EINVAL;
+ }
+
+ if(count > numberOfElements) {
+ memset(dest, 0, numberOfElements);
+
+ *MSVCRT__errno() = MSVCRT_ERANGE;
+ return MSVCRT_ERANGE;
+ }
+
+ memmove(dest, src, count);
+ return 0;
+}
diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec
index eac8f46..08b330f 100644
--- a/dlls/msvcrt/msvcrt.spec
+++ b/dlls/msvcrt/msvcrt.spec
@@ -1267,9 +1267,9 @@
@ cdecl memchr(ptr long long) ntdll.memchr
@ cdecl memcmp(ptr ptr long) ntdll.memcmp
@ cdecl memcpy(ptr ptr long) ntdll.memcpy
-# stub memcpy_s
+@ cdecl memcpy_s(ptr long ptr long) memmove_s
@ cdecl memmove(ptr ptr long) ntdll.memmove
-# stub memmove_s
+@ cdecl memmove_s(ptr long ptr long)
@ cdecl memset(ptr long long) ntdll.memset
@ cdecl mktime(ptr) MSVCRT_mktime
@ cdecl modf(double ptr) MSVCRT_modf
diff --git a/dlls/msvcrt/tests/misc.c b/dlls/msvcrt/tests/misc.c
index 1f069fa..d8b1b88 100644
--- a/dlls/msvcrt/tests/misc.c
+++ b/dlls/msvcrt/tests/misc.c
@@ -20,14 +20,17 @@
#include "wine/test.h"
#include <errno.h>
+#include "msvcrt.h"
static int (__cdecl *prand_s)(unsigned int *);
+static int (__cdecl *memcpy_s)(void *, MSVCRT_size_t, void*, MSVCRT_size_t);
static void init(void)
{
HMODULE hmod = GetModuleHandleA("msvcrt.dll");
prand_s = (void *)GetProcAddress(hmod, "rand_s");
+ memcpy_s = (void*)GetProcAddress(hmod, "memcpy_s");
}
static void test_rand_s(void)
@@ -50,9 +53,61 @@
ok(ret == 0, "Expected rand_s to return 0, got %d\n", ret);
}
+static void test_memcpy_s(void)
+{
+ static char data[] = "data\0to\0be\0copied";
+ static char dest[32];
+ int ret;
+
+ if(!memcpy_s)
+ {
+ win_skip("memcpy_s in not available\n");
+ return;
+ }
+
+ errno = 0xdeadbeef;
+ ret = memcpy_s(NULL, 0, NULL, 0);
+ ok(ret == 0, "ret = %x\n", ret);
+ ok(errno == 0xdeadbeef, "errno = %x\n", errno);
+
+ errno = 0xdeadbeef;
+ dest[0] = 'x';
+ ret = memcpy_s(dest, 10, NULL, 0);
+ ok(ret == 0, "ret = %x\n", ret);
+ ok(errno == 0xdeadbeef, "errno = %x\n", errno);
+ ok(dest[0] == 'x', "dest[0] != \'x\'\n");
+
+ errno = 0xdeadbeef;
+ ret = memcpy_s(NULL, 10, data, 10);
+ ok(ret == EINVAL, "ret = %x\n", ret);
+ ok(errno == EINVAL, "errno = %x\n", errno);
+
+ errno = 0xdeadbeef;
+ dest[7] = 'x';
+ ret = memcpy_s(dest, 10, data, 5);
+ ok(ret == 0, "ret = %x\n", ret);
+ ok(errno == 0xdeadbeef, "errno = %x\n", errno);
+ ok(memcmp(dest, data, 10), "All data copied\n");
+ ok(!memcmp(dest, data, 5), "First five bytes are different\n");
+
+ errno = 0xdeadbeef;
+ ret = memcpy_s(data, 10, data, 10);
+ ok(ret == 0, "ret = %x\n", ret);
+ ok(errno == 0xdeadbeef, "errno = %x\n", errno);
+ ok(!memcmp(dest, data, 5), "data was destroyed during overwritting\n");
+
+ errno = 0xdeadbeef;
+ dest[0] = 'x';
+ ret = memcpy_s(dest, 5, data, 10);
+ ok(ret == ERANGE, "ret = %x\n", ret);
+ ok(errno == ERANGE, "errno = %x\n", errno);
+ ok(dest[0] == '\0', "dest[0] != \'\\0\'\n");
+}
+
START_TEST(misc)
{
init();
test_rand_s();
+ test_memcpy_s();
}