Commit 659e5851 authored by Sebastian Lackner's avatar Sebastian Lackner Committed by Alexandre Julliard

kernel32/tests: Add a test to demonstrate a deadlock by suspending a thread during a system APC.

parent f91a7b2c
...@@ -56,6 +56,9 @@ static VOID (WINAPI *pReleaseSRWLockExclusive)(PSRWLOCK); ...@@ -56,6 +56,9 @@ static VOID (WINAPI *pReleaseSRWLockExclusive)(PSRWLOCK);
static VOID (WINAPI *pReleaseSRWLockShared)(PSRWLOCK); static VOID (WINAPI *pReleaseSRWLockShared)(PSRWLOCK);
static BOOLEAN (WINAPI *pTryAcquireSRWLockExclusive)(PSRWLOCK); static BOOLEAN (WINAPI *pTryAcquireSRWLockExclusive)(PSRWLOCK);
static BOOLEAN (WINAPI *pTryAcquireSRWLockShared)(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 NTSTATUS (WINAPI *pNtWaitForMultipleObjects)(ULONG,const HANDLE*,BOOLEAN,BOOLEAN,const LARGE_INTEGER*);
static void test_signalandwait(void) static void test_signalandwait(void)
...@@ -2394,8 +2397,105 @@ static void test_alertable_wait(void) ...@@ -2394,8 +2397,105 @@ static void test_alertable_wait(void)
CloseHandle(semaphores[1]); 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) START_TEST(sync)
{ {
char **argv;
int argc;
HMODULE hdll = GetModuleHandleA("kernel32.dll"); HMODULE hdll = GetModuleHandleA("kernel32.dll");
HMODULE hntdll = GetModuleHandleA("ntdll.dll"); HMODULE hntdll = GetModuleHandleA("ntdll.dll");
...@@ -2424,8 +2524,21 @@ START_TEST(sync) ...@@ -2424,8 +2524,21 @@ START_TEST(sync)
pReleaseSRWLockShared = (void *)GetProcAddress(hdll, "ReleaseSRWLockShared"); pReleaseSRWLockShared = (void *)GetProcAddress(hdll, "ReleaseSRWLockShared");
pTryAcquireSRWLockExclusive = (void *)GetProcAddress(hdll, "TryAcquireSRWLockExclusive"); pTryAcquireSRWLockExclusive = (void *)GetProcAddress(hdll, "TryAcquireSRWLockExclusive");
pTryAcquireSRWLockShared = (void *)GetProcAddress(hdll, "TryAcquireSRWLockShared"); pTryAcquireSRWLockShared = (void *)GetProcAddress(hdll, "TryAcquireSRWLockShared");
pNtAllocateVirtualMemory = (void *)GetProcAddress(hntdll, "NtAllocateVirtualMemory");
pNtFreeVirtualMemory = (void *)GetProcAddress(hntdll, "NtFreeVirtualMemory");
pNtWaitForMultipleObjects = (void *)GetProcAddress(hntdll, "NtWaitForMultipleObjects"); 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_signalandwait();
test_mutex(); test_mutex();
test_slist(); test_slist();
...@@ -2442,4 +2555,5 @@ START_TEST(sync) ...@@ -2442,4 +2555,5 @@ START_TEST(sync)
test_srwlock_base(); test_srwlock_base();
test_srwlock_example(); test_srwlock_example();
test_alertable_wait(); test_alertable_wait();
test_apc_deadlock();
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment