Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com ---
Notes: v3 -> v4: - iatgas.h - LLVM(Clang), ARM, ARM64 support - Use __ASM_NAME macro - Don't fail test on MSVC - Don't end asm macros with "\n\t"
v4 -> v5: - iatgas.h - mark idata sections as RO - loader.c - test for forward export itself
v5 -> v6: - loader.c - Fix compilation warning in format string
v6 -> v7: - forward4.c - fix building without MinGW
v7 -> v8: - forward[1-3].c - Call DisableThreadLibraryCalls in DllMain - forward4.c: removed - iatgas.h: removed - sforward.c: new file - loader.c - test static forwarded import using shlwapi -> userenv forward
dlls/kernel32/tests/Makefile.in | 14 ++- dlls/kernel32/tests/forward1.c | 19 ++++ dlls/kernel32/tests/forward1.spec | 2 + dlls/kernel32/tests/forward2.c | 9 ++ dlls/kernel32/tests/forward2.spec | 2 + dlls/kernel32/tests/forward3.c | 9 ++ dlls/kernel32/tests/forward3.spec | 2 + dlls/kernel32/tests/loader.c | 177 ++++++++++++++++++++++++++++++ dlls/kernel32/tests/sforward.c | 16 +++ dlls/kernel32/tests/sforward.spec | 1 + 10 files changed, 249 insertions(+), 2 deletions(-) create mode 100644 dlls/kernel32/tests/forward1.c create mode 100644 dlls/kernel32/tests/forward1.spec create mode 100644 dlls/kernel32/tests/forward2.c create mode 100644 dlls/kernel32/tests/forward2.spec create mode 100644 dlls/kernel32/tests/forward3.c create mode 100644 dlls/kernel32/tests/forward3.spec create mode 100644 dlls/kernel32/tests/sforward.c create mode 100644 dlls/kernel32/tests/sforward.spec
diff --git a/dlls/kernel32/tests/Makefile.in b/dlls/kernel32/tests/Makefile.in index e9516603ce9..1f8dd3b86a0 100644 --- a/dlls/kernel32/tests/Makefile.in +++ b/dlls/kernel32/tests/Makefile.in @@ -1,5 +1,7 @@ TESTDLL = kernel32.dll -IMPORTS = user32 advapi32 + +# shlwapi is for testing export forwarding (to userenv) +IMPORTS = user32 advapi32 shlwapi
SOURCES = \ actctx.c \ @@ -37,4 +39,12 @@ SOURCES = \ toolhelp.c \ version.c \ virtual.c \ - volume.c + volume.c \ + forward1.c \ + forward1.spec \ + forward2.c \ + forward2.spec \ + forward3.c \ + forward3.spec \ + sforward.c \ + sforward.spec diff --git a/dlls/kernel32/tests/forward1.c b/dlls/kernel32/tests/forward1.c new file mode 100644 index 00000000000..6419d95eaea --- /dev/null +++ b/dlls/kernel32/tests/forward1.c @@ -0,0 +1,19 @@ +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +BOOL WINAPI DllMain(HINSTANCE instance_new, DWORD reason, LPVOID reserved) +{ + if (reason == DLL_PROCESS_ATTACH) + DisableThreadLibraryCalls( instance_new ); + return TRUE; +} + +unsigned long forward_test_func(void) +{ + return 0x00005678UL; +} + +unsigned long forward_test_func2(void) +{ + return 0x12340000UL; +} diff --git a/dlls/kernel32/tests/forward1.spec b/dlls/kernel32/tests/forward1.spec new file mode 100644 index 00000000000..bf19fa7e011 --- /dev/null +++ b/dlls/kernel32/tests/forward1.spec @@ -0,0 +1,2 @@ +1 cdecl forward_test_func() +2 cdecl -noname forward_test_func2() diff --git a/dlls/kernel32/tests/forward2.c b/dlls/kernel32/tests/forward2.c new file mode 100644 index 00000000000..d1e77f45f3c --- /dev/null +++ b/dlls/kernel32/tests/forward2.c @@ -0,0 +1,9 @@ +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +BOOL WINAPI DllMain(HINSTANCE instance_new, DWORD reason, LPVOID reserved) +{ + if (reason == DLL_PROCESS_ATTACH) + DisableThreadLibraryCalls( instance_new ); + return TRUE; +} diff --git a/dlls/kernel32/tests/forward2.spec b/dlls/kernel32/tests/forward2.spec new file mode 100644 index 00000000000..374156d8d06 --- /dev/null +++ b/dlls/kernel32/tests/forward2.spec @@ -0,0 +1,2 @@ +1 cdecl forward_test_func() forward1.forward_test_func +2 cdecl -noname forward_test_func2() forward1.#2 diff --git a/dlls/kernel32/tests/forward3.c b/dlls/kernel32/tests/forward3.c new file mode 100644 index 00000000000..d1e77f45f3c --- /dev/null +++ b/dlls/kernel32/tests/forward3.c @@ -0,0 +1,9 @@ +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +BOOL WINAPI DllMain(HINSTANCE instance_new, DWORD reason, LPVOID reserved) +{ + if (reason == DLL_PROCESS_ATTACH) + DisableThreadLibraryCalls( instance_new ); + return TRUE; +} diff --git a/dlls/kernel32/tests/forward3.spec b/dlls/kernel32/tests/forward3.spec new file mode 100644 index 00000000000..31d019aa071 --- /dev/null +++ b/dlls/kernel32/tests/forward3.spec @@ -0,0 +1,2 @@ +1 cdecl forward_test_func() forward2.forward_test_func +2 cdecl -noname forward_test_func2() forward2.#2 diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index f990d632f73..1efd5a7fa5d 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -1642,6 +1642,180 @@ static void test_ImportDescriptors(void) } }
+static void extract_resource(const char *name, const char *type, const char *path) +{ + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + file = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n", path, GetLastError()); + + res = FindResourceA(NULL, name, type); + ok( res != 0, "couldn't find resource\n" ); + ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res )); + WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL ); + ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" ); + CloseHandle( file ); +} + +static void test_static_forwarded_import_refs(void) +{ + CHAR temp_path[MAX_PATH], dir_path[MAX_PATH], sforward_path[MAX_PATH]; + HMODULE userenv, shlwapi, sforward; + FARPROC test_func_stub; + + if (GetModuleHandleA( "userenv.dll" )) + { + skip("cannot test since userenv.dll is already loaded\n"); + return; + } + + GetTempPathA( ARRAY_SIZE(temp_path), temp_path ); + GetTempFileNameA( temp_path, "ldr", GetTickCount() | 1UL, dir_path ); + ok( CreateDirectoryA( dir_path, NULL ), "failed to create dir %s, error %u\n", + dir_path, GetLastError() ); + + snprintf( sforward_path, MAX_PATH, "%s\sforward.dll", dir_path ); + extract_resource( "sforward.dll", "TESTDLL", sforward_path ); + + userenv = LoadLibraryA( "userenv.dll" ); + ok( !!userenv, "couldn't find userenv.dll: %u\n", GetLastError() ); + shlwapi = LoadLibraryA( "shlwapi.dll" ); + ok( !!shlwapi, "couldn't find shlwapi.dll: %u\n", GetLastError() ); + sforward = LoadLibraryA( sforward_path ); + ok( !!sforward, "couldn't find %s: %u\n", sforward_path, GetLastError() ); + + test_func_stub = GetProcAddress( sforward, "test_func_stub" ); + ok( !!test_func_stub, "sforward!test_func_stub not found\n" ); + + FreeLibrary( userenv ); + FreeLibrary( shlwapi ); + + todo_wine + ok( !!GetModuleHandleA( "userenv.dll" ), "userenv.dll unexpectedly unloaded\n" ); + ok( !!GetModuleHandleA( "shlwapi.dll" ), "shlwapi.dll unexpectedly unloaded\n" ); + + FreeLibrary( sforward ); + + ok( !GetModuleHandleA( "userenv.dll" ), "userenv.dll unexpectedly kept open\n" ); + ok( !GetModuleHandleA( "shlwapi.dll" ), "shlwapi.dll unexpectedly kept open\n" ); + ok( !GetModuleHandleA( "sforward.dll" ), "sforward.dll unexpectedly kept open\n" ); + + DeleteFileA( sforward_path ); + RemoveDirectoryA( dir_path ); +} + +static void test_dynamic_forwarded_import_refs(void) +{ + CHAR temp_path[MAX_PATH], dir_path[MAX_PATH]; + CHAR forward1_path[MAX_PATH]; + CHAR forward2_path[MAX_PATH]; + CHAR forward3_path[MAX_PATH]; + HMODULE forward1, forward2, forward3; + FARPROC proc1, proc2, proc3, oproc1, oproc2, oproc3; + + GetTempPathA( ARRAY_SIZE(temp_path), temp_path ); + GetTempFileNameA( temp_path, "ldr", GetTickCount() | 1UL, dir_path ); + ok( CreateDirectoryA( dir_path, NULL ), "failed to create dir %s, error %u\n", + dir_path, GetLastError() ); + + snprintf( forward1_path, MAX_PATH, "%s\forward1.dll", dir_path ); + snprintf( forward2_path, MAX_PATH, "%s\forward2.dll", dir_path ); + snprintf( forward3_path, MAX_PATH, "%s\forward3.dll", dir_path ); + extract_resource( "forward1.dll", "TESTDLL", forward1_path ); + extract_resource( "forward2.dll", "TESTDLL", forward2_path ); + extract_resource( "forward3.dll", "TESTDLL", forward3_path ); + + forward1 = LoadLibraryA( forward1_path ); + ok( !!forward1, "couldn't find %s: %u\n", forward1_path, GetLastError() ); + forward2 = LoadLibraryA( forward2_path ); + ok( !!forward2, "couldn't find %s: %u\n", forward2_path, GetLastError() ); + forward3 = LoadLibraryA( forward3_path ); + ok( !!forward3, "couldn't find %s: %u\n", forward3_path, GetLastError() ); + + proc1 = GetProcAddress(forward1, "forward_test_func"); + ok( !!proc1, "cannot resolve forward1!forward_test_func\n"); + proc2 = GetProcAddress(forward2, "forward_test_func"); + ok( !!proc2, "cannot resolve forward2!forward_test_func\n"); + proc3 = GetProcAddress(forward3, "forward_test_func"); + ok( !!proc3, "cannot resolve forward3!forward_test_func\n"); + ok( proc1 == proc3, "forward1!forward_test_func is not equal to forward3!forward_test_func\n"); + ok( proc2 == proc3, "forward2!forward_test_func is not equal to forward3!forward_test_func\n"); + + oproc1 = GetProcAddress(forward1, (LPSTR)2); + ok( !!oproc1, "cannot resolve forward1!#2 (forward_test_func2)\n"); + oproc2 = GetProcAddress(forward2, (LPSTR)2); + ok( !!oproc2, "cannot resolve forward2!#2 (forward_test_func2)\n"); + oproc3 = GetProcAddress(forward3, (LPSTR)2); + ok( !!oproc3, "cannot resolve forward3!#2 (forward_test_func2)\n"); + ok( oproc1 == oproc3, "forward1!forward_test_func2 is not equal to forward3!forward_test_func2\n"); + ok( oproc2 == oproc3, "forward2!forward_test_func2 is not equal to forward3!forward_test_func2\n"); + + FreeLibrary( forward1 ); + FreeLibrary( forward2 ); + + todo_wine + ok( !!GetModuleHandleA( "forward1.dll" ), "forward1.dll unexpectedly unloaded\n" ); + todo_wine + ok( !!GetModuleHandleA( "forward2.dll" ), "forward2.dll unexpectedly unloaded\n" ); + + FreeLibrary( forward3 ); + + ok( !GetModuleHandleA( "forward1.dll" ), "forward1.dll unexpectedly kept open\n" ); + ok( !GetModuleHandleA( "forward2.dll" ), "forward2.dll unexpectedly kept open\n" ); + ok( !GetModuleHandleA( "forward3.dll" ), "forward3.dll unexpectedly kept open\n" ); + + DeleteFileA( forward1_path ); + DeleteFileA( forward2_path ); + DeleteFileA( forward3_path ); + RemoveDirectoryA( dir_path ); +} + +static void test_dynamic_forward_export_norefs(void) +{ + CHAR temp_path[MAX_PATH], dir_path[MAX_PATH]; + CHAR forward1_path[MAX_PATH]; + CHAR forward2_path[MAX_PATH]; + CHAR forward3_path[MAX_PATH]; + HMODULE forward1, forward2, forward3; + + GetTempPathA( ARRAY_SIZE(temp_path), temp_path ); + GetTempFileNameA( temp_path, "ldr", GetTickCount() | 1UL, dir_path ); + ok( CreateDirectoryA( dir_path, NULL ), "failed to create dir %s, error %u\n", + dir_path, GetLastError() ); + + snprintf( forward1_path, MAX_PATH, "%s\forward1.dll", dir_path ); + snprintf( forward2_path, MAX_PATH, "%s\forward2.dll", dir_path ); + snprintf( forward3_path, MAX_PATH, "%s\forward3.dll", dir_path ); + extract_resource( "forward1.dll", "TESTDLL", forward1_path ); + extract_resource( "forward2.dll", "TESTDLL", forward2_path ); + extract_resource( "forward3.dll", "TESTDLL", forward3_path ); + + forward1 = LoadLibraryA( forward1_path ); + ok( !!forward1, "couldn't find %s: %u\n", forward1_path, GetLastError() ); + forward2 = LoadLibraryA( forward2_path ); + ok( !!forward2, "couldn't find %s: %u\n", forward2_path, GetLastError() ); + forward3 = LoadLibraryA( forward3_path ); + ok( !!forward3, "couldn't find %s: %u\n", forward3_path, GetLastError() ); + + FreeLibrary( forward1 ); + FreeLibrary( forward3 ); + + ok( !GetModuleHandleA( "forward1.dll" ), "forward1.dll unexpectedly kept open\n" ); + ok( !GetModuleHandleA( "forward3.dll" ), "forward3.dll unexpectedly kept open\n" ); + + FreeLibrary( forward2 ); + + ok( !GetModuleHandleA( "forward2.dll" ), "forward2.dll unexpectedly kept open\n" ); + + DeleteFileA( forward1_path ); + DeleteFileA( forward2_path ); + DeleteFileA( forward3_path ); + RemoveDirectoryA( dir_path ); +} + static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL is_dll) { HANDLE hfile, hmap; @@ -4119,9 +4293,12 @@ START_TEST(loader) return; }
+ test_static_forwarded_import_refs(); /* Must be first; other tests may load userenv.dll */ test_filenames(); test_ResolveDelayLoadedAPI(); test_ImportDescriptors(); + test_dynamic_forwarded_import_refs(); + test_dynamic_forward_export_norefs(); test_section_access(); test_import_resolution(); test_ExitProcess(); diff --git a/dlls/kernel32/tests/sforward.c b/dlls/kernel32/tests/sforward.c new file mode 100644 index 00000000000..17f79fb5a74 --- /dev/null +++ b/dlls/kernel32/tests/sforward.c @@ -0,0 +1,16 @@ +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +DECLSPEC_IMPORT BOOL WINAPI SHExpandEnvironmentStringsForUserW(HANDLE,LPCWSTR,LPWSTR,DWORD); + +void test_func_stub(void) +{ + SHExpandEnvironmentStringsForUserW(NULL, NULL, NULL, 0); +} + +BOOL WINAPI DllMain(HINSTANCE instance_new, DWORD reason, LPVOID reserved) +{ + if (reason == DLL_PROCESS_ATTACH) + DisableThreadLibraryCalls( instance_new ); + return TRUE; +} diff --git a/dlls/kernel32/tests/sforward.spec b/dlls/kernel32/tests/sforward.spec new file mode 100644 index 00000000000..cb6d4add796 --- /dev/null +++ b/dlls/kernel32/tests/sforward.spec @@ -0,0 +1 @@ +@ cdecl test_func_stub()
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52094 Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com ---
Notes: v7 -> v8: - Also do GetProcAddress for forwarded ordinal exports
dlls/kernel32/tests/loader.c | 3 -- dlls/ntdll/loader.c | 69 ++++++++++++++++++++---------------- 2 files changed, 39 insertions(+), 33 deletions(-)
diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index 1efd5a7fa5d..40882d3ee34 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -1693,7 +1693,6 @@ static void test_static_forwarded_import_refs(void) FreeLibrary( userenv ); FreeLibrary( shlwapi );
- todo_wine ok( !!GetModuleHandleA( "userenv.dll" ), "userenv.dll unexpectedly unloaded\n" ); ok( !!GetModuleHandleA( "shlwapi.dll" ), "shlwapi.dll unexpectedly unloaded\n" );
@@ -1756,9 +1755,7 @@ static void test_dynamic_forwarded_import_refs(void) FreeLibrary( forward1 ); FreeLibrary( forward2 );
- todo_wine ok( !!GetModuleHandleA( "forward1.dll" ), "forward1.dll unexpectedly unloaded\n" ); - todo_wine ok( !!GetModuleHandleA( "forward2.dll" ), "forward2.dll unexpectedly unloaded\n" );
FreeLibrary( forward3 ); diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 362e1c66be5..6852f0280af 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -749,7 +749,7 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS { const IMAGE_EXPORT_DIRECTORY *exports; DWORD exp_size; - WINE_MODREF *wm; + WINE_MODREF *wm = NULL, *imp; WCHAR mod_name[256]; const char *end = strrchr(forward, '.'); FARPROC proc = NULL; @@ -757,30 +757,24 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS if (!end) return NULL; if (build_import_name( mod_name, forward, end - forward )) return NULL;
- if (!(wm = find_basename_module( mod_name ))) + imp = get_modref( module ); + TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward ); + if (load_dll( load_path, mod_name, 0, &wm, imp->system ) == STATUS_SUCCESS && + !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) { - WINE_MODREF *imp = get_modref( module ); - TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward ); - if (load_dll( load_path, mod_name, 0, &wm, imp->system ) == STATUS_SUCCESS && - !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) + if ((imports_fixup_done || !current_modref) && + process_attach( wm->ldr.DdagNode, NULL ) != STATUS_SUCCESS) { - if (!imports_fixup_done && current_modref) - { - add_module_dependency( current_modref->ldr.DdagNode, wm->ldr.DdagNode ); - } - else if (process_attach( wm->ldr.DdagNode, NULL ) != STATUS_SUCCESS) - { - LdrUnloadDll( wm->ldr.DllBase ); - wm = NULL; - } + LdrUnloadDll( wm->ldr.DllBase ); + wm = NULL; } + }
- if (!wm) - { - ERR( "module not found for forward '%s' used by %s\n", - forward, debugstr_w(imp->ldr.FullDllName.Buffer) ); - return NULL; - } + if (!wm) + { + ERR( "module not found for forward '%s' used by %s\n", + forward, debugstr_w(imp->ldr.FullDllName.Buffer) ); + return NULL; } if ((exports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size ))) @@ -800,6 +794,11 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS " If you are using builtin %s, try using the native one instead.\n", forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer), debugstr_w(get_modref(module)->ldr.BaseDllName.Buffer) ); + if (wm) LdrUnloadDll( wm->ldr.DllBase ); + } + else if (current_modref) + { + add_module_dependency( current_modref->ldr.DdagNode, wm->ldr.DdagNode ); } return proc; } @@ -1844,21 +1843,31 @@ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name, IMAGE_EXPORT_DIRECTORY *exports; DWORD exp_size; NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND; + WINE_MODREF *prev, *wm;
RtlEnterCriticalSection( &loader_section );
- /* check if the module itself is invalid to return the proper error */ - if (!get_modref( module )) ret = STATUS_DLL_NOT_FOUND; - else if ((exports = RtlImageDirectoryEntryToData( module, TRUE, - IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size ))) + wm = get_modref( module ); + if (!wm) ret = STATUS_DLL_NOT_FOUND; + else { - void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, NULL ) - : find_ordinal_export( module, exports, exp_size, ord - exports->Base, NULL ); - if (proc) + prev = current_modref; + current_modref = wm; + + /* check if the module itself is invalid to return the proper error */ + if ((exports = RtlImageDirectoryEntryToData( module, TRUE, + IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size ))) { - *address = proc; - ret = STATUS_SUCCESS; + void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, NULL ) + : find_ordinal_export( module, exports, exp_size, ord - exports->Base, NULL ); + if (proc) + { + *address = proc; + ret = STATUS_SUCCESS; + } } + + current_modref = prev; }
RtlLeaveCriticalSection( &loader_section );
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=105414
Your paranoid android.
=== w8 (32 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded loader.c:1702: Test failed: shlwapi.dll unexpectedly kept open
=== w8adm (32 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded loader.c:1702: Test failed: shlwapi.dll unexpectedly kept open
=== w864 (32 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded loader.c:1702: Test failed: shlwapi.dll unexpectedly kept open
=== w1064v1507 (32 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded loader.c:1702: Test failed: shlwapi.dll unexpectedly kept open
=== w1064v1809 (32 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded loader.c:1702: Test failed: shlwapi.dll unexpectedly kept open
=== w1064 (32 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded loader.c:1702: Test failed: shlwapi.dll unexpectedly kept open
=== w1064_tsign (32 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded loader.c:1702: Test failed: shlwapi.dll unexpectedly kept open
=== w10pro64 (32 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded loader.c:1702: Test failed: shlwapi.dll unexpectedly kept open loader.c:3005: Test failed: attached thread count should be 2
=== w864 (64 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded
=== w1064v1507 (64 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded
=== w1064v1809 (64 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded
=== w1064 (64 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded
=== w1064_2qxl (64 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded
=== w1064_tsign (64 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded loader.c:720: Test failed: 1486: wrong status c000011b/0 loader.c:720: Test failed: 1490: wrong status c000011b/0 loader.c:720: Test failed: 1494: wrong status c000011b/0
=== w10pro64 (64 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded
=== w10pro64_ar (64 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded loader.c:720: Test failed: 1224: wrong status c0000130/c000007b loader.c:720: Test failed: 1229: wrong status c0000130/c000007b loader.c:720: Test failed: 1234: wrong status c0000130/c000007b loader.c:720: Test failed: 1239: wrong status c0000130/c000007b loader.c:720: Test failed: 1244: wrong status c0000130/c000007b loader.c:720: Test failed: 1260: wrong status c0000130/0 loader.c:720: Test failed: 1264: wrong status c0000130/0 loader.c:720: Test failed: 1269: wrong status c0000130/0 loader.c:720: Test failed: 1273: wrong status c0000130/0 loader.c:720: Test failed: 1277: wrong status c0000130/0 loader.c:720: Test failed: 1431: wrong status c0000130/c000007b loader.c:720: Test failed: 1439: wrong status c0000130/c000007b loader.c:720: Test failed: 1444: wrong status c0000130/0 loader.c:724: Test failed: 1444: failed with c0000130 expected fallback loader.c:720: Test failed: 1450: wrong status c0000130/0 loader.c:724: Test failed: 1450: failed with c0000130 expected fallback loader.c:720: Test failed: 1456: wrong status c0000130/0 loader.c:724: Test failed: 1456: failed with c0000130 expected fallback loader.c:720: Test failed: 1463: wrong status c0000130/0 loader.c:724: Test failed: 1463: failed with c0000130 expected fallback loader.c:720: Test failed: 1469: wrong status c0000130/0 loader.c:720: Test failed: 1478: wrong status c0000130/0 loader.c:720: Test failed: 1482: wrong status c0000130/0 loader.c:720: Test failed: 1486: wrong status c0000130/0 loader.c:720: Test failed: 1490: wrong status c0000130/0 loader.c:720: Test failed: 1494: wrong status c0000130/0
=== w10pro64_he (64 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded loader.c:720: Test failed: 1224: wrong status c0000130/c000007b loader.c:720: Test failed: 1229: wrong status c0000130/c000007b loader.c:720: Test failed: 1234: wrong status c0000130/c000007b loader.c:720: Test failed: 1239: wrong status c0000130/c000007b loader.c:720: Test failed: 1244: wrong status c0000130/c000007b loader.c:720: Test failed: 1260: wrong status c0000130/0 loader.c:720: Test failed: 1264: wrong status c0000130/0 loader.c:720: Test failed: 1269: wrong status c0000130/0 loader.c:720: Test failed: 1273: wrong status c0000130/0 loader.c:720: Test failed: 1277: wrong status c0000130/0 loader.c:720: Test failed: 1431: wrong status c0000130/c000007b loader.c:720: Test failed: 1439: wrong status c0000130/c000007b loader.c:720: Test failed: 1444: wrong status c0000130/0 loader.c:724: Test failed: 1444: failed with c0000130 expected fallback loader.c:720: Test failed: 1450: wrong status c0000130/0 loader.c:724: Test failed: 1450: failed with c0000130 expected fallback loader.c:720: Test failed: 1456: wrong status c0000130/0 loader.c:724: Test failed: 1456: failed with c0000130 expected fallback loader.c:720: Test failed: 1463: wrong status c0000130/0 loader.c:724: Test failed: 1463: failed with c0000130 expected fallback loader.c:720: Test failed: 1469: wrong status c0000130/0 loader.c:720: Test failed: 1478: wrong status c0000130/0 loader.c:720: Test failed: 1482: wrong status c0000130/0 loader.c:720: Test failed: 1486: wrong status c0000130/0 loader.c:720: Test failed: 1490: wrong status c0000130/0 loader.c:720: Test failed: 1494: wrong status c0000130/0
=== w10pro64_ja (64 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded loader.c:720: Test failed: 1219: wrong status c000011b/c0000130 loader.c:720: Test failed: 1224: wrong status c000011b/c000007b loader.c:720: Test failed: 1229: wrong status c000011b/c000007b loader.c:720: Test failed: 1234: wrong status c000011b/c000007b loader.c:720: Test failed: 1239: wrong status c000011b/c000007b loader.c:720: Test failed: 1244: wrong status c000011b/c000007b loader.c:720: Test failed: 1260: wrong status c000011b/0 loader.c:720: Test failed: 1264: wrong status c000011b/0 loader.c:720: Test failed: 1269: wrong status c000011b/0 loader.c:720: Test failed: 1273: wrong status c000011b/0 loader.c:720: Test failed: 1277: wrong status c000011b/0 loader.c:720: Test failed: 1431: wrong status c000011b/c000007b loader.c:720: Test failed: 1439: wrong status c000011b/c000007b loader.c:720: Test failed: 1444: wrong status c000011b/0 loader.c:724: Test failed: 1444: failed with c000011b expected fallback loader.c:720: Test failed: 1450: wrong status c000011b/0 loader.c:724: Test failed: 1450: failed with c000011b expected fallback loader.c:720: Test failed: 1456: wrong status c000011b/0 loader.c:724: Test failed: 1456: failed with c000011b expected fallback loader.c:720: Test failed: 1463: wrong status c000011b/0 loader.c:724: Test failed: 1463: failed with c000011b expected fallback loader.c:720: Test failed: 1469: wrong status c000011b/0 loader.c:720: Test failed: 1478: wrong status c000011b/0 loader.c:720: Test failed: 1482: wrong status c000011b/0 loader.c:720: Test failed: 1486: wrong status c000011b/0 loader.c:720: Test failed: 1490: wrong status c000011b/0 loader.c:720: Test failed: 1494: wrong status c000011b/0
=== w10pro64_zh_CN (64 bit report) ===
kernel32: loader.c:1696: Test failed: userenv.dll unexpectedly unloaded loader.c:720: Test failed: 1219: wrong status c000011b/c0000130 loader.c:720: Test failed: 1224: wrong status c000011b/c000007b loader.c:720: Test failed: 1229: wrong status c000011b/c000007b loader.c:720: Test failed: 1234: wrong status c000011b/c000007b loader.c:720: Test failed: 1239: wrong status c000011b/c000007b loader.c:720: Test failed: 1244: wrong status c000011b/c000007b loader.c:720: Test failed: 1260: wrong status c000011b/0 loader.c:720: Test failed: 1264: wrong status c000011b/0 loader.c:720: Test failed: 1269: wrong status c000011b/0 loader.c:720: Test failed: 1273: wrong status c000011b/0 loader.c:720: Test failed: 1277: wrong status c000011b/0 loader.c:720: Test failed: 1431: wrong status c000011b/c000007b loader.c:720: Test failed: 1439: wrong status c000011b/c000007b loader.c:720: Test failed: 1444: wrong status c000011b/0 loader.c:724: Test failed: 1444: failed with c000011b expected fallback
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- dlls/ntdll/tests/exception.c | 93 ++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 4307016f149..488a5e94729 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -8397,6 +8397,91 @@ static void test_ripevent(DWORD numexc) pRtlRemoveVectoredExceptionHandler(vectored_handler); }
+static void subtest_fastfail(unsigned int code) +{ + char cmdline[MAX_PATH]; + PROCESS_INFORMATION pi; + STARTUPINFOA si = { 0 }; + DEBUG_EVENT de; + DWORD continuestatus; + BOOL ret; + BOOL had_ff = FALSE, had_se = FALSE; + + sprintf(cmdline, "%s %s %s %u", my_argv[0], my_argv[1], "fastfail", code); + si.cb = sizeof(si); + ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); + ok(ret, "could not create child process error: %u\n", GetLastError()); + if (!ret) + return; + + do + { + continuestatus = DBG_CONTINUE; + ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n"); + + if (de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) + { + if (de.u.Exception.ExceptionRecord.ExceptionCode == STATUS_STACK_BUFFER_OVERRUN) + { + ok(!de.u.Exception.dwFirstChance, "must be a second chance exception\n"); + ok(de.u.Exception.ExceptionRecord.NumberParameters == 1, "expected exactly one parameter, got %u\n", + de.u.Exception.ExceptionRecord.NumberParameters); + ok(de.u.Exception.ExceptionRecord.ExceptionInformation[0] == code, "expected %u for code, got %Iu\n", + code, de.u.Exception.ExceptionRecord.ExceptionInformation[0]); + had_ff = TRUE; + } + + if (de.u.Exception.dwFirstChance) + { + continuestatus = DBG_EXCEPTION_NOT_HANDLED; + } + else + { + had_se = TRUE; + pNtTerminateProcess(pi.hProcess, 0); + } + } + + ContinueDebugEvent(de.dwProcessId, de.dwThreadId, continuestatus); + + } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT); + + todo_wine + ok(had_ff || broken(had_se) /* Win7 */, "fast fail did not occur\n"); + + wait_child_process( pi.hProcess ); + ret = CloseHandle(pi.hThread); + ok(ret, "error %u\n", GetLastError()); + ret = CloseHandle(pi.hProcess); + ok(ret, "error %u\n", GetLastError()); + + return; +} + +static void test_fastfail(void) +{ + unsigned int codes[] = { + FAST_FAIL_LEGACY_GS_VIOLATION, + FAST_FAIL_VTGUARD_CHECK_FAILURE, + FAST_FAIL_STACK_COOKIE_CHECK_FAILURE, + FAST_FAIL_CORRUPT_LIST_ENTRY, + FAST_FAIL_INCORRECT_STACK, + FAST_FAIL_INVALID_ARG, + FAST_FAIL_GS_COOKIE_INIT, + FAST_FAIL_FATAL_APP_EXIT, + FAST_FAIL_INVALID_FAST_FAIL_CODE, + 0xdeadbeefUL, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(codes); i++) + { + winetest_push_context("__fastfail(%#x)", codes[i]); + subtest_fastfail(codes[i]); + winetest_pop_context(); + } +} + static DWORD breakpoint_exceptions;
static LONG CALLBACK breakpoint_handler(EXCEPTION_POINTERS *ExceptionInfo) @@ -10628,6 +10713,13 @@ START_TEST(exception) if (my_argc >= 4) { void *addr; + + if (strcmp(my_argv[2], "fastfail") == 0) + { + __fastfail(strtoul(my_argv[3], NULL, 0)); + return; + } + sscanf( my_argv[3], "%p", &addr );
if (addr != &test_stage) @@ -10766,6 +10858,7 @@ START_TEST(exception) test_thread_context(); test_outputdebugstring(1, FALSE); test_ripevent(1); + test_fastfail(); test_breakpoint(1); test_closehandle(0, (HANDLE)0xdeadbeef); /* Call of Duty WWII writes to BeingDebugged then closes an invalid handle,
__fastfail() is used by the Visual C++ runtime and Windows system libraries to signal that the in-process state is corrupted and unrecoverable.
If __fastfail() is invoked, the NT kernel raises a second-chance non-continuable exception STATUS_STACK_BUFFER_OVERRUN. This quickly terminates the process, bypassing all in-process exception handlers (since they all rely on the potentially corrupted process state).
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com ---
Notes: v3 -> v4: fix BRK #0xF003 detection on ARM64 add comments v4 -> v5: use NtRaiseException()
dlls/ntdll/tests/exception.c | 1 - dlls/ntdll/unix/signal_arm.c | 40 +++++++++++++++++++++++++++++++-- dlls/ntdll/unix/signal_arm64.c | 40 +++++++++++++++++++++++++++++++++ dlls/ntdll/unix/signal_i386.c | 38 ++++++++++++++++++++++++++++++- dlls/ntdll/unix/signal_x86_64.c | 35 +++++++++++++++++++++++++++++ 5 files changed, 150 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 488a5e94729..71d25fa3e93 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -8446,7 +8446,6 @@ static void subtest_fastfail(unsigned int code)
} while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
- todo_wine ok(had_ff || broken(had_se) /* Win7 */, "fast fail did not occur\n");
wait_child_process( pi.hProcess ); diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index a1bcb0ddd32..5d919167d0d 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -615,6 +615,32 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec ) }
+/*********************************************************************** + * raise_second_chance_exception + * + * Raise a second chance exception. + */ +static void raise_second_chance_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec ) +{ + CONTEXT context; + + rec->ExceptionAddress = (void *)PC_sig(sigcontext); + if (is_inside_syscall( sigcontext )) + { + /* Windows would bug check here */ + ERR("Direct second chance exception code %x flags %x addr %p (inside syscall)\n", + rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress ); + NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode ); + } + else + { + save_context( &context, sigcontext ); + NtRaiseException( rec, &context, FALSE ); + restore_context( &context, sigcontext ); + } +} + + /*********************************************************************** * call_user_apc_dispatcher */ @@ -812,13 +838,23 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) switch (get_trap_code(signal, context)) { case TRAP_ARM_PRIVINFLT: /* Invalid opcode exception */ - if (*(WORD *)PC_sig(context) == 0xdefe) /* breakpoint */ + switch (*(WORD *)PC_sig(context)) { + case 0xdefb: /* __fastfail */ + rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; + rec.ExceptionFlags = EH_NONCONTINUABLE; + rec.NumberParameters = 1; + rec.ExceptionInformation[0] = REGn_sig( 0, context ); + raise_second_chance_exception( context, &rec ); + return; + case 0xdefe: /* breakpoint */ rec.ExceptionCode = EXCEPTION_BREAKPOINT; rec.NumberParameters = 1; break; + default: + rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; + break; } - rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; break; case TRAP_ARM_PAGEFLT: /* Page fault */ rec.NumberParameters = 2; diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index 94f280e218a..26910173b81 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -656,6 +656,32 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec ) }
+/*********************************************************************** + * raise_second_chance_exception + * + * Raise a second chance exception. + */ +static void raise_second_chance_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec ) +{ + CONTEXT context; + + rec->ExceptionAddress = (void *)PC_sig(sigcontext); + if (is_inside_syscall( sigcontext )) + { + /* Windows would bug check here */ + ERR("Direct second chance exception code %x flags %x addr %p (inside syscall)\n", + rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress ); + NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode ); + } + else + { + save_context( &context, sigcontext ); + NtRaiseException( rec, &context, FALSE ); + restore_context( &context, sigcontext ); + } +} + + /*********************************************************************** * call_user_apc_dispatcher */ @@ -908,6 +934,7 @@ static void bus_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { EXCEPTION_RECORD rec = { 0 }; + ucontext_t *context = sigcontext;
switch (siginfo->si_code) { @@ -916,6 +943,19 @@ static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) break; case TRAP_BRKPT: default: + /* debug exceptions do not update ESR on Linux, so we fetch the instruction directly. */ + if (!(PSTATE_sig( context ) & 0x10) && /* AArch64 (not WoW) */ + !(PC_sig( context ) & 3) && + *(ULONG *)PC_sig( context ) == 0xd43e0060UL) /* brk #0xf003 */ + { + /* __fastfail */ + rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; + rec.ExceptionFlags = EH_NONCONTINUABLE; + rec.NumberParameters = 1; + rec.ExceptionInformation[0] = REGn_sig( 0, context ); + raise_second_chance_exception( context, &rec ); + return; + } rec.ExceptionCode = EXCEPTION_BREAKPOINT; rec.NumberParameters = 1; break; diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 6bb5649e2b5..f0074216de6 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1485,6 +1485,30 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec ) setup_raise_exception( sigcontext, stack, rec, &xcontext ); }
+/*********************************************************************** + * raise_second_chance_exception + * + * Raise a second chance exception. + */ +static void raise_second_chance_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, struct xcontext *xcontext ) +{ + rec->ExceptionAddress = (void *)EIP_sig( sigcontext ); + if (is_inside_syscall( sigcontext )) + { + /* Windows would bug check here */ + WINE_ERR("Direct second chance exception code %x flags %x addr %p (inside syscall)\n", + rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress ); + NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode ); + } + else + { + save_context( xcontext, sigcontext ); + NtRaiseException( rec, &xcontext->c, FALSE ); + restore_context( xcontext, sigcontext ); + } +} + + /* stack layout when calling an user apc function. * FIXME: match Windows ABI. */ struct apc_stack_layout @@ -1780,8 +1804,20 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) EXCEPTION_RECORD rec = { 0 }; struct xcontext xcontext; ucontext_t *ucontext = sigcontext; - void *stack = setup_exception_record( sigcontext, &rec, &xcontext ); + void *stack;
+ if (TRAP_sig(ucontext) == TRAP_x86_PROTFLT && ERROR_sig(ucontext) == ((0x29 << 3) | 2)) + { + /* __fastfail: process state is corrupted - skip setup_exception_record */ + rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; + rec.ExceptionFlags = EH_NONCONTINUABLE; + rec.NumberParameters = 1; + rec.ExceptionInformation[0] = ECX_sig( ucontext ); + raise_second_chance_exception( ucontext, &rec, &xcontext ); + return; + } + + stack = setup_exception_record( sigcontext, &rec, &xcontext ); switch (TRAP_sig(ucontext)) { case TRAP_x86_OFLOW: /* Overflow exception */ diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 68e0c7ce66e..90fa04f0309 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2198,6 +2198,30 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec ) }
+/*********************************************************************** + * raise_second_chance_exception + * + * Raise a second chance exception. + */ +static void raise_second_chance_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, struct xcontext *xcontext ) +{ + rec->ExceptionAddress = (void *)RIP_sig(sigcontext); + if (is_inside_syscall( sigcontext )) + { + /* Windows would bug check here */ + ERR("Direct second chance exception code %x flags %x addr %p (inside syscall)\n", + rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress ); + NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode ); + } + else + { + save_context( xcontext, sigcontext ); + NtRaiseException( rec, &xcontext->c, FALSE ); + restore_context( xcontext, sigcontext ); + } +} + + /*********************************************************************** * call_user_apc_dispatcher */ @@ -2560,6 +2584,17 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) struct xcontext context; ucontext_t *ucontext = sigcontext;
+ if (TRAP_sig(ucontext) == TRAP_x86_PROTFLT && ERROR_sig(ucontext) == ((0x29 << 3) | 2)) + { + /* __fastfail: process state is corrupted */ + rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; + rec.ExceptionFlags = EH_NONCONTINUABLE; + rec.NumberParameters = 1; + rec.ExceptionInformation[0] = RCX_sig( ucontext ); + raise_second_chance_exception( ucontext, &rec, &context ); + return; + } + rec.ExceptionAddress = (void *)RIP_sig(ucontext); save_context( &context, sigcontext );
Jinoh Kang jinoh.kang.kr@gmail.com writes:
@@ -1780,8 +1804,20 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) EXCEPTION_RECORD rec = { 0 }; struct xcontext xcontext; ucontext_t *ucontext = sigcontext;
- void *stack = setup_exception_record( sigcontext, &rec, &xcontext );
void *stack;
if (TRAP_sig(ucontext) == TRAP_x86_PROTFLT && ERROR_sig(ucontext) == ((0x29 << 3) | 2))
{
/* __fastfail: process state is corrupted - skip setup_exception_record */
rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;
rec.ExceptionFlags = EH_NONCONTINUABLE;
rec.NumberParameters = 1;
rec.ExceptionInformation[0] = ECX_sig( ucontext );
raise_second_chance_exception( ucontext, &rec, &xcontext );
return;
}
This should be part of the normal handling, not a special case at the top. If the process state is corrupted skipping setup_exception_record() will make things even worse. The same thing is true for other platforms.
Today, the UDF instruction handler code assumes Thumb mode code, and cannot recognise the UDF.W form or equivalent instructions in ARM mode encoding.
Fix this by generalising the UDF instruction parser code.
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- dlls/ntdll/unix/signal_arm.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index 5d919167d0d..eaa41d9e139 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -360,6 +360,35 @@ static inline WORD get_error_code( const ucontext_t *sigcontext ) }
+/*********************************************************************** + * get_udf_immediate + * + * Get the immediate operand if the PC is at a UDF instruction. + */ +static inline int get_udf_immediate( const ucontext_t *sigcontext ) +{ + if (CPSR_sig(sigcontext) & 0x20) + { + WORD thumb_insn = *(WORD *)PC_sig(sigcontext); + if ((thumb_insn >> 8) == 0xde) return thumb_insn & 0xff; + if ((thumb_insn & 0xfff0) == 0xf7f0) /* udf.w */ + { + WORD ext = *(WORD *)(PC_sig(sigcontext) + 2); + if ((ext & 0xf000) == 0xa000) return ((thumb_insn & 0xf) << 12) | (ext & 0x0fff); + } + } + else + { + DWORD arm_insn = *(DWORD *)PC_sig(sigcontext); + if ((arm_insn & 0xfff000f0) == 0xe7f000f0) + { + return ((arm_insn >> 4) & 0xfff0) | (arm_insn & 0xf); + } + } + return -1; +} + + /*********************************************************************** * save_context * @@ -838,16 +867,16 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) switch (get_trap_code(signal, context)) { case TRAP_ARM_PRIVINFLT: /* Invalid opcode exception */ - switch (*(WORD *)PC_sig(context)) + switch (get_udf_immediate( context )) { - case 0xdefb: /* __fastfail */ + case 0xfb: /* __fastfail */ rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; rec.ExceptionFlags = EH_NONCONTINUABLE; rec.NumberParameters = 1; rec.ExceptionInformation[0] = REGn_sig( 0, context ); raise_second_chance_exception( context, &rec ); return; - case 0xdefe: /* breakpoint */ + case 0xfe: /* breakpoint */ rec.ExceptionCode = EXCEPTION_BREAKPOINT; rec.NumberParameters = 1; break;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=105413
Your paranoid android.
=== w7u_adm (32 bit report) ===
kernel32: comm.c:859: Test failed: WaitCommEvent failed with a timeout comm.c:880: Test failed: WaitCommEvent error 0 comm.c:881: Test failed: WaitCommEvent: expected EV_TXEMPTY, got 0 comm.c:886: Test failed: WaitCommEvent used 1498 ms for waiting
=== w8adm (32 bit report) ===
kernel32: comm.c:886: Test failed: WaitCommEvent used 1532 ms for waiting
=== w7u_2qxl (32 bit report) ===
kernel32: debugger.c:1027: Test failed: ole32.dll was not reported
=== w7u_adm (32 bit report) ===
kernel32: debugger.c:1027: Test failed: ole32.dll was not reported debugger.c:2122: Test failed: NtSetInformationDebugObject failed c0000008
=== w7u_el (32 bit report) ===
kernel32: debugger.c:1027: Test failed: ole32.dll was not reported
=== w1064_tsign (32 bit report) ===
kernel32: debugger: Timeout
=== w1064_tsign (64 bit report) ===
kernel32: debugger.c:155: Test failed: unable to open 'C:\Users\winetest\AppData\Local\Temp\wt7697.tmp' debugger.c:155: Test failed: failed to open: C:\Users\winetest\AppData\Local\Temp\wt7697.tmp debugger.c:676: Test failed: the child and debugged pids don't match: 6276 != 4044
=== w8 (32 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded loader.c:1703: Test failed: shlwapi.dll unexpectedly kept open
=== w8adm (32 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded loader.c:1703: Test failed: shlwapi.dll unexpectedly kept open
=== w864 (32 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded loader.c:1703: Test failed: shlwapi.dll unexpectedly kept open
=== w1064v1507 (32 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded loader.c:1703: Test failed: shlwapi.dll unexpectedly kept open
=== w1064v1809 (32 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded loader.c:1703: Test failed: shlwapi.dll unexpectedly kept open
=== w1064 (32 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded loader.c:1703: Test failed: shlwapi.dll unexpectedly kept open
=== w1064_tsign (32 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded loader.c:1703: Test failed: shlwapi.dll unexpectedly kept open
=== w10pro64 (32 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded loader.c:1703: Test failed: shlwapi.dll unexpectedly kept open
=== w864 (64 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded
=== w1064v1507 (64 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded
=== w1064v1809 (64 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded
=== w1064 (64 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded
=== w1064_2qxl (64 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded
=== w1064_tsign (64 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded
=== w10pro64 (64 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded
=== w10pro64_ar (64 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded
=== w10pro64_he (64 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded loader.c:720: Test failed: 1219: wrong status c000011b/c0000130 loader.c:720: Test failed: 1224: wrong status c000011b/c000007b loader.c:720: Test failed: 1229: wrong status c000011b/c000007b loader.c:720: Test failed: 1234: wrong status c000011b/c000007b loader.c:720: Test failed: 1239: wrong status c000011b/c000007b loader.c:720: Test failed: 1244: wrong status c000011b/c000007b loader.c:720: Test failed: 1260: wrong status c000011b/0 loader.c:720: Test failed: 1264: wrong status c000011b/0 loader.c:720: Test failed: 1269: wrong status c000011b/0 loader.c:720: Test failed: 1273: wrong status c000011b/0 loader.c:720: Test failed: 1277: wrong status c000011b/0 loader.c:720: Test failed: 1431: wrong status c000011b/c000007b loader.c:720: Test failed: 1439: wrong status c000011b/c000007b loader.c:720: Test failed: 1444: wrong status c000011b/0 loader.c:724: Test failed: 1444: failed with c000011b expected fallback loader.c:720: Test failed: 1450: wrong status c000011b/0 loader.c:724: Test failed: 1450: failed with c000011b expected fallback loader.c:720: Test failed: 1456: wrong status c000011b/0 loader.c:724: Test failed: 1456: failed with c000011b expected fallback loader.c:720: Test failed: 1463: wrong status c000011b/0 loader.c:724: Test failed: 1463: failed with c000011b expected fallback loader.c:720: Test failed: 1469: wrong status c000011b/0 loader.c:720: Test failed: 1478: wrong status c000011b/0 loader.c:720: Test failed: 1482: wrong status c000011b/0 loader.c:720: Test failed: 1486: wrong status c000011b/0 loader.c:720: Test failed: 1490: wrong status c000011b/0 loader.c:720: Test failed: 1494: wrong status c000011b/0
=== w10pro64_ja (64 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded loader.c:720: Test failed: 1219: wrong status c000011b/c0000130 loader.c:720: Test failed: 1224: wrong status c000011b/c000007b loader.c:720: Test failed: 1229: wrong status c000011b/c000007b loader.c:720: Test failed: 1234: wrong status c000011b/c000007b loader.c:720: Test failed: 1239: wrong status c000011b/c000007b loader.c:720: Test failed: 1244: wrong status c000011b/c000007b loader.c:720: Test failed: 1260: wrong status c000011b/0 loader.c:720: Test failed: 1264: wrong status c000011b/0 loader.c:720: Test failed: 1269: wrong status c000011b/0 loader.c:720: Test failed: 1273: wrong status c000011b/0 loader.c:720: Test failed: 1277: wrong status c000011b/0 loader.c:720: Test failed: 1431: wrong status c000011b/c000007b loader.c:720: Test failed: 1439: wrong status c000011b/c000007b loader.c:720: Test failed: 1444: wrong status c000011b/0 loader.c:724: Test failed: 1444: failed with c000011b expected fallback loader.c:720: Test failed: 1450: wrong status c000011b/0 loader.c:724: Test failed: 1450: failed with c000011b expected fallback loader.c:720: Test failed: 1456: wrong status c000011b/0 loader.c:724: Test failed: 1456: failed with c000011b expected fallback loader.c:720: Test failed: 1463: wrong status c000011b/0 loader.c:724: Test failed: 1463: failed with c000011b expected fallback loader.c:720: Test failed: 1469: wrong status c000011b/0 loader.c:720: Test failed: 1478: wrong status c000011b/0 loader.c:720: Test failed: 1482: wrong status c000011b/0 loader.c:720: Test failed: 1486: wrong status c000011b/0 loader.c:720: Test failed: 1490: wrong status c000011b/0 loader.c:720: Test failed: 1494: wrong status c000011b/0
=== w10pro64_zh_CN (64 bit report) ===
kernel32: loader.c:1697: Test failed: userenv.dll unexpectedly unloaded loader.c:720: Test failed: 1219: wrong status c000011b/c0000130 loader.c:720: Test failed: 1224: wrong status c000011b/c000007b loader.c:720: Test failed: 1229: wrong status c000011b/c000007b loader.c:720: Test failed: 1234: wrong status c000011b/c000007b loader.c:720: Test failed: 1239: wrong status c000011b/c000007b loader.c:720: Test failed: 1244: wrong status c000011b/c000007b loader.c:720: Test failed: 1260: wrong status c000011b/0 loader.c:720: Test failed: 1264: wrong status c000011b/0 loader.c:720: Test failed: 1269: wrong status c000011b/0 loader.c:720: Test failed: 1273: wrong status c000011b/0 loader.c:720: Test failed: 1277: wrong status c000011b/0 loader.c:720: Test failed: 1431: wrong status c000011b/c000007b loader.c:720: Test failed: 1439: wrong status c000011b/c000007b loader.c:720: Test failed: 1444: wrong status c000011b/0 loader.c:724: Test failed: 1444: failed with c000011b expected fallback loader.c:720: Test failed: 1450: wrong status c000011b/0 loader.c:724: Test failed: 1450: failed with c000011b expected fallback loader.c:720: Test failed: 1456: wrong status c000011b/0 loader.c:724: Test failed: 1456: failed with c000011b expected fallback loader.c:720: Test failed: 1463: wrong status c000011b/0 loader.c:724: Test failed: 1463: failed with c000011b expected fallback loader.c:720: Test failed: 1469: wrong status c000011b/0 loader.c:720: Test failed: 1478: wrong status c000011b/0 loader.c:720: Test failed: 1482: wrong status c000011b/0 loader.c:720: Test failed: 1486: wrong status c000011b/0 loader.c:720: Test failed: 1490: wrong status c000011b/0 loader.c:720: Test failed: 1494: wrong status c000011b/0