Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/kernel32/tests/codepage.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/dlls/kernel32/tests/codepage.c b/dlls/kernel32/tests/codepage.c index b15a3a1..1a797eb 100644 --- a/dlls/kernel32/tests/codepage.c +++ b/dlls/kernel32/tests/codepage.c @@ -314,12 +314,22 @@ static void test_overlapped_buffers(void) char buf[256]; int ret;
+ /* limit such that strA's NUL terminator overlaps strW's NUL */ + size_t overlap_limit = (sizeof(strW)-sizeof(strA)) - (sizeof(strW[0])-sizeof(strA[0])); + SetLastError(0xdeadbeef); memcpy(buf + 1, strW, sizeof(strW)); ret = WideCharToMultiByte(CP_ACP, 0, (WCHAR *)(buf + 1), -1, buf, sizeof(buf), NULL, NULL); ok(ret == sizeof(strA), "unexpected ret %d\n", ret); ok(!memcmp(buf, strA, sizeof(strA)), "conversion failed: %s\n", buf); ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + memcpy(buf + overlap_limit, strA, sizeof(strA)); + ret = MultiByteToWideChar(CP_ACP, 0, buf + overlap_limit, -1, (WCHAR *)buf, sizeof(buf) / sizeof(WCHAR)); + ok(ret == ARRAY_SIZE(strW), "unexpected ret %d\n", ret); + ok(!memcmp(buf, strW, sizeof(strW)), "conversion failed: %s\n", buf); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); }
static void test_string_conversion(LPBOOL bUsedDefaultChar)
Some applications partially overlap the two buffers. For such rare corner cases, do a single check so that there will be no performance regressions, as unsigned operations are defined to wrap around.
Bug discovered by Jason Edmeades, revised from bug report.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=38558 Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- libs/port/mbtowc.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/libs/port/mbtowc.c b/libs/port/mbtowc.c index 4977c82..6ed2c2e 100644 --- a/libs/port/mbtowc.c +++ b/libs/port/mbtowc.c @@ -65,6 +65,17 @@ static inline int mbstowcs_sbcs( const struct sbcs_table *table, int flags, ret = -1; }
+ /* dst can overlap into src, in which case we need to handle 1 char at a time, + but when src < dst, there is no issue no matter how many we handle at once */ + if ((UINT_PTR) ((UINT_PTR)src - (UINT_PTR)dst) < srclen * sizeof(*dst)) + { + do + *dst++ = cp2uni[*src++]; + while (--srclen); + return ret; + } + + /* dst doesn't overlap into src */ for (;;) { switch(srclen)