[PATCH] [Msvcrt]: now using macro for parameters validation itoa_s (and updated the tests as well)

Eric Pouech eric.pouech at orange.fr
Mon Nov 8 15:41:17 CST 2010


msvcr90 doesn't set msvcrt's errno in case of error, while msvcrt does
Hence the wrappers inside msvcr90 around _itoa_s and _itow_s calls.

A+
---

 dlls/msvcr80/msvcr80.spec    |    4 +
 dlls/msvcr90/msvcr90.c       |   44 ++++++++++++++++
 dlls/msvcr90/msvcr90.spec    |    4 +
 dlls/msvcr90/tests/msvcr90.c |  115 ++++++++++++++++++++++++++++++++++++++++++
 dlls/msvcrt/string.c         |   10 ++--
 dlls/msvcrt/tests/string.c   |   16 ++++++
 6 files changed, 185 insertions(+), 8 deletions(-)


diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec
index f939329..25000b9 100644
--- a/dlls/msvcr80/msvcr80.spec
+++ b/dlls/msvcr80/msvcr80.spec
@@ -680,9 +680,9 @@
 @ stub _iswxdigit_l
 @ stub _isxdigit_l
 @ cdecl _itoa(long ptr long) msvcrt._itoa
-@ cdecl _itoa_s(long ptr long long) msvcrt._itoa_s
+@ cdecl _itoa_s(long ptr long long) MSVCR80__itoa_s
 @ cdecl _itow(long ptr long) msvcrt._itow
-@ cdecl _itow_s(long ptr long long) msvcrt._itow_s
+@ cdecl _itow_s(long ptr long long) MSVCR80__itow_s
 @ cdecl _j0(double) msvcrt._j0
 @ cdecl _j1(double) msvcrt._j1
 @ cdecl _jn(long double) msvcrt._jn
diff --git a/dlls/msvcr90/msvcr90.c b/dlls/msvcr90/msvcr90.c
index 2fff15a..eff82ef 100644
--- a/dlls/msvcr90/msvcr90.c
+++ b/dlls/msvcr90/msvcr90.c
@@ -218,3 +218,47 @@ int CDECL _wstat64i32(const wchar_t *path, struct _stat64i32 *buf)
         msvcrt_stat64_to_stat64i32(&buf64, buf);
     return ret;
 }
+
+/*********************************************************************
+ *  _itoa_s (MSVCR90.@)
+ */
+int CDECL MSVCR90__itoa_s(int value, char *str, size_t size, int radix)
+{
+    static errno_t (__cdecl *p_itoa_s)(int,char*,size_t,int) = NULL;
+    int ret, perrno;
+
+    if (!p_itoa_s)
+    {
+        HANDLE hMsvcrt;
+        if (!(hMsvcrt = GetModuleHandleA("msvcrt.dll")))
+            hMsvcrt = GetModuleHandleA("msvcrtd.dll");
+        if (!(p_itoa_s = (void *)GetProcAddress(hMsvcrt, "_itoa_s")))
+            return ENOMEM;
+    }
+    _get_errno(&perrno);
+    if ((ret = p_itoa_s(value, str, size, radix)) != 0)
+        _set_errno(perrno);
+    return ret;
+}
+
+/*********************************************************************
+ *  _itow_s (MSVCR90.@)
+ */
+int CDECL MSVCR90__itow_s(int value, wchar_t *str, size_t size, int radix)
+{
+    static errno_t (__cdecl *p_itoa_s)(int,wchar_t*,size_t,int) = NULL;
+    int ret, perrno;
+
+    if (!p_itoa_s)
+    {
+        HANDLE hMsvcrt;
+        if (!(hMsvcrt = GetModuleHandleA("msvcrt.dll")))
+            hMsvcrt = GetModuleHandleA("msvcrtd.dll");
+        if (!(p_itoa_s = (void *)GetProcAddress(hMsvcrt, "_itoa_s")))
+            return ENOMEM;
+    }
+    perrno = _get_errno(&perrno);
+    if ((ret = p_itoa_s(value, str, size, radix)) != 0)
+        _set_errno(perrno);
+    return ret;
+}
diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec
index 99e81fd..b43a57d 100644
--- a/dlls/msvcr90/msvcr90.spec
+++ b/dlls/msvcr90/msvcr90.spec
@@ -668,9 +668,9 @@
 @ stub _iswxdigit_l
 @ stub _isxdigit_l
 @ cdecl _itoa(long ptr long) msvcrt._itoa
-@ cdecl _itoa_s(long ptr long long) msvcrt._itoa_s
+@ cdecl _itoa_s(long ptr long long) MSVCR90__itoa_s
 @ cdecl _itow(long ptr long) msvcrt._itow
-@ cdecl _itow_s(long ptr long long) msvcrt._itow_s
+@ cdecl _itow_s(long ptr long long) MSVCR90__itow_s
 @ cdecl _j0(double) msvcrt._j0
 @ cdecl _j1(double) msvcrt._j1
 @ cdecl _jn(long double) msvcrt._jn
diff --git a/dlls/msvcr90/tests/msvcr90.c b/dlls/msvcr90/tests/msvcr90.c
index 5a60871..776d2d8 100644
--- a/dlls/msvcr90/tests/msvcr90.c
+++ b/dlls/msvcr90/tests/msvcr90.c
@@ -63,6 +63,7 @@ static char **p_sys_errlist;
 static char** (__cdecl *p__sys_errlist)(void);
 static __int64 (__cdecl *p_strtoi64)(const char *, char **, int);
 static unsigned __int64 (__cdecl *p_strtoui64)(const char *, char **, int);
+static errno_t (__cdecl *p_itoa_s)(int,char*,size_t,int);
 
 static void* (WINAPI *pEncodePointer)(void *);
 
@@ -282,6 +283,118 @@ static void test__strtoi64(void)
     ok(errno == 0xdeadbeef, "errno = %x\n", errno);
 }
 
+static void test__itoa_s(void)
+{
+    errno_t ret;
+    char buffer[33];
+
+    if (!p_itoa_s)
+    {
+        win_skip("Skipping _itoa_s tests\n");
+        return;
+    }
+
+    if(!p_set_invalid_parameter_handler) {
+        win_skip("_set_invalid_parameter_handler not found\n");
+        return;
+    }
+
+    errno = EBADF;
+    SET_EXPECT(invalid_parameter_handler);
+    ret = p_itoa_s(0, NULL, 0, 0);
+    ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
+    ok(errno == EBADF, "Expected errno to be unchanged (EBADF), got %d\n", errno);
+    CHECK_CALLED(invalid_parameter_handler);
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    SET_EXPECT(invalid_parameter_handler);
+    ret = p_itoa_s(0, buffer, 0, 0);
+    ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
+    ok(errno == EBADF, "Expected errno to be unchanged (EBADF), got %d\n", errno);
+    ok(buffer[0] == 'X', "Expected the output buffer to be untouched\n");
+    CHECK_CALLED(invalid_parameter_handler);
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    SET_EXPECT(invalid_parameter_handler);
+    ret = p_itoa_s(0, buffer, sizeof(buffer), 0);
+    ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
+    ok(errno == EBADF, "Expected errno to be unchanged (EBADF), got %d\n", errno);
+    ok(buffer[0] == '\0', "Expected the output buffer to be null terminated\n");
+    CHECK_CALLED(invalid_parameter_handler);
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    SET_EXPECT(invalid_parameter_handler);
+    ret = p_itoa_s(0, buffer, sizeof(buffer), 64);
+    ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
+    ok(errno == EBADF, "Expected errno to be unchanged (EBADF), got %d\n", errno);
+    ok(buffer[0] == '\0', "Expected the output buffer to be null terminated\n");
+    CHECK_CALLED(invalid_parameter_handler);
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    SET_EXPECT(invalid_parameter_handler);
+    ret = p_itoa_s(12345678, buffer, 4, 10);
+    ok(ret == ERANGE, "Expected _itoa_s to return ERANGE, got %d\n", ret);
+    ok(errno == EBADF, "Expected errno to be unchanged (EBADF), got %d\n", errno);
+    ok(!memcmp(buffer, "\000765", 4),
+       "Expected the output buffer to be null terminated with truncated output\n");
+    CHECK_CALLED(invalid_parameter_handler);
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    SET_EXPECT(invalid_parameter_handler);
+    ret = p_itoa_s(12345678, buffer, 8, 10);
+    ok(ret == ERANGE, "Expected _itoa_s to return ERANGE, got %d\n", ret);
+    ok(errno == EBADF, "Expected errno to be unchanged (EBADF), got %d\n", errno);
+    ok(!memcmp(buffer, "\0007654321", 8),
+       "Expected the output buffer to be null terminated with truncated output\n");
+    CHECK_CALLED(invalid_parameter_handler);
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    SET_EXPECT(invalid_parameter_handler);
+    ret = p_itoa_s(-12345678, buffer, 9, 10);
+    ok(ret == ERANGE, "Expected _itoa_s to return ERANGE, got %d\n", ret);
+    ok(errno == EBADF, "Expected errno to be unchanged (EBADF), got %d\n", errno);
+    ok(!memcmp(buffer, "\00087654321", 9),
+       "Expected the output buffer to be null terminated with truncated output\n");
+    CHECK_CALLED(invalid_parameter_handler);
+
+    ret = p_itoa_s(12345678, buffer, 9, 10);
+    ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
+    ok(!strcmp(buffer, "12345678"),
+       "Expected output buffer string to be \"12345678\", got \"%s\"\n",
+       buffer);
+
+    ret = p_itoa_s(43690, buffer, sizeof(buffer), 2);
+    ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
+    ok(!strcmp(buffer, "1010101010101010"),
+       "Expected output buffer string to be \"1010101010101010\", got \"%s\"\n",
+       buffer);
+
+    ret = p_itoa_s(1092009, buffer, sizeof(buffer), 36);
+    ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
+    ok(!strcmp(buffer, "nell"),
+       "Expected output buffer string to be \"nell\", got \"%s\"\n",
+       buffer);
+
+    ret = p_itoa_s(5704, buffer, sizeof(buffer), 18);
+    ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
+    ok(!strcmp(buffer, "hag"),
+       "Expected output buffer string to be \"hag\", got \"%s\"\n",
+       buffer);
+
+    ret = p_itoa_s(-12345678, buffer, sizeof(buffer), 10);
+    ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
+    ok(!strcmp(buffer, "-12345678"),
+       "Expected output buffer string to be \"-12345678\", got \"%s\"\n",
+       buffer);
+}
+
+
 /* ########## */
 
 START_TEST(msvcr90)
@@ -311,6 +424,7 @@ START_TEST(msvcr90)
     p__sys_errlist = (void *) GetProcAddress(hcrt, "__sys_errlist");
     p_strtoi64 = (void *) GetProcAddress(hcrt, "_strtoi64");
     p_strtoui64 = (void *) GetProcAddress(hcrt, "_strtoui64");
+    p_itoa_s = (void *)GetProcAddress(hcrt, "_itoa_s");
 
     hkernel32 = GetModuleHandleA("kernel32.dll");
     pEncodePointer = (void *) GetProcAddress(hkernel32, "EncodePointer");
@@ -319,4 +433,5 @@ START_TEST(msvcr90)
     test__encode_pointer();
     test_error_messages();
     test__strtoi64();
+    test__itoa_s();
 }
diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c
index 3c4b53c..ea3ca1b 100644
--- a/dlls/msvcrt/string.c
+++ b/dlls/msvcrt/string.c
@@ -680,7 +680,8 @@ int CDECL _itoa_s(int value, char *str, MSVCRT_size_t size, int radix)
     char buffer[33], *pos;
     size_t len;
 
-    if (!str || !size || radix < 2 || radix > 36)
+    if (!MSVCRT_CHECK_PMT(str != NULL) || !MSVCRT_CHECK_PMT(size > 0) ||
+        !MSVCRT_CHECK_PMT(radix >= 2) || !MSVCRT_CHECK_PMT(radix <= 36))
     {
         if (str && size)
             str[0] = '\0';
@@ -737,6 +738,7 @@ int CDECL _itoa_s(int value, char *str, MSVCRT_size_t size, int radix)
             *p++ = *pos--;
 
         str[0] = '\0';
+        MSVCRT_INVALID_PMT("str[size] is too small");
         *MSVCRT__errno() = MSVCRT_ERANGE;
         return MSVCRT_ERANGE;
     }
@@ -831,8 +833,8 @@ int CDECL MSVCRT__ui64toa_s(unsigned __int64 value, char *str,
     char buffer[65], *pos;
     int digit;
 
-    if(!str || radix<2 || radix>36) {
-        MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
+    if (!MSVCRT_CHECK_PMT(str != NULL) || !MSVCRT_CHECK_PMT(size > 0) ||
+        !MSVCRT_CHECK_PMT(radix>=2) || !MSVCRT_CHECK_PMT(radix<=36)) {
         *MSVCRT__errno() = MSVCRT_EINVAL;
         return MSVCRT_EINVAL;
     }
@@ -851,7 +853,7 @@ int CDECL MSVCRT__ui64toa_s(unsigned __int64 value, char *str,
     }while(value != 0);
 
     if(buffer-pos+65 > size) {
-        MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
+        MSVCRT_INVALID_PMT("str[size] is too small");
         *MSVCRT__errno() = MSVCRT_EINVAL;
         return MSVCRT_EINVAL;
     }
diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c
index ab647db..aa57b31 100644
--- a/dlls/msvcrt/tests/string.c
+++ b/dlls/msvcrt/tests/string.c
@@ -43,6 +43,13 @@ static char *buf_to_string(const unsigned char *bin, int len, int nr)
     return buf[nr];
 }
 
+static void __cdecl test_invalid_parameter_handler(const wchar_t *expression,
+        const wchar_t *function, const wchar_t *file,
+        unsigned line, uintptr_t arg)
+{
+    /* we just ignore handler calls */
+}
+
 #define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret, #expr " expected " format " got " format "\n", value, ret); }
 #define expect_bin(buf, value, len) { ok(memcmp((buf), value, len) == 0, "Binary buffer mismatch - expected %s, got %s\n", buf_to_string((unsigned char *)value, len, 1), buf_to_string((buf), len, 0)); }
 
@@ -66,6 +73,7 @@ static errno_t (__cdecl *p_strlwr_s)(char*,size_t);
 static errno_t (__cdecl *p_ultoa_s)(__msvcrt_ulong,char*,size_t,int);
 static int *p__mb_cur_max;
 static unsigned char *p_mbctype;
+static _invalid_parameter_handler (__cdecl *p_set_invalid_parameter_handler)(_invalid_parameter_handler);
 
 #define SETNOFAIL(x,y) x = (void*)GetProcAddress(hMsvcrt,y)
 #define SET(x,y) SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y)
@@ -1293,6 +1301,10 @@ static void test__itoa_s(void)
         return;
     }
 
+    if (p_set_invalid_parameter_handler)
+        ok(p_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL,
+                "Invalid parameter handler was already set\n");
+
     errno = EBADF;
     ret = p_itoa_s(0, NULL, 0, 0);
     ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
@@ -1372,6 +1384,9 @@ static void test__itoa_s(void)
     ok(!strcmp(buffer, "-12345678"),
        "Expected output buffer string to be \"-12345678\", got \"%s\"\n",
        buffer);
+    if (p_set_invalid_parameter_handler)
+        ok(p_set_invalid_parameter_handler(NULL) == test_invalid_parameter_handler,
+                "Cannot reset invalid parameter handler\n");
 }
 
 static void test__strlwr_s(void)
@@ -1705,6 +1720,7 @@ START_TEST(string)
     p_itoa_s = (void *)GetProcAddress(hMsvcrt, "_itoa_s");
     p_strlwr_s = (void *)GetProcAddress(hMsvcrt, "_strlwr_s");
     p_ultoa_s = (void *)GetProcAddress(hMsvcrt, "_ultoa_s");
+    p_set_invalid_parameter_handler = (void *) GetProcAddress(hMsvcrt, "_set_invalid_parameter_handler");
 
     /* MSVCRT memcpy behaves like memmove for overlapping moves,
        MFC42 CString::Insert seems to rely on that behaviour */






More information about the wine-patches mailing list