kernel32: Add a test for threads state when a process is being terminated.

Dmitry Timoshkov dmitry at baikal.ru
Tue Apr 9 04:06:46 CDT 2013


This test demonstrates the problem reported in the bug 33331.
---
 dlls/kernel32/tests/loader.c | 177 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 177 insertions(+)

diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c
index 92a2e0b..a992d3a 100644
--- a/dlls/kernel32/tests/loader.c
+++ b/dlls/kernel32/tests/loader.c
@@ -1037,6 +1037,180 @@ nt4_is_broken:
     }
 }
 
+#define MAX_COUNT 10
+static HANDLE hthread[MAX_COUNT];
+static DWORD count;
+
+static DWORD WINAPI thread_proc(void *param)
+{
+    SetEvent(param);
+
+    while (1)
+    {
+        trace("%04u: thread_proc: still alive\n", GetCurrentThreadId());
+        Sleep(50);
+    }
+
+    return 0;
+}
+
+static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param)
+{
+    switch (reason)
+    {
+    case DLL_PROCESS_ATTACH:
+        trace("dll: %p, DLL_PROCESS_ATTACH, %p\n", hinst, param);
+        break;
+    case DLL_PROCESS_DETACH:
+    {
+        BOOL ret;
+        DWORD code, i;
+        trace("dll: %p, DLL_PROCESS_DETACH, %p\n", hinst, param);
+
+        ok(count != 0, "attached thread count should not be 0\n");
+
+        for (i = 0; i < count; i++)
+        {
+            ret = GetExitCodeThread(hthread[i], &code);
+            trace("dll: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
+            ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
+        todo_wine
+            ok(code == 0, "expected thread exit code 0, got %u\n", code);
+        }
+        break;
+    }
+    case DLL_THREAD_ATTACH:
+        trace("dll: %p, DLL_THREAD_ATTACH, %p\n", hinst, param);
+        if (count < MAX_COUNT)
+        {
+            DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hthread[count],
+                            0, TRUE, DUPLICATE_SAME_ACCESS);
+            count++;
+        }
+        break;
+    case DLL_THREAD_DETACH:
+        trace("dll: %p, DLL_THREAD_DETACH, %p\n", hinst, param);
+        break;
+    default:
+        trace("dll: %p, %d, %p\n", hinst, reason, param);
+        break;
+    }
+
+    return TRUE;
+}
+
+static void test_ExitProcess(void)
+{
+#include "pshpack1.h"
+    static struct
+    {
+        BYTE mov_eax;
+        void *target;
+        BYTE jmp_eax[2];
+    } section_data = { 0xb8, 0, { 0xff,0xe0 } };
+#include "poppack.h"
+    static const char filler[0x1000];
+    DWORD dummy, file_align;
+    HANDLE file, thread, event;
+    HMODULE hmod;
+    SYSTEM_INFO si;
+    char dll_name[MAX_PATH];
+    DWORD ret;
+
+#ifndef __i386__
+    skip("x86 specific ExitProcess test\n");
+    return;
+#endif
+
+    GetSystemInfo(&si);
+    trace("system page size %#x\n", si.dwPageSize);
+
+    /* prevent displaying of the "Unable to load this DLL" message box */
+    SetErrorMode(SEM_FAILCRITICALERRORS);
+
+    GetTempPath(MAX_PATH, dll_name);
+    lstrcat(dll_name, "ldr_thrd.tst");
+
+    trace("creating %s\n", dll_name);
+    file = CreateFile(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
+    if (file == INVALID_HANDLE_VALUE)
+    {
+        ok(0, "could not create %s\n", dll_name);
+        return;
+    }
+
+    SetLastError(0xdeadbeef);
+    ret = WriteFile(file, &dos_header, sizeof(dos_header), &dummy, NULL);
+    ok(ret, "WriteFile error %d\n", GetLastError());
+
+    nt_header.FileHeader.NumberOfSections = 1;
+    nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
+    nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED;
+
+    nt_header.OptionalHeader.AddressOfEntryPoint = si.dwPageSize;
+    nt_header.OptionalHeader.SectionAlignment = si.dwPageSize;
+    nt_header.OptionalHeader.FileAlignment = 0x200;
+    nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + si.dwPageSize;
+    nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
+    SetLastError(0xdeadbeef);
+    ret = WriteFile(file, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
+    ok(ret, "WriteFile error %d\n", GetLastError());
+    SetLastError(0xdeadbeef);
+    ret = WriteFile(file, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
+    ok(ret, "WriteFile error %d\n", GetLastError());
+
+    section_data.target = dll_entry_point;
+    section.SizeOfRawData = sizeof(section_data);
+    section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
+    section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
+    section.Misc.VirtualSize = nt_header.OptionalHeader.SectionAlignment;
+    section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
+    SetLastError(0xdeadbeef);
+    ret = WriteFile(file, &section, sizeof(section), &dummy, NULL);
+    ok(ret, "WriteFile error %d\n", GetLastError());
+
+    file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
+    assert(file_align < sizeof(filler));
+    SetLastError(0xdeadbeef);
+    ret = WriteFile(file, filler, file_align, &dummy, NULL);
+    ok(ret, "WriteFile error %d\n", GetLastError());
+
+    /* section data */
+    SetLastError(0xdeadbeef);
+    ret = WriteFile(file, &section_data, sizeof(section_data), &dummy, NULL);
+    ok(ret, "WriteFile error %d\n", GetLastError());
+
+    CloseHandle(file);
+
+    SetLastError(0xdeadbeef);
+    hmod = LoadLibrary(dll_name);
+    ok(hmod != 0, "LoadLibrary error %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    event = CreateEvent(NULL, 0, 0, NULL);
+    ok(event != 0, "CreateEvent error %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    thread = CreateThread(NULL, 0, thread_proc, event, 0, &dummy);
+    ok(thread != 0, "CreateThread error %d\n", GetLastError());
+    WaitForSingleObject(event, INFINITE);
+    CloseHandle(thread);
+
+    ResetEvent(event);
+
+    SetLastError(0xdeadbeef);
+    thread = CreateThread(NULL, 0, thread_proc, event, 0, &dummy);
+    ok(thread != 0, "CreateThread error %d\n", GetLastError());
+    WaitForSingleObject(event, INFINITE);
+    CloseHandle(thread);
+
+    CloseHandle(event);
+
+    Sleep(100);
+    trace("call ExitProcess()\n");
+    ExitProcess(0);
+}
+
 START_TEST(loader)
 {
     pNtMapViewOfSection = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtMapViewOfSection");
@@ -1045,4 +1219,7 @@ START_TEST(loader)
     test_Loader();
     test_ImportDescriptors();
     test_section_access();
+
+    /* ExitProcess test must be the last one */
+    test_ExitProcess();
 }
-- 
1.8.2




More information about the wine-patches mailing list