Module: wine Branch: master Commit: a0b6bf86f74438c574f7165ab220060681bb66cd URL: http://source.winehq.org/git/wine.git/?a=commit;h=a0b6bf86f74438c574f7165ab2...
Author: Sebastian Lackner sebastian@fds-team.de Date: Mon Dec 21 13:06:37 2015 +0100
kernel32/tests: Add test for process object destruction.
Signed-off-by: Sebastian Lackner sebastian@fds-team.de Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/kernel32/tests/process.c | 161 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index f186c94..b88db45 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -33,11 +33,14 @@ #include "wincon.h" #include "winnls.h" #include "winternl.h" +#include "tlhelp32.h"
#include "wine/test.h"
/* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */ #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000) +/* THREAD_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */ +#define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff)
#define expect_eq_d(expected, actual) \ do { \ @@ -79,6 +82,12 @@ static BOOL (WINAPI *pGetNumaProcessorNode)(UCHAR, PUCHAR); static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); static BOOL (WINAPI *pProcessIdToSessionId)(DWORD,DWORD*); static DWORD (WINAPI *pWTSGetActiveConsoleSessionId)(void); +static HANDLE (WINAPI *pCreateToolhelp32Snapshot)(DWORD, DWORD); +static BOOL (WINAPI *pProcess32First)(HANDLE, PROCESSENTRY32*); +static BOOL (WINAPI *pProcess32Next)(HANDLE, PROCESSENTRY32*); +static BOOL (WINAPI *pThread32First)(HANDLE, THREADENTRY32*); +static BOOL (WINAPI *pThread32Next)(HANDLE, THREADENTRY32*); +
/* ############################### */ static char base[MAX_PATH]; @@ -237,6 +246,12 @@ static BOOL init(void) pGetNumaProcessorNode = (void *)GetProcAddress(hkernel32, "GetNumaProcessorNode"); pProcessIdToSessionId = (void *)GetProcAddress(hkernel32, "ProcessIdToSessionId"); pWTSGetActiveConsoleSessionId = (void *)GetProcAddress(hkernel32, "WTSGetActiveConsoleSessionId"); + pCreateToolhelp32Snapshot = (void *)GetProcAddress(hkernel32, "CreateToolhelp32Snapshot"); + pProcess32First = (void *)GetProcAddress(hkernel32, "Process32First"); + pProcess32Next = (void *)GetProcAddress(hkernel32, "Process32Next"); + pThread32First = (void *)GetProcAddress(hkernel32, "Thread32First"); + pThread32Next = (void *)GetProcAddress(hkernel32, "Thread32Next"); + return TRUE; }
@@ -287,6 +302,8 @@ static void doChild(const char* file, const char* option) char bufA[MAX_PATH]; WCHAR bufW[MAX_PATH]; HANDLE hFile = CreateFileA(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + HANDLE snapshot; + PROCESSENTRY32 pe; BOOL ret;
if (hFile == INVALID_HANDLE_VALUE) return; @@ -341,6 +358,26 @@ static void doChild(const char* file, const char* option) childPrintf(hFile, "CommandLineA=%s\n", encodeA(GetCommandLineA())); childPrintf(hFile, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
+ /* output toolhelp information */ + snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError()); + memset(&pe, 0, sizeof(pe)); + pe.dwSize = sizeof(pe); + if (pProcess32First(snapshot, &pe)) + { + while (pe.th32ProcessID != GetCurrentProcessId()) + if (!pProcess32Next(snapshot, &pe)) break; + } + CloseHandle(snapshot); + ok(pe.th32ProcessID == GetCurrentProcessId(), "failed to find current process in snapshot\n"); + childPrintf(hFile, + "[Toolhelp]\ncntUsage=%u\nth32DefaultHeapID=%lu\n" + "th32ModuleID=%u\ncntThreads=%u\nth32ParentProcessID=%u\n" + "pcPriClassBase=%u\ndwFlags=%u\nszExeFile=%s\n\n", + pe.cntUsage, pe.th32DefaultHeapID, pe.th32ModuleID, + pe.cntThreads, pe.th32ParentProcessID, pe.pcPriClassBase, + pe.dwFlags, encodeA(pe.szExeFile)); + /* output of environment (Ansi) */ ptrA_save = ptrA = GetEnvironmentStringsA(); if (ptrA) @@ -1065,6 +1102,112 @@ static void test_Directory(void) ok(!TerminateProcess(info.hProcess, 0), "Child process should not exist\n"); }
+static void test_Toolhelp(void) +{ + char buffer[MAX_PATH]; + STARTUPINFOA startup; + PROCESS_INFORMATION info; + HANDLE process, thread, snapshot; + PROCESSENTRY32 pe; + THREADENTRY32 te; + DWORD ret; + int i; + + memset(&startup, 0, sizeof(startup)); + startup.cb = sizeof(startup); + startup.dwFlags = STARTF_USESHOWWINDOW; + startup.wShowWindow = SW_SHOWNORMAL; + + get_file_name(resfile); + sprintf(buffer, ""%s" tests/process.c dump "%s"", selfname, resfile); + ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n"); + ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); + CloseHandle(info.hProcess); + CloseHandle(info.hThread); + + WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + okChildInt("Toolhelp", "cntUsage", 0); + okChildInt("Toolhelp", "th32DefaultHeapID", 0); + okChildInt("Toolhelp", "th32ModuleID", 0); + okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId()); + todo_wine okChildInt("Toolhelp", "pcPriClassBase", 8); + okChildInt("Toolhelp", "dwFlags", 0); + + release_memory(); + DeleteFileA(resfile); + + get_file_name(resfile); + sprintf(buffer, ""%s" tests/process.c nested "%s"", selfname, resfile); + ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n"); + ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); + + process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId); + ok(process != NULL, "OpenProcess failed %u\n", GetLastError()); + CloseHandle(process); + + CloseHandle(info.hProcess); + CloseHandle(info.hThread); + + for (i = 0; i < 20; i++) + { + SetLastError(0xdeadbeef); + process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId); + ok(process || GetLastError() == ERROR_INVALID_PARAMETER, "OpenProcess failed %u\n", GetLastError()); + if (!process) break; + CloseHandle(process); + Sleep(100); + } + /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */ + todo_wine ok(i < 20 || broken(i == 20), "process object not released\n"); + + snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError()); + memset(&pe, 0, sizeof(pe)); + pe.dwSize = sizeof(pe); + if (pProcess32First(snapshot, &pe)) + { + while (pe.th32ParentProcessID != info.dwProcessId) + if (!pProcess32Next(snapshot, &pe)) break; + } + CloseHandle(snapshot); + ok(pe.th32ParentProcessID == info.dwProcessId, "failed to find nested child process\n"); + + process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pe.th32ProcessID); + ok(process != NULL, "OpenProcess failed %u\n", GetLastError()); + + snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError()); + memset(&te, 0, sizeof(te)); + te.dwSize = sizeof(te); + if (pThread32First(snapshot, &te)) + { + while (te.th32OwnerProcessID != pe.th32ProcessID) + if (!pThread32Next(snapshot, &te)) break; + } + CloseHandle(snapshot); + ok(te.th32OwnerProcessID == pe.th32ProcessID, "failed to find suspended thread\n"); + + thread = OpenThread(THREAD_ALL_ACCESS_NT4, FALSE, te.th32ThreadID); + ok(thread != NULL, "OpenThread failed %u\n", GetLastError()); + ret = ResumeThread(thread); + ok(ret == 1, "expected 1, got %u\n", ret); + CloseHandle(thread); + + ok(WaitForSingleObject(process, 30000) == WAIT_OBJECT_0, "Child process termination\n"); + CloseHandle(process); + + WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + okChildInt("Toolhelp", "cntUsage", 0); + okChildInt("Toolhelp", "th32DefaultHeapID", 0); + okChildInt("Toolhelp", "th32ModuleID", 0); + okChildInt("Toolhelp", "th32ParentProcessID", info.dwProcessId); + todo_wine okChildInt("Toolhelp", "pcPriClassBase", 8); + okChildInt("Toolhelp", "dwFlags", 0); + + release_memory(); + DeleteFileA(resfile); +} + static BOOL is_str_env_drive_dir(const char* str) { return str[0] == '=' && str[1] >= 'A' && str[1] <= 'Z' && str[2] == ':' && @@ -2989,6 +3132,23 @@ START_TEST(process) Sleep(100); return; } + else if (!strcmp(myARGV[2], "nested") && myARGC >= 4) + { + char buffer[MAX_PATH]; + STARTUPINFOA startup; + PROCESS_INFORMATION info; + + memset(&startup, 0, sizeof(startup)); + startup.cb = sizeof(startup); + startup.dwFlags = STARTF_USESHOWWINDOW; + startup.wShowWindow = SW_SHOWNORMAL; + + sprintf(buffer, ""%s" tests/process.c dump "%s"", selfname, myARGV[3]); + ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess failed\n"); + CloseHandle(info.hProcess); + CloseHandle(info.hThread); + return; + }
ok(0, "Unexpected command %s\n", myARGV[2]); return; @@ -2998,6 +3158,7 @@ START_TEST(process) test_Startup(); test_CommandLine(); test_Directory(); + test_Toolhelp(); test_Environment(); test_SuspendFlag(); test_DebuggingFlag();