[PATCH resent 2/2] libs/port/mbtowc: Convert 1 character at a time if dst overlaps into src

Gabriel Ivăncescu gabrielopcode at gmail.com
Wed Dec 19 06:22:25 CST 2018


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 at 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)
-- 
2.19.1




More information about the wine-devel mailing list