[PATCH 01/14] [Msvcrt]: now using macro for parameters validation itoa_s (and updated the tests as well)
Eric Pouech
eric.pouech at orange.fr
Tue Nov 2 16:02:41 CDT 2010
A+
---
dlls/msvcrt/string.c | 10 ++++--
dlls/msvcrt/tests/string.c | 68 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 74 insertions(+), 4 deletions(-)
diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c
index 6b3725f..9f4d6a6 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;
}
@@ -754,8 +756,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;
}
@@ -774,7 +776,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..d20257d 100644
--- a/dlls/msvcrt/tests/string.c
+++ b/dlls/msvcrt/tests/string.c
@@ -43,6 +43,51 @@ static char *buf_to_string(const unsigned char *bin, int len, int nr)
return buf[nr];
}
+#define DEFINE_EXPECT(func) \
+ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
+
+#define SET_EXPECT(func) \
+ expect_ ## func = TRUE
+
+#define CHECK_EXPECT2(func) \
+ do { \
+ ok(expect_ ##func, "unexpected call " #func "\n"); \
+ called_ ## func = TRUE; \
+ } while(0)
+
+#define CHECK_EXPECT(func) \
+ do { \
+ CHECK_EXPECT2(func); \
+ expect_ ## func = FALSE; \
+ } while(0)
+
+/* As of today, native and builtin msvcr80, msvcr90, msvcr100 raise an exception on CRT
+ * parameter checking on "secure"
+ * As Wine forwards most of the APIs of those msvcrNN DLLs to msvcrt, builtin msvcrt does
+ * raise an exception on those cases
+ * Testing shows that native msvcrt doesn't
+ * So we make this test always succeed under Windows
+ */
+#define CHECK_CALLED(func) \
+ do { \
+ ok(called_ ## func || broken(TRUE), "expected " #func "\n"); \
+ expect_ ## func = called_ ## func = FALSE; \
+ } while(0)
+
+DEFINE_EXPECT(invalid_parameter_handler);
+
+static void __cdecl test_invalid_parameter_handler(const wchar_t *expression,
+ const wchar_t *function, const wchar_t *file,
+ unsigned line, uintptr_t arg)
+{
+ CHECK_EXPECT(invalid_parameter_handler);
+ ok(expression == NULL, "expression is not NULL\n");
+ ok(function == NULL, "function is not NULL\n");
+ ok(file == NULL, "file is not NULL\n");
+ ok(line == 0, "line = %u\n", line);
+ ok(arg == 0, "arg = %lx\n", (UINT_PTR)arg);
+}
+
#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 +111,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,55 +1339,73 @@ 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;
+ 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 == EINVAL, "Expected errno to be EINVAL, 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 == EINVAL, "Expected errno to be EINVAL, 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 == EINVAL, "Expected errno to be EINVAL, 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 == EINVAL, "Expected errno to be EINVAL, 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 == ERANGE, "Expected errno to be ERANGE, 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 == ERANGE, "Expected errno to be ERANGE, 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 == ERANGE, "Expected errno to be ERANGE, 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);
@@ -1372,6 +1436,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 +1772,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