ucrtbase._mbsncpy_s is used by Marvel vs Capcom when trying to create multiplayer lobby.
The functions are also present in msvcrt (unlike msvcr70, msvcr71) where I didn't add it because it behaves differently: there is at least one weirdness when it doubles the number of characters to copy ('n' parameter, not buffer size). I suppose we don't need to explore and deal with this specific until something needs those functions from msvcrt.
From: Paul Gofman pgofman@codeweavers.com
--- dlls/msvcr100/msvcr100.spec | 4 +- dlls/msvcr110/msvcr110.spec | 4 +- dlls/msvcr120/msvcr120.spec | 4 +- dlls/msvcr80/msvcr80.spec | 4 +- dlls/msvcr80/tests/msvcr80.c | 133 ++++++++++++++++++++++++++++++++++- dlls/msvcr90/msvcr90.spec | 4 +- dlls/msvcrt/mbcs.c | 64 +++++++++++++++++ dlls/ucrtbase/tests/string.c | 85 ++++++++++++++++++++++ dlls/ucrtbase/ucrtbase.spec | 8 +-- include/msvcrt/mbstring.h | 2 + 10 files changed, 297 insertions(+), 15 deletions(-)
diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec index 68e502af597..7e6397051e9 100644 --- a/dlls/msvcr100/msvcr100.spec +++ b/dlls/msvcr100/msvcr100.spec @@ -1157,8 +1157,8 @@ @ stub _mbsncoll_l @ cdecl _mbsncpy(ptr str long) @ cdecl _mbsncpy_l(ptr str long ptr) -@ stub _mbsncpy_s -@ stub _mbsncpy_s_l +@ cdecl _mbsncpy_s(ptr long str long) +@ cdecl _mbsncpy_s_l(ptr long str long ptr) @ cdecl _mbsnextc(str) @ cdecl _mbsnextc_l(str ptr) @ cdecl _mbsnicmp(str str long) diff --git a/dlls/msvcr110/msvcr110.spec b/dlls/msvcr110/msvcr110.spec index 560002e59ed..010d222d665 100644 --- a/dlls/msvcr110/msvcr110.spec +++ b/dlls/msvcr110/msvcr110.spec @@ -1514,8 +1514,8 @@ @ stub _mbsncoll_l @ cdecl _mbsncpy(ptr str long) @ cdecl _mbsncpy_l(ptr str long ptr) -@ stub _mbsncpy_s -@ stub _mbsncpy_s_l +@ cdecl _mbsncpy_s(ptr long str long) +@ cdecl _mbsncpy_s_l(ptr long str long ptr) @ cdecl _mbsnextc(str) @ cdecl _mbsnextc_l(str ptr) @ cdecl _mbsnicmp(str str long) diff --git a/dlls/msvcr120/msvcr120.spec b/dlls/msvcr120/msvcr120.spec index 46715817932..caddf750038 100644 --- a/dlls/msvcr120/msvcr120.spec +++ b/dlls/msvcr120/msvcr120.spec @@ -1525,8 +1525,8 @@ @ stub _mbsncoll_l @ cdecl _mbsncpy(ptr str long) @ cdecl _mbsncpy_l(ptr str long ptr) -@ stub _mbsncpy_s -@ stub _mbsncpy_s_l +@ cdecl _mbsncpy_s(ptr long str long) +@ cdecl _mbsncpy_s_l(ptr long str long ptr) @ cdecl _mbsnextc(str) @ cdecl _mbsnextc_l(str ptr) @ cdecl _mbsnicmp(str str long) diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec index 6cce6ee22ee..b4548945236 100644 --- a/dlls/msvcr80/msvcr80.spec +++ b/dlls/msvcr80/msvcr80.spec @@ -829,8 +829,8 @@ @ stub _mbsncoll_l @ cdecl _mbsncpy(ptr str long) @ cdecl _mbsncpy_l(ptr str long ptr) -@ stub _mbsncpy_s -@ stub _mbsncpy_s_l +@ cdecl _mbsncpy_s(ptr long str long) +@ cdecl _mbsncpy_s_l(ptr long str long ptr) @ cdecl _mbsnextc(str) @ cdecl _mbsnextc_l(str ptr) @ cdecl _mbsnicmp(str str long) diff --git a/dlls/msvcr80/tests/msvcr80.c b/dlls/msvcr80/tests/msvcr80.c index fa04b024031..82379e1246f 100644 --- a/dlls/msvcr80/tests/msvcr80.c +++ b/dlls/msvcr80/tests/msvcr80.c @@ -39,6 +39,44 @@
#define MSVCRT_FD_BLOCK_SIZE 32
+#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) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "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 = %Ix\n", arg); +} + typedef struct { HANDLE handle; @@ -57,6 +95,7 @@ typedef struct
static ioinfo **__pioinfo;
+static _invalid_parameter_handler (__cdecl *p__set_invalid_parameter_handler)(_invalid_parameter_handler); static int (WINAPIV *p__open)(const char *, int, ...); static int (__cdecl *p__close)(int); static intptr_t (__cdecl *p__get_osfhandle)(int); @@ -64,6 +103,8 @@ static int (__cdecl *p_strcmp)(const char *, const char *); static int (__cdecl *p_strncmp)(const char *, const char *, size_t); static int (__cdecl *p_dupenv_s)(char **, size_t *, const char *); static int (__cdecl *p_wdupenv_s)(wchar_t **, size_t *, const wchar_t *); +static errno_t (__cdecl *p__mbsncpy_s)(unsigned char*,size_t,const unsigned char*,size_t); +
#define SETNOFAIL(x,y) x = (void*)GetProcAddress(hcrt,y) #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0) @@ -78,6 +119,8 @@ static BOOL init(void) return FALSE; }
+ SET(p__set_invalid_parameter_handler, "_set_invalid_parameter_handler"); + SET(__pioinfo, "__pioinfo"); SET(p__open,"_open"); SET(p__close,"_close"); @@ -87,7 +130,7 @@ static BOOL init(void) SET(p_strncmp, "strncmp"); SET(p_dupenv_s, "_dupenv_s"); SET(p_wdupenv_s, "_wdupenv_s"); - + SET(p__mbsncpy_s, "_mbsncpy_s"); return TRUE; }
@@ -216,13 +259,101 @@ static void test_wdupenv_s(void) ok( !tmp, "_wdupenv_s returned pointer is %p\n", tmp ); }
+static char *buf_to_string(const unsigned char *bin, int len, int nr) +{ + static char buf[2][1024]; + char *w = buf[nr]; + int i; + + for (i = 0; i < len; i++) + { + sprintf(w, "%02x ", (unsigned char)bin[i]); + w += strlen(w); + } + return buf[nr]; +} + +#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)); } + +static void test__mbsncpy_s(void) +{ + unsigned char *mbstring = (unsigned char *)"\xb0\xb1\xb2\xb3Q\xb4\xb5\x0"; /* correct string */ + unsigned char buf[16]; + errno_t err; + + errno = 0xdeadbeef; + memset(buf, 0xcc, sizeof(buf)); + err = p__mbsncpy_s(buf, 6, mbstring, 1); + ok(errno == 0xdeadbeef, "Unexpected errno = %d\n", errno); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\xb0\0\xcc", 3); + + memset(buf, 0xcc, sizeof(buf)); + err = p__mbsncpy_s(buf, 6, mbstring, 2); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\xb0\xb1\0\xcc", 4); + + memset(buf, 0xcc, sizeof(buf)); + err = p__mbsncpy_s(buf, 2, mbstring, _TRUNCATE); + ok(err == STRUNCATE, "got %d.\n", err); + expect_bin(buf, "\xb0\0\xcc", 3); + + memset(buf, 0xcc, sizeof(buf)); + err = p__mbsncpy_s(buf, 2, mbstring, 1); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\xb0\0\xcc", 3); + + memset(buf, 0xcc, sizeof(buf)); + SET_EXPECT(invalid_parameter_handler); + err = p__mbsncpy_s(buf, 2, mbstring, 3); + CHECK_CALLED(invalid_parameter_handler); + ok(err == ERANGE, "got %d.\n", err); + expect_bin(buf, "\x0\xb1\xcc", 3); + + memset(buf, 0xcc, sizeof(buf)); + SET_EXPECT(invalid_parameter_handler); + err = p__mbsncpy_s(buf, 1, mbstring, 3); + CHECK_CALLED(invalid_parameter_handler); + ok(err == ERANGE, "got %d.\n", err); + expect_bin(buf, "\x0\xcc", 2); + + memset(buf, 0xcc, sizeof(buf)); + SET_EXPECT(invalid_parameter_handler); + err = p__mbsncpy_s(buf, 0, mbstring, 3); + CHECK_CALLED(invalid_parameter_handler); + ok(err == EINVAL, "got %d.\n", err); + expect_bin(buf, "\xcc", 1); + + memset(buf, 0xcc, sizeof(buf)); + SET_EXPECT(invalid_parameter_handler); + err = p__mbsncpy_s(buf, 0, mbstring, 0); + CHECK_CALLED(invalid_parameter_handler); + ok(err == EINVAL, "got %d.\n", err); + expect_bin(buf, "\xcc", 1); + + memset(buf, 0xcc, sizeof(buf)); + err = p__mbsncpy_s(buf, -1, mbstring, 0); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\x0\xcc", 2); + + memset(buf, 0xcc, sizeof(buf)); + err = p__mbsncpy_s(buf, -1, mbstring, 256); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\xb0\xb1\xb2\xb3Q\xb4\xb5\x0\xcc", 9); +} + START_TEST(msvcr80) { if(!init()) return;
+ ok(p__set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL, + "Invalid parameter handler was already set\n"); + test_ioinfo_flags(); test_strcmp(); test_dupenv_s(); test_wdupenv_s(); + test__mbsncpy_s(); } diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec index ca22d7460be..c19f7298235 100644 --- a/dlls/msvcr90/msvcr90.spec +++ b/dlls/msvcr90/msvcr90.spec @@ -807,8 +807,8 @@ @ stub _mbsncoll_l @ cdecl _mbsncpy(ptr str long) @ cdecl _mbsncpy_l(ptr str long ptr) -@ stub _mbsncpy_s -@ stub _mbsncpy_s_l +@ cdecl _mbsncpy_s(ptr long str long) +@ cdecl _mbsncpy_s_l(ptr long str long ptr) @ cdecl _mbsnextc(str) @ cdecl _mbsnextc_l(str ptr) @ cdecl _mbsnicmp(str str long) diff --git a/dlls/msvcrt/mbcs.c b/dlls/msvcrt/mbcs.c index ce8a3115eeb..3ddbae09078 100644 --- a/dlls/msvcrt/mbcs.c +++ b/dlls/msvcrt/mbcs.c @@ -900,6 +900,70 @@ unsigned char* CDECL _mbsncpy_l(unsigned char* dst, const unsigned char* src, si return ret; }
+#if _MSVCR_VER>=80 +errno_t CDECL _mbsncpy_s_l(unsigned char* dst, size_t maxsize, const unsigned char* src, size_t n, _locale_t locale) +{ + BOOL truncate = (n == _TRUNCATE); + unsigned char *start = dst; + pthreadmbcinfo mbcinfo; + + if(!MSVCRT_CHECK_PMT(dst != NULL)) return EINVAL; + if (!MSVCRT_CHECK_PMT(maxsize != 0)) return EINVAL; + if (!MSVCRT_CHECK_PMT(src != NULL)) + { + *start = 0; + return EINVAL; + } + + if (!n) + { + *start = 0; + return 0; + } + + if (locale) + mbcinfo = locale->mbcinfo; + else + mbcinfo = get_mbcinfo(); + + while (*src && n && maxsize) + { + if (mbcinfo->ismbcodepage && _ismbblead_l(*src, locale)) + { + --maxsize; + if (!*(src + 1)) + { + *dst++ = 0; + break; + } + *dst++ = *src++; + if (!maxsize) break; + } + --maxsize; + --n; + *dst++ = *src++; + } + + if (!maxsize && truncate) + { + *(dst - 1) = 0; + return STRUNCATE; + } + if (!maxsize) + { + *start = 0; + if (!MSVCRT_CHECK_PMT(FALSE)) return ERANGE; + } + *dst = 0; + return 0; +} + +errno_t CDECL _mbsncpy_s(unsigned char* dst, size_t maxsize, const unsigned char* src, size_t n) +{ + return _mbsncpy_s_l(dst, maxsize, src, n, NULL); +} +#endif + /********************************************************************* * _mbsncpy(MSVCRT.@) * REMARKS diff --git a/dlls/ucrtbase/tests/string.c b/dlls/ucrtbase/tests/string.c index 6dcd15fb5b9..5789e7ba619 100644 --- a/dlls/ucrtbase/tests/string.c +++ b/dlls/ucrtbase/tests/string.c @@ -651,6 +651,90 @@ static void test_strcmp(void) ok( ret == 0, "wrong ret %d\n", ret ); }
+static char *buf_to_string(const unsigned char *bin, int len, int nr) +{ + static char buf[2][1024]; + char *w = buf[nr]; + int i; + + for (i = 0; i < len; i++) + { + sprintf(w, "%02x ", (unsigned char)bin[i]); + w += strlen(w); + } + return buf[nr]; +} + +#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)); } + +static void test__mbsncpy_s(void) +{ + unsigned char *mbstring = (unsigned char *)"\xb0\xb1\xb2\xb3Q\xb4\xb5\x0"; /* correct string */ + unsigned char buf[16]; + errno_t err; + + errno = 0xdeadbeef; + memset(buf, 0xcc, sizeof(buf)); + err = _mbsncpy_s(buf, 6, mbstring, 1); + ok(errno == 0xdeadbeef, "Unexpected errno = %d\n", errno); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\xb0\0\xcc", 3); + + memset(buf, 0xcc, sizeof(buf)); + err = _mbsncpy_s(buf, 6, mbstring, 2); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\xb0\xb1\0\xcc", 4); + + memset(buf, 0xcc, sizeof(buf)); + err = _mbsncpy_s(buf, 2, mbstring, _TRUNCATE); + ok(err == STRUNCATE, "got %d.\n", err); + expect_bin(buf, "\xb0\0\xcc", 3); + + memset(buf, 0xcc, sizeof(buf)); + err = _mbsncpy_s(buf, 2, mbstring, 1); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\xb0\0\xcc", 3); + + memset(buf, 0xcc, sizeof(buf)); + SET_EXPECT(invalid_parameter_handler); + err = _mbsncpy_s(buf, 2, mbstring, 3); + CHECK_CALLED(invalid_parameter_handler); + ok(err == ERANGE, "got %d.\n", err); + expect_bin(buf, "\x0\xb1\xcc", 3); + + memset(buf, 0xcc, sizeof(buf)); + SET_EXPECT(invalid_parameter_handler); + err = _mbsncpy_s(buf, 1, mbstring, 3); + CHECK_CALLED(invalid_parameter_handler); + ok(err == ERANGE, "got %d.\n", err); + expect_bin(buf, "\x0\xcc", 2); + + memset(buf, 0xcc, sizeof(buf)); + SET_EXPECT(invalid_parameter_handler); + err = _mbsncpy_s(buf, 0, mbstring, 3); + CHECK_CALLED(invalid_parameter_handler); + ok(err == EINVAL, "got %d.\n", err); + expect_bin(buf, "\xcc", 1); + + memset(buf, 0xcc, sizeof(buf)); + SET_EXPECT(invalid_parameter_handler); + err = _mbsncpy_s(buf, 0, mbstring, 0); + CHECK_CALLED(invalid_parameter_handler); + ok(err == EINVAL, "got %d.\n", err); + expect_bin(buf, "\xcc", 1); + + memset(buf, 0xcc, sizeof(buf)); + err = _mbsncpy_s(buf, -1, mbstring, 0); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\x0\xcc", 2); + + memset(buf, 0xcc, sizeof(buf)); + err = _mbsncpy_s(buf, -1, mbstring, 256); + ok(!err, "got %d.\n", err); + expect_bin(buf, "\xb0\xb1\xb2\xb3Q\xb4\xb5\x0\xcc", 9); +} + START_TEST(string) { ok(_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL, @@ -669,4 +753,5 @@ START_TEST(string) test_SpecialCasing(); test__mbbtype_l(); test_strcmp(); + test__mbsncpy_s(); } diff --git a/dlls/ucrtbase/ucrtbase.spec b/dlls/ucrtbase/ucrtbase.spec index 449b734ad34..054fc4055f4 100644 --- a/dlls/ucrtbase/ucrtbase.spec +++ b/dlls/ucrtbase/ucrtbase.spec @@ -673,8 +673,8 @@ @ stub _mbsncoll_l @ cdecl _mbsncpy(ptr str long) @ cdecl _mbsncpy_l(ptr str long ptr) -@ stub _mbsncpy_s -@ stub _mbsncpy_s_l +@ cdecl _mbsncpy_s(ptr long str long) +@ cdecl _mbsncpy_s_l(ptr long str long ptr) @ cdecl _mbsnextc(str) @ cdecl _mbsnextc_l(str ptr) @ cdecl _mbsnicmp(str str long) @@ -1242,8 +1242,8 @@ @ stub _o__mbsncoll_l @ cdecl _o__mbsncpy(ptr str long) _mbsncpy @ cdecl _o__mbsncpy_l(ptr str long ptr) _mbsncpy_l -@ stub _o__mbsncpy_s -@ stub _o__mbsncpy_s_l +@ cdecl _o__mbsncpy_s(ptr long str long) _mbsncpy_s +@ cdecl _o__mbsncpy_s_l(ptr long str long ptr) _mbsncpy_s_l @ cdecl _o__mbsnextc(str) _mbsnextc @ cdecl _o__mbsnextc_l(str ptr) _mbsnextc_l @ cdecl _o__mbsnicmp(str str long) _mbsnicmp diff --git a/include/msvcrt/mbstring.h b/include/msvcrt/mbstring.h index 28a0e41f10d..f51d8ed6bc3 100644 --- a/include/msvcrt/mbstring.h +++ b/include/msvcrt/mbstring.h @@ -93,6 +93,8 @@ _ACRTIMP size_t __cdecl _mbsnccnt(const unsigned char*,size_t); _ACRTIMP int __cdecl _mbsncmp(const unsigned char*,const unsigned char*,size_t); _ACRTIMP int __cdecl _mbsncoll(const unsigned char*,const unsigned char*,size_t); _ACRTIMP unsigned char* __cdecl _mbsncpy(unsigned char*,const unsigned char*,size_t); +_ACRTIMP errno_t __cdecl _mbsncpy_s(unsigned char*,size_t,const unsigned char*,size_t); +_ACRTIMP errno_t __cdecl _mbsncpy_s_l(unsigned char*,size_t,const unsigned char*,size_t,_locale_t); _ACRTIMP unsigned int __cdecl _mbsnextc(const unsigned char*); _ACRTIMP unsigned int __cdecl _mbsnextc_l(const unsigned char*,_locale_t); _ACRTIMP int __cdecl _mbsnicmp(const unsigned char*,const unsigned char*,size_t);
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=145248
Your paranoid android.
=== w10pro64_zh_CN (64 bit report) ===
msvcr80: msvcr80.c:290: Test failed: Binary buffer mismatch - expected b0 00 cc , got b0 b1 00 msvcr80.c:295: Test failed: Binary buffer mismatch - expected b0 b1 00 cc , got b0 b1 b2 b3 msvcr80.c:300: Test failed: Binary buffer mismatch - expected b0 00 cc , got 00 b1 cc msvcr80.c:72: Test failed: unexpected call invalid_parameter_handler msvcr80.c:304: Test failed: got 34. msvcr80.c:305: Test failed: Binary buffer mismatch - expected b0 00 cc , got 00 cc cc msvcr80.c:312: Test failed: Binary buffer mismatch - expected 00 b1 cc , got 00 cc cc
=== debian11 (32 bit zh:CN report) ===
msvcr80: msvcr80.c:290: Test failed: Binary buffer mismatch - expected b0 00 cc , got b0 b1 00 msvcr80.c:295: Test failed: Binary buffer mismatch - expected b0 b1 00 cc , got b0 b1 b2 b3 msvcr80.c:72: Test failed: unexpected call invalid_parameter_handler msvcr80.c:304: Test failed: got 34. msvcr80.c:305: Test failed: Binary buffer mismatch - expected b0 00 cc , got 00 b1 cc
There are related test failures, I will fix that on Monday.