[1/2] kernel32/tests: Add a test to demonstrate a deadlock by suspending a thread during a system APC.
Sebastian Lackner
sebastian at fds-team.de
Wed Nov 4 22:41:43 CST 2015
Signed-off-by: Sebastian Lackner <sebastian at fds-team.de>
---
On my machine and with this test code, 1000 runs are sufficient to reliably
reproduce the issue. My patch submitted yesterday fixes this issue, but I
guess it doesn't make much sense to resubmit when a completely different
solution is preferred. I still think my approach wasn't too bad. ;)
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 1065d5e..4ac6a99 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();
}
--
2.6.2
More information about the wine-patches
mailing list