Recently I am experimenting with an ASan instrumented Wine build (Details [here](https://gitlab.winehq.org/bernhardu/wine/-/blob/asan-pe_2024-12-29/README.md)), which was showing some issues when running the confirmance tests.
ASan got triggered on this `lstrlenW( dst )` because it seems the NormalizeString function does not add a termination if the length of the source string does not include the terminating character.
Because the `ok` statements condition contains `lstrlenW( ptest->expected[i] )` I assume that value is also expected to get printed if the test would fail.
``` ASAN_OPTIONS="allocator_may_return_null=1:halt_on_error=0" wine dlls/kernel32/tests/x86_64-windows/kernel32_test.exe locale ================================================================= ==640==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffffe1dd420 at pc 0x000140117178 bp 0x7ffffe1dd0d0 sp 0x7ffffe1dd118 READ of size 2 at 0x7ffffe1dd420 thread T0 0800:fixme:file:server_get_file_info Unsupported info class e #0 0x000140117177 in lstrlenW .../wine/include/winbase.h:2921:12 #1 0x00014010d76e in test_NormalizeString .../wine/dlls/kernel32/tests/locale.c:7401:54 #2 0x0001400f0e4c in func_locale .../wine/dlls/kernel32/tests/locale.c:8725:3 #3 0x0001401e6c5e in run_test .../wine/include/wine/test.h:765:5 #4 0x0001401e67a1 in main .../wine/include/wine/test.h:884:12 #5 0x0001401e8113 in mainCRTStartup .../wine/dlls/msvcrt/crt_main.c:58:11 #6 0x6fffffc455ee in BaseThreadInitThunk .../wine/dlls/kernel32/thread.c:61:24 #7 0x6fffffdcaaea in RtlUserThreadStart (C:\windows\system32\ntdll.dll+0x17004aaea)
Address 0x7ffffe1dd420 is located in stack of thread T0 at offset 544 in frame #0 0x00014010d13f in test_NormalizeString .../wine/dlls/kernel32/tests/locale.c:7212
This frame has 8 object(s): [32, 544) 'dst' (line 7358) <== Memory access at offset 544 overflows this variable [608, 609) 'ret' (line 7359) [624, 628) 'dstlen' (line 7361) [640, 1664) 'buffer' (line 7620) [1792, 1798) 'str745' (line 7621) [1824, 1888) 'srcW' (line 7621) [1920, 1984) 'dstW' (line 7621) [2016, 2272) 'resW' (line 7621) HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork (longjmp, SEH and C++ exceptions *are* supported) SUMMARY: AddressSanitizer: stack-buffer-overflow .../wine/include/winbase.h:2921:12 in lstrlenW Shadow bytes around the buggy address: 0x7ffffe1dd180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x7ffffe1dd200: f1 f1 f1 f1 00 00 00 00 00 00 00 00 00 00 00 00 0x7ffffe1dd280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x7ffffe1dd300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x7ffffe1dd380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x7ffffe1dd400: 00 00 00 00[f2]f2 f2 f2 f2 f2 f2 f2 01 f2 04 f2 0x7ffffe1dd480: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 0x7ffffe1dd500: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 0x7ffffe1dd580: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 0x7ffffe1dd600: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 0x7ffffe1dd680: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==640==ABORTING ```
From: Bernhard Übelacker bernhardu@mailbox.org
--- dlls/kernel32/tests/locale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c index 60fa7d99a8a..f21fb14dbad 100644 --- a/dlls/kernel32/tests/locale.c +++ b/dlls/kernel32/tests/locale.c @@ -7398,7 +7398,7 @@ static void test_NormalizeString(void) memset(dst, 0xcc, sizeof(dst)); dstlen = pNormalizeString( norm_forms[i], ptest->str, lstrlenW(ptest->str), dst, dstlen ); ok(dstlen == lstrlenW( ptest->expected[i] ), "%s:%d: Copied length differed: was %d, should be %d\n", - wine_dbgstr_w(ptest->str), i, dstlen, lstrlenW( dst )); + wine_dbgstr_w(ptest->str), i, dstlen, lstrlenW( ptest->expected[i] )); str_cmp = wcsncmp( ptest->expected[i], dst, dstlen ); ok( str_cmp == 0, "%s:%d: string incorrect got %s expect %s\n", wine_dbgstr_w(ptest->str), i, wine_dbgstr_w(dst), wine_dbgstr_w(ptest->expected[i]) );