From 659e585166d3440665588de939652294a5fd2e01 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Thu, 5 Nov 2015 05:41:43 +0100 Subject: [PATCH] kernel32/tests: Add a test to demonstrate a deadlock by suspending a thread during a system APC. Signed-off-by: Sebastian Lackner Signed-off-by: Alexandre Julliard --- dlls/kernel32/tests/sync.c | 114 +++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index 1065d5e7f90..4ac6a99468c 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -56,6 +56,9 @@ static VOID (WINAPI *pReleaseSRWLockExclusive)(PSRWLOCK); static VOID (WINAPI *pReleaseSRWLockShared)(PSRWLOCK); static BOOLEAN (WINAPI *pTryAcquireSRWLockExclusive)(PSRWLOCK); static BOOLEAN (WINAPI *pTryAcquireSRWLockShared)(PSRWLOCK); + +static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG, SIZE_T *, ULONG, ULONG); +static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG); static NTSTATUS (WINAPI *pNtWaitForMultipleObjects)(ULONG,const HANDLE*,BOOLEAN,BOOLEAN,const LARGE_INTEGER*); static void test_signalandwait(void) @@ -2394,8 +2397,105 @@ static void test_alertable_wait(void) CloseHandle(semaphores[1]); } +struct apc_deadlock_info +{ + PROCESS_INFORMATION *pi; + HANDLE event; + BOOL running; +}; + +static DWORD WINAPI apc_deadlock_thread(void *param) +{ + struct apc_deadlock_info *info = param; + PROCESS_INFORMATION *pi = info->pi; + NTSTATUS status; + SIZE_T size; + void *base; + + while (info->running) + { + base = NULL; + size = 0x1000; + status = pNtAllocateVirtualMemory(pi->hProcess, &base, 0, &size, + MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + ok(!status, "expected STATUS_SUCCESS, got %08x\n", status); + ok(base != NULL, "expected base != NULL, got %p\n", base); + SetEvent(info->event); + + size = 0; + status = pNtFreeVirtualMemory(pi->hProcess, &base, &size, MEM_RELEASE); + ok(!status, "expected STATUS_SUCCESS, got %08x\n", status); + SetEvent(info->event); + } + + return 0; +} + +static void test_apc_deadlock(void) +{ + struct apc_deadlock_info info; + PROCESS_INFORMATION pi; + STARTUPINFOA si = { sizeof(si) }; + char cmdline[MAX_PATH]; + HANDLE event, thread; + DWORD result; + BOOL success; + char **argv; + int i; + + winetest_get_mainargs(&argv); + sprintf(cmdline, "\"%s\" sync apc_deadlock", argv[0]); + success = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(success, "CreateProcess failed with %u\n", GetLastError()); + + event = CreateEventA(NULL, FALSE, FALSE, NULL); + ok(event != NULL, "CreateEvent failed with %u\n", GetLastError()); + + info.pi = π + info.event = event; + info.running = TRUE; + + thread = CreateThread(NULL, 0, apc_deadlock_thread, &info, 0, NULL); + ok(thread != NULL, "CreateThread failed with %u\n", GetLastError()); + result = WaitForSingleObject(event, 1000); + ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", result); + + for (i = 0; i < 1000 && info.running; i++) + { + result = SuspendThread(pi.hThread); + ok(result == 0, "expected 0, got %u\n", result); + + WaitForSingleObject(event, 0); /* reset event */ + result = WaitForSingleObject(event, 1000); + if (result == WAIT_TIMEOUT) + { + todo_wine + ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", result); + info.running = FALSE; + } + else + ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", result); + + result = ResumeThread(pi.hThread); + ok(result == 1, "expected 1, got %u\n", result); + Sleep(1); + } + + info.running = FALSE; + result = WaitForSingleObject(thread, 1000); + ok(result == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", result); + CloseHandle(thread); + CloseHandle(event); + + TerminateProcess(pi.hProcess, 0); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); +} + START_TEST(sync) { + char **argv; + int argc; HMODULE hdll = GetModuleHandleA("kernel32.dll"); HMODULE hntdll = GetModuleHandleA("ntdll.dll"); @@ -2424,8 +2524,21 @@ START_TEST(sync) pReleaseSRWLockShared = (void *)GetProcAddress(hdll, "ReleaseSRWLockShared"); pTryAcquireSRWLockExclusive = (void *)GetProcAddress(hdll, "TryAcquireSRWLockExclusive"); pTryAcquireSRWLockShared = (void *)GetProcAddress(hdll, "TryAcquireSRWLockShared"); + pNtAllocateVirtualMemory = (void *)GetProcAddress(hntdll, "NtAllocateVirtualMemory"); + pNtFreeVirtualMemory = (void *)GetProcAddress(hntdll, "NtFreeVirtualMemory"); pNtWaitForMultipleObjects = (void *)GetProcAddress(hntdll, "NtWaitForMultipleObjects"); + argc = winetest_get_mainargs( &argv ); + if (argc >= 3) + { + if (!strcmp(argv[2], "apc_deadlock")) + { + HANDLE handle = GetCurrentThread(); + for (;;) WaitForMultipleObjectsEx(1, &handle, FALSE, INFINITE, TRUE); + } + return; + } + test_signalandwait(); test_mutex(); test_slist(); @@ -2442,4 +2555,5 @@ START_TEST(sync) test_srwlock_base(); test_srwlock_example(); test_alertable_wait(); + test_apc_deadlock(); }