Cause of bug discovered by Jason Edmeades.
Some applications partially overlap the two buffers. Handle such rare corner cases without affecting performance in the general case.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=38558 Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
There are no risks of regression here, as the only case where it is slower now is when previously gave a completely wrong result.
I assume performance is important for this function, since it had the switch statement in the first place...
dlls/kernel32/tests/codepage.c | 1 - libs/port/mbtowc.c | 10 ++++++++++ 2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/tests/codepage.c b/dlls/kernel32/tests/codepage.c index 2e47868..38f094f 100644 --- a/dlls/kernel32/tests/codepage.c +++ b/dlls/kernel32/tests/codepage.c @@ -328,7 +328,6 @@ static void test_overlapped_buffers(void) 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); -todo_wine ok(!memcmp(buf, strW, sizeof(strW)), "conversion failed: %s\n", wine_dbgstr_wn((WCHAR *)buf, ARRAY_SIZE(strW))); ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); } diff --git a/libs/port/mbtowc.c b/libs/port/mbtowc.c index 4977c82..6b12e81 100644 --- a/libs/port/mbtowc.c +++ b/libs/port/mbtowc.c @@ -65,6 +65,16 @@ static inline int mbstowcs_sbcs( const struct sbcs_table *table, int flags, ret = -1; }
+ /* when dst overlaps into src we need to handle 1 char at a time */ + if ((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)