Release 1.5.29.
[wine] / dlls / kernel32 / tests / loader.c
1 /*
2  * Unit test suite for the PE loader.
3  *
4  * Copyright 2006,2011 Dmitry Timoshkov
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <assert.h>
24
25 #include "ntstatus.h"
26 #define WIN32_NO_STATUS
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winternl.h"
30 #include "wine/test.h"
31
32 #define ALIGN_SIZE(size, alignment) (((size) + (alignment - 1)) & ~((alignment - 1)))
33
34 struct PROCESS_BASIC_INFORMATION_PRIVATE
35 {
36     DWORD_PTR ExitStatus;
37     PPEB      PebBaseAddress;
38     DWORD_PTR AffinityMask;
39     DWORD_PTR BasePriority;
40     ULONG_PTR UniqueProcessId;
41     ULONG_PTR InheritedFromUniqueProcessId;
42 };
43
44 static BOOL is_child;
45 static LONG *child_failures;
46
47 static NTSTATUS (WINAPI *pNtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG, SIZE_T, const LARGE_INTEGER *, SIZE_T *, ULONG, ULONG, ULONG);
48 static NTSTATUS (WINAPI *pNtUnmapViewOfSection)(HANDLE, PVOID);
49 static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
50 static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
51 static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE, DWORD);
52 static void (WINAPI *pLdrShutdownProcess)(void);
53 static BOOLEAN (WINAPI *pRtlDllShutdownInProgress)(void);
54 static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG, SIZE_T *, ULONG, ULONG);
55 static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG);
56
57 static PVOID RVAToAddr(DWORD_PTR rva, HMODULE module)
58 {
59     if (rva == 0)
60         return NULL;
61     return ((char*) module) + rva;
62 }
63
64 static const struct
65 {
66     WORD e_magic;      /* 00: MZ Header signature */
67     WORD unused[29];
68     DWORD e_lfanew;    /* 3c: Offset to extended header */
69 } dos_header =
70 {
71     IMAGE_DOS_SIGNATURE, { 0 }, sizeof(dos_header)
72 };
73
74 static IMAGE_NT_HEADERS nt_header =
75 {
76     IMAGE_NT_SIGNATURE, /* Signature */
77     {
78 #if defined __i386__
79       IMAGE_FILE_MACHINE_I386, /* Machine */
80 #elif defined __x86_64__
81       IMAGE_FILE_MACHINE_AMD64, /* Machine */
82 #elif defined __powerpc__
83       IMAGE_FILE_MACHINE_POWERPC, /* Machine */
84 #elif defined __arm__
85       IMAGE_FILE_MACHINE_ARMNT, /* Machine */
86 #elif defined __aarch64__
87       IMAGE_FILE_MACHINE_ARM64, /* Machine */
88 #else
89 # error You must specify the machine type
90 #endif
91       1, /* NumberOfSections */
92       0, /* TimeDateStamp */
93       0, /* PointerToSymbolTable */
94       0, /* NumberOfSymbols */
95       sizeof(IMAGE_OPTIONAL_HEADER), /* SizeOfOptionalHeader */
96       IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL /* Characteristics */
97     },
98     { IMAGE_NT_OPTIONAL_HDR_MAGIC, /* Magic */
99       1, /* MajorLinkerVersion */
100       0, /* MinorLinkerVersion */
101       0, /* SizeOfCode */
102       0, /* SizeOfInitializedData */
103       0, /* SizeOfUninitializedData */
104       0, /* AddressOfEntryPoint */
105       0x10, /* BaseOfCode, also serves as e_lfanew in the truncated MZ header */
106 #ifndef _WIN64
107       0, /* BaseOfData */
108 #endif
109       0x10000000, /* ImageBase */
110       0, /* SectionAlignment */
111       0, /* FileAlignment */
112       4, /* MajorOperatingSystemVersion */
113       0, /* MinorOperatingSystemVersion */
114       1, /* MajorImageVersion */
115       0, /* MinorImageVersion */
116       4, /* MajorSubsystemVersion */
117       0, /* MinorSubsystemVersion */
118       0, /* Win32VersionValue */
119       sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000, /* SizeOfImage */
120       sizeof(dos_header) + sizeof(nt_header), /* SizeOfHeaders */
121       0, /* CheckSum */
122       IMAGE_SUBSYSTEM_WINDOWS_CUI, /* Subsystem */
123       0, /* DllCharacteristics */
124       0, /* SizeOfStackReserve */
125       0, /* SizeOfStackCommit */
126       0, /* SizeOfHeapReserve */
127       0, /* SizeOfHeapCommit */
128       0, /* LoaderFlags */
129       0, /* NumberOfRvaAndSizes */
130       { { 0 } } /* DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] */
131     }
132 };
133
134 static IMAGE_SECTION_HEADER section =
135 {
136     ".rodata", /* Name */
137     { 0x10 }, /* Misc */
138     0, /* VirtualAddress */
139     0x0a, /* SizeOfRawData */
140     0, /* PointerToRawData */
141     0, /* PointerToRelocations */
142     0, /* PointerToLinenumbers */
143     0, /* NumberOfRelocations */
144     0, /* NumberOfLinenumbers */
145     IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, /* Characteristics */
146 };
147
148 static void test_Loader(void)
149 {
150     static const struct test_data
151     {
152         const void *dos_header;
153         DWORD size_of_dos_header;
154         WORD number_of_sections, size_of_optional_header;
155         DWORD section_alignment, file_alignment;
156         DWORD size_of_image, size_of_headers;
157         DWORD errors[4]; /* 0 means LoadLibrary should succeed */
158     } td[] =
159     {
160         { &dos_header, sizeof(dos_header),
161           1, 0, 0, 0, 0, 0,
162           { ERROR_BAD_EXE_FORMAT }
163         },
164         { &dos_header, sizeof(dos_header),
165           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
166           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0xe00,
167           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER),
168           { ERROR_BAD_EXE_FORMAT } /* XP doesn't like too small image size */
169         },
170         { &dos_header, sizeof(dos_header),
171           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
172           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
173           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER),
174           { ERROR_SUCCESS }
175         },
176         { &dos_header, sizeof(dos_header),
177           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
178           0x1f00,
179           0x1000,
180           { ERROR_SUCCESS }
181         },
182         { &dos_header, sizeof(dos_header),
183           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x200,
184           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x200,
185           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER),
186           { ERROR_SUCCESS, ERROR_INVALID_ADDRESS } /* vista is more strict */
187         },
188         { &dos_header, sizeof(dos_header),
189           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x1000,
190           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
191           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER),
192           { ERROR_BAD_EXE_FORMAT } /* XP doesn't like alignments */
193         },
194         { &dos_header, sizeof(dos_header),
195           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
196           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
197           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER),
198           { ERROR_SUCCESS }
199         },
200         { &dos_header, sizeof(dos_header),
201           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
202           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
203           0x200,
204           { ERROR_SUCCESS }
205         },
206         /* Mandatory are all fields up to SizeOfHeaders, everything else
207          * is really optional (at least that's true for XP).
208          */
209         { &dos_header, sizeof(dos_header),
210           1, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
211           sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER) + 0x10,
212           sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER),
213           { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT, ERROR_INVALID_ADDRESS,
214             ERROR_NOACCESS }
215         },
216         { &dos_header, sizeof(dos_header),
217           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
218           0xd0, /* beyond of the end of file */
219           0xc0, /* beyond of the end of file */
220           { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
221         },
222         { &dos_header, sizeof(dos_header),
223           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
224           0x1000,
225           0,
226           { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
227         },
228         { &dos_header, sizeof(dos_header),
229           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
230           1,
231           0,
232           { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
233         },
234 #if 0 /* not power of 2 alignments need more test cases */
235         { &dos_header, sizeof(dos_header),
236           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x300, 0x300,
237           1,
238           0,
239           { ERROR_BAD_EXE_FORMAT } /* alignment is not power of 2 */
240         },
241 #endif
242         { &dos_header, sizeof(dos_header),
243           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 4, 4,
244           1,
245           0,
246           { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
247         },
248         { &dos_header, sizeof(dos_header),
249           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 1, 1,
250           1,
251           0,
252           { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
253         },
254         { &dos_header, sizeof(dos_header),
255           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
256           0,
257           0,
258           { ERROR_BAD_EXE_FORMAT } /* image size == 0 -> failure */
259         },
260         /* the following data mimics the PE image which upack creates */
261         { &dos_header, 0x10,
262           1, 0x148, 0x1000, 0x200,
263           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
264           0x200,
265           { ERROR_SUCCESS }
266         },
267         /* Minimal PE image that XP is able to load: 92 bytes */
268         { &dos_header, 0x04,
269           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum),
270           0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
271           1,
272           0,
273           { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
274         }
275     };
276     static const char filler[0x1000];
277     static const char section_data[0x10] = "section data";
278     int i;
279     DWORD dummy, file_size, file_align;
280     HANDLE hfile;
281     HMODULE hlib, hlib_as_data_file;
282     SYSTEM_INFO si;
283     char temp_path[MAX_PATH];
284     char dll_name[MAX_PATH];
285     SIZE_T size;
286     BOOL ret;
287
288     GetSystemInfo(&si);
289
290     /* prevent displaying of the "Unable to load this DLL" message box */
291     SetErrorMode(SEM_FAILCRITICALERRORS);
292
293     GetTempPath(MAX_PATH, temp_path);
294
295     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
296     {
297         GetTempFileName(temp_path, "ldr", 0, dll_name);
298
299         /*trace("creating %s\n", dll_name);*/
300         hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
301         if (hfile == INVALID_HANDLE_VALUE)
302         {
303             ok(0, "could not create %s\n", dll_name);
304             break;
305         }
306
307         SetLastError(0xdeadbeef);
308         ret = WriteFile(hfile, td[i].dos_header, td[i].size_of_dos_header, &dummy, NULL);
309         ok(ret, "WriteFile error %d\n", GetLastError());
310
311         nt_header.FileHeader.NumberOfSections = td[i].number_of_sections;
312         nt_header.FileHeader.SizeOfOptionalHeader = td[i].size_of_optional_header;
313
314         nt_header.OptionalHeader.SectionAlignment = td[i].section_alignment;
315         nt_header.OptionalHeader.FileAlignment = td[i].file_alignment;
316         nt_header.OptionalHeader.SizeOfImage = td[i].size_of_image;
317         nt_header.OptionalHeader.SizeOfHeaders = td[i].size_of_headers;
318         SetLastError(0xdeadbeef);
319         ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
320         ok(ret, "WriteFile error %d\n", GetLastError());
321
322         if (nt_header.FileHeader.SizeOfOptionalHeader)
323         {
324             SetLastError(0xdeadbeef);
325             ret = WriteFile(hfile, &nt_header.OptionalHeader,
326                             min(nt_header.FileHeader.SizeOfOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER)),
327                             &dummy, NULL);
328             ok(ret, "WriteFile error %d\n", GetLastError());
329             if (nt_header.FileHeader.SizeOfOptionalHeader > sizeof(IMAGE_OPTIONAL_HEADER))
330             {
331                 file_align = nt_header.FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER);
332                 assert(file_align < sizeof(filler));
333                 SetLastError(0xdeadbeef);
334                 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
335                 ok(ret, "WriteFile error %d\n", GetLastError());
336             }
337         }
338
339         assert(nt_header.FileHeader.NumberOfSections <= 1);
340         if (nt_header.FileHeader.NumberOfSections)
341         {
342             if (nt_header.OptionalHeader.SectionAlignment >= si.dwPageSize)
343             {
344                 section.PointerToRawData = td[i].size_of_dos_header;
345                 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
346                 section.Misc.VirtualSize = section.SizeOfRawData * 10;
347             }
348             else
349             {
350                 section.PointerToRawData = nt_header.OptionalHeader.SizeOfHeaders;
351                 section.VirtualAddress = nt_header.OptionalHeader.SizeOfHeaders;
352                 section.Misc.VirtualSize = 5;
353             }
354
355             SetLastError(0xdeadbeef);
356             ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
357             ok(ret, "WriteFile error %d\n", GetLastError());
358
359             /* section data */
360             SetLastError(0xdeadbeef);
361             ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
362             ok(ret, "WriteFile error %d\n", GetLastError());
363         }
364
365         file_size = GetFileSize(hfile, NULL);
366         CloseHandle(hfile);
367
368         SetLastError(0xdeadbeef);
369         hlib = LoadLibrary(dll_name);
370         if (hlib)
371         {
372             MEMORY_BASIC_INFORMATION info;
373
374             ok( td[i].errors[0] == ERROR_SUCCESS, "%d: should have failed\n", i );
375
376             SetLastError(0xdeadbeef);
377             size = VirtualQuery(hlib, &info, sizeof(info));
378             ok(size == sizeof(info),
379                 "%d: VirtualQuery error %d\n", i, GetLastError());
380             ok(info.BaseAddress == hlib, "%d: %p != %p\n", i, info.BaseAddress, hlib);
381             ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
382             ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
383             ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize), "%d: got %lx != expected %x\n",
384                i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize));
385             ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
386             if (nt_header.OptionalHeader.SectionAlignment < si.dwPageSize)
387                 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
388             else
389                 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
390             ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
391
392             SetLastError(0xdeadbeef);
393             size = VirtualQuery((char *)hlib + info.RegionSize, &info, sizeof(info));
394             ok(size == sizeof(info),
395                 "%d: VirtualQuery error %d\n", i, GetLastError());
396             if (nt_header.OptionalHeader.SectionAlignment == si.dwPageSize ||
397                 nt_header.OptionalHeader.SectionAlignment == nt_header.OptionalHeader.FileAlignment)
398             {
399                 ok(info.BaseAddress == (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize), "%d: got %p != expected %p\n",
400                    i, info.BaseAddress, (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize));
401                 ok(info.AllocationBase == 0, "%d: %p != 0\n", i, info.AllocationBase);
402                 ok(info.AllocationProtect == 0, "%d: %x != 0\n", i, info.AllocationProtect);
403                 /*ok(info.RegionSize == not_practical_value, "%d: %lx != not_practical_value\n", i, info.RegionSize);*/
404                 ok(info.State == MEM_FREE, "%d: %x != MEM_FREE\n", i, info.State);
405                 ok(info.Type == 0, "%d: %x != 0\n", i, info.Type);
406                 ok(info.Protect == PAGE_NOACCESS, "%d: %x != PAGE_NOACCESS\n", i, info.Protect);
407             }
408             else
409             {
410                 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
411                 ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib);
412                 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
413                 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
414                 ok(info.RegionSize == ALIGN_SIZE(file_size, si.dwPageSize), "%d: got %lx != expected %x\n",
415                    i, info.RegionSize, ALIGN_SIZE(file_size, si.dwPageSize));
416                 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
417                 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
418                 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
419             }
420
421             /* header: check the zeroing of alignment */
422             if (nt_header.OptionalHeader.SectionAlignment >= si.dwPageSize)
423             {
424                 const char *start;
425
426                 start = (const char *)hlib + nt_header.OptionalHeader.SizeOfHeaders;
427                 size = ALIGN_SIZE((ULONG_PTR)start, si.dwPageSize) - (ULONG_PTR)start;
428                 ok(!memcmp(start, filler, size), "%d: header alignment is not cleared\n", i);
429             }
430
431             if (nt_header.FileHeader.NumberOfSections)
432             {
433                 SetLastError(0xdeadbeef);
434                 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
435                 ok(size == sizeof(info),
436                     "%d: VirtualQuery error %d\n", i, GetLastError());
437                 if (nt_header.OptionalHeader.SectionAlignment < si.dwPageSize)
438                 {
439                     ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib);
440                     ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize), "%d: got %lx != expected %x\n",
441                        i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize));
442                     ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
443                 }
444                 else
445                 {
446                     ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
447                     ok(info.RegionSize == ALIGN_SIZE(section.Misc.VirtualSize, si.dwPageSize), "%d: got %lx != expected %x\n",
448                        i, info.RegionSize, ALIGN_SIZE(section.Misc.VirtualSize, si.dwPageSize));
449                     ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
450                 }
451                 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
452                 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
453                 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
454                 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
455
456                 if (nt_header.OptionalHeader.SectionAlignment >= si.dwPageSize)
457                     ok(!memcmp((const char *)hlib + section.VirtualAddress + section.PointerToRawData, &nt_header, section.SizeOfRawData), "wrong section data\n");
458                 else
459                     ok(!memcmp((const char *)hlib + section.PointerToRawData, section_data, section.SizeOfRawData), "wrong section data\n");
460
461                 /* check the zeroing of alignment */
462                 if (nt_header.OptionalHeader.SectionAlignment >= si.dwPageSize)
463                 {
464                     const char *start;
465
466                     start = (const char *)hlib + section.VirtualAddress + section.PointerToRawData + section.SizeOfRawData;
467                     size = ALIGN_SIZE((ULONG_PTR)start, si.dwPageSize) - (ULONG_PTR)start;
468                     ok(memcmp(start, filler, size), "%d: alignment should not be cleared\n", i);
469                 }
470             }
471
472             SetLastError(0xdeadbeef);
473             hlib_as_data_file = LoadLibraryEx(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
474             ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
475             ok(hlib_as_data_file == hlib, "hlib_as_file and hlib are different\n");
476
477             SetLastError(0xdeadbeef);
478             ret = FreeLibrary(hlib);
479             ok(ret, "FreeLibrary error %d\n", GetLastError());
480
481             SetLastError(0xdeadbeef);
482             hlib = GetModuleHandle(dll_name);
483             ok(hlib != 0, "GetModuleHandle error %u\n", GetLastError());
484
485             SetLastError(0xdeadbeef);
486             ret = FreeLibrary(hlib_as_data_file);
487             ok(ret, "FreeLibrary error %d\n", GetLastError());
488
489             hlib = GetModuleHandle(dll_name);
490             ok(!hlib, "GetModuleHandle should fail\n");
491
492             SetLastError(0xdeadbeef);
493             hlib_as_data_file = LoadLibraryEx(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
494             ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
495             ok((ULONG_PTR)hlib_as_data_file & 1, "hlib_as_data_file is even\n");
496
497             hlib = GetModuleHandle(dll_name);
498             ok(!hlib, "GetModuleHandle should fail\n");
499
500             SetLastError(0xdeadbeef);
501             ret = FreeLibrary(hlib_as_data_file);
502             ok(ret, "FreeLibrary error %d\n", GetLastError());
503         }
504         else
505         {
506             BOOL error_match;
507             int error_index;
508
509             error_match = FALSE;
510             for (error_index = 0;
511                  ! error_match && error_index < sizeof(td[i].errors) / sizeof(DWORD);
512                  error_index++)
513             {
514                 error_match = td[i].errors[error_index] == GetLastError();
515             }
516             ok(error_match, "%d: unexpected error %d\n", i, GetLastError());
517         }
518
519         SetLastError(0xdeadbeef);
520         ret = DeleteFile(dll_name);
521         ok(ret, "DeleteFile error %d\n", GetLastError());
522     }
523 }
524
525 /* Verify linking style of import descriptors */
526 static void test_ImportDescriptors(void)
527 {
528     HMODULE kernel32_module = NULL;
529     PIMAGE_DOS_HEADER d_header;
530     PIMAGE_NT_HEADERS nt_headers;
531     DWORD import_dir_size;
532     DWORD_PTR dir_offset;
533     PIMAGE_IMPORT_DESCRIPTOR import_chunk;
534
535     /* Load kernel32 module */
536     kernel32_module = GetModuleHandleA("kernel32.dll");
537     assert( kernel32_module != NULL );
538
539     /* Get PE header info from module image */
540     d_header = (PIMAGE_DOS_HEADER) kernel32_module;
541     nt_headers = (PIMAGE_NT_HEADERS) (((char*) d_header) +
542             d_header->e_lfanew);
543
544     /* Get size of import entry directory */
545     import_dir_size = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
546     if (!import_dir_size)
547     {
548         skip("Unable to continue testing due to missing import directory.\n");
549         return;
550     }
551
552     /* Get address of first import chunk */
553     dir_offset = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
554     import_chunk = RVAToAddr(dir_offset, kernel32_module);
555     ok(import_chunk != 0, "Invalid import_chunk: %p\n", import_chunk);
556     if (!import_chunk) return;
557
558     /* Iterate through import descriptors and verify set name,
559      * OriginalFirstThunk, and FirstThunk.  Core Windows DLLs, such as
560      * kernel32.dll, don't use Borland-style linking, where the table of
561      * imported names is stored directly in FirstThunk and overwritten
562      * by the relocation, instead of being stored in OriginalFirstThunk.
563      * */
564     for (; import_chunk->FirstThunk; import_chunk++)
565     {
566         LPCSTR module_name = RVAToAddr(import_chunk->Name, kernel32_module);
567         PIMAGE_THUNK_DATA name_table = RVAToAddr(
568                 U(*import_chunk).OriginalFirstThunk, kernel32_module);
569         PIMAGE_THUNK_DATA iat = RVAToAddr(
570                 import_chunk->FirstThunk, kernel32_module);
571         ok(module_name != NULL, "Imported module name should not be NULL\n");
572         ok(name_table != NULL,
573                 "Name table for imported module %s should not be NULL\n",
574                 module_name);
575         ok(iat != NULL, "IAT for imported module %s should not be NULL\n",
576                 module_name);
577     }
578 }
579
580 static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL is_dll)
581 {
582     HANDLE hfile, hmap;
583     NTSTATUS status;
584     LARGE_INTEGER offset;
585     SIZE_T size;
586     void *addr1, *addr2;
587     MEMORY_BASIC_INFORMATION info;
588     SYSTEM_INFO si;
589
590     if (!pNtMapViewOfSection) return;
591
592     GetSystemInfo(&si);
593
594     SetLastError(0xdeadbeef);
595     hfile = CreateFile(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
596     ok(hfile != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError());
597
598     SetLastError(0xdeadbeef);
599     hmap = CreateFileMapping(hfile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, 0);
600     ok(hmap != 0, "CreateFileMapping error %d\n", GetLastError());
601
602     offset.u.LowPart  = 0;
603     offset.u.HighPart = 0;
604
605     addr1 = NULL;
606     size = 0;
607     status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr1, 0, 0, &offset,
608                                  &size, 1 /* ViewShare */, 0, PAGE_READONLY);
609     ok(status == STATUS_SUCCESS, "NtMapViewOfSection error %x\n", status);
610     ok(addr1 != 0, "mapped address should be valid\n");
611
612     SetLastError(0xdeadbeef);
613     size = VirtualQuery((char *)addr1 + section.VirtualAddress, &info, sizeof(info));
614     ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
615     ok(info.BaseAddress == (char *)addr1 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr1 + section.VirtualAddress);
616     ok(info.RegionSize == si.dwPageSize, "got %#lx != expected %#x\n", info.RegionSize, si.dwPageSize);
617     ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
618     ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
619     ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
620     ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
621     ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
622
623     addr2 = NULL;
624     size = 0;
625     status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr2, 0, 0, &offset,
626                                  &size, 1 /* ViewShare */, 0, PAGE_READONLY);
627     /* FIXME: remove once Wine is fixed */
628     if (status != STATUS_IMAGE_NOT_AT_BASE)
629     {
630         todo_wine {
631         ok(status == STATUS_IMAGE_NOT_AT_BASE, "expected STATUS_IMAGE_NOT_AT_BASE, got %x\n", status);
632         ok(addr2 != 0, "mapped address should be valid\n");
633         }
634         goto wine_is_broken;
635     }
636     ok(status == STATUS_IMAGE_NOT_AT_BASE, "expected STATUS_IMAGE_NOT_AT_BASE, got %x\n", status);
637     ok(addr2 != 0, "mapped address should be valid\n");
638     ok(addr2 != addr1, "mapped addresses should be different\n");
639
640     SetLastError(0xdeadbeef);
641     size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info));
642     ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
643     ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress);
644     ok(info.RegionSize == si.dwPageSize, "got %#lx != expected %#x\n", info.RegionSize, si.dwPageSize);
645     ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
646     ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2);
647     ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
648     ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
649     ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
650
651     status = pNtUnmapViewOfSection(GetCurrentProcess(), addr2);
652     ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status);
653
654     addr2 = MapViewOfFile(hmap, 0, 0, 0, 0);
655     ok(addr2 != 0, "mapped address should be valid\n");
656     ok(addr2 != addr1, "mapped addresses should be different\n");
657
658     SetLastError(0xdeadbeef);
659     size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info));
660     ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
661     ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress);
662     ok(info.RegionSize == si.dwPageSize, "got %#lx != expected %#x\n", info.RegionSize, si.dwPageSize);
663     ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
664     ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2);
665     ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
666     ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
667     ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
668
669     UnmapViewOfFile(addr2);
670
671     SetLastError(0xdeadbeef);
672     addr2 = LoadLibrary(dll_name);
673     if (is_dll)
674     {
675         ok(!addr2, "LoadLibrary should fail, is_dll %d\n", is_dll);
676         ok(GetLastError() == ERROR_INVALID_ADDRESS, "expected ERROR_INVALID_ADDRESS, got %d\n", GetLastError());
677     }
678     else
679     {
680         BOOL ret;
681         ok(addr2 != 0, "LoadLibrary error %d, is_dll %d\n", GetLastError(), is_dll);
682         ok(addr2 != addr1, "mapped addresses should be different\n");
683
684         SetLastError(0xdeadbeef);
685         ret = FreeLibrary(addr2);
686         ok(ret, "FreeLibrary error %d\n", GetLastError());
687     }
688
689 wine_is_broken:
690     status = pNtUnmapViewOfSection(GetCurrentProcess(), addr1);
691     ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status);
692
693     CloseHandle(hmap);
694     CloseHandle(hfile);
695 }
696
697 static BOOL is_mem_writable(DWORD prot)
698 {
699     switch (prot & 0xff)
700     {
701         case PAGE_READWRITE:
702         case PAGE_WRITECOPY:
703         case PAGE_EXECUTE_READWRITE:
704         case PAGE_EXECUTE_WRITECOPY:
705             return TRUE;
706
707         default:
708             return FALSE;
709     }
710 }
711
712 static void test_VirtualProtect(void *base, void *section)
713 {
714     static const struct test_data
715     {
716         DWORD prot_set, prot_get;
717     } td[] =
718     {
719         { 0, 0 }, /* 0x00 */
720         { PAGE_NOACCESS, PAGE_NOACCESS }, /* 0x01 */
721         { PAGE_READONLY, PAGE_READONLY }, /* 0x02 */
722         { PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x03 */
723         { PAGE_READWRITE, PAGE_WRITECOPY }, /* 0x04 */
724         { PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x05 */
725         { PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x06 */
726         { PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x07 */
727         { PAGE_WRITECOPY, PAGE_WRITECOPY }, /* 0x08 */
728         { PAGE_WRITECOPY | PAGE_NOACCESS, 0 }, /* 0x09 */
729         { PAGE_WRITECOPY | PAGE_READONLY, 0 }, /* 0x0a */
730         { PAGE_WRITECOPY | PAGE_NOACCESS | PAGE_READONLY, 0 }, /* 0x0b */
731         { PAGE_WRITECOPY | PAGE_READWRITE, 0 }, /* 0x0c */
732         { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x0d */
733         { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x0e */
734         { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x0f */
735
736         { PAGE_EXECUTE, PAGE_EXECUTE }, /* 0x10 */
737         { PAGE_EXECUTE_READ, PAGE_EXECUTE_READ }, /* 0x20 */
738         { PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x30 */
739         { PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY }, /* 0x40 */
740         { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0x50 */
741         { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0x60 */
742         { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x70 */
743         { PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_WRITECOPY }, /* 0x80 */
744         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE, 0 }, /* 0x90 */
745         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ, 0 }, /* 0xa0 */
746         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0xb0 */
747         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE, 0 }, /* 0xc0 */
748         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0xd0 */
749         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0xe0 */
750         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 } /* 0xf0 */
751     };
752     DWORD ret, orig_prot, old_prot, rw_prot, exec_prot, i, j;
753     MEMORY_BASIC_INFORMATION info;
754     SYSTEM_INFO si;
755
756     GetSystemInfo(&si);
757
758     SetLastError(0xdeadbeef);
759     ret = VirtualProtect(section, si.dwPageSize, PAGE_NOACCESS, &old_prot);
760     ok(ret, "VirtualProtect error %d\n", GetLastError());
761
762     orig_prot = old_prot;
763
764     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
765     {
766         SetLastError(0xdeadbeef);
767         ret = VirtualQuery(section, &info, sizeof(info));
768         ok(ret, "VirtualQuery failed %d\n", GetLastError());
769         ok(info.BaseAddress == section, "%d: got %p != expected %p\n", i, info.BaseAddress, section);
770         ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
771         ok(info.Protect == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, info.Protect);
772         ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
773         ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
774         ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
775         ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
776
777         old_prot = 0xdeadbeef;
778         SetLastError(0xdeadbeef);
779         ret = VirtualProtect(section, si.dwPageSize, td[i].prot_set, &old_prot);
780         if (td[i].prot_get)
781         {
782             ok(ret, "%d: VirtualProtect error %d, requested prot %#x\n", i, GetLastError(), td[i].prot_set);
783             ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
784
785             SetLastError(0xdeadbeef);
786             ret = VirtualQuery(section, &info, sizeof(info));
787             ok(ret, "VirtualQuery failed %d\n", GetLastError());
788             ok(info.BaseAddress == section, "%d: got %p != expected %p\n", i, info.BaseAddress, section);
789             ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
790             ok(info.Protect == td[i].prot_get, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_get);
791             ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
792             ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
793             ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
794             ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
795         }
796         else
797         {
798             ok(!ret, "%d: VirtualProtect should fail\n", i);
799             ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
800         }
801
802         old_prot = 0xdeadbeef;
803         SetLastError(0xdeadbeef);
804         ret = VirtualProtect(section, si.dwPageSize, PAGE_NOACCESS, &old_prot);
805         ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
806         if (td[i].prot_get)
807             ok(old_prot == td[i].prot_get, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_get);
808         else
809             ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
810     }
811
812     exec_prot = 0;
813
814     for (i = 0; i <= 4; i++)
815     {
816         rw_prot = 0;
817
818         for (j = 0; j <= 4; j++)
819         {
820             DWORD prot = exec_prot | rw_prot;
821
822             SetLastError(0xdeadbeef);
823             ret = VirtualProtect(section, si.dwPageSize, prot, &old_prot);
824             if ((rw_prot && exec_prot) || (!rw_prot && !exec_prot))
825             {
826                 ok(!ret, "VirtualProtect(%02x) should fail\n", prot);
827                 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
828             }
829             else
830                 ok(ret, "VirtualProtect(%02x) error %d\n", prot, GetLastError());
831
832             rw_prot = 1 << j;
833         }
834
835         exec_prot = 1 << (i + 4);
836     }
837
838     SetLastError(0xdeadbeef);
839     ret = VirtualProtect(section, si.dwPageSize, orig_prot, &old_prot);
840     ok(ret, "VirtualProtect error %d\n", GetLastError());
841 }
842
843 static void test_section_access(void)
844 {
845     static const struct test_data
846     {
847         DWORD scn_file_access, scn_page_access, scn_page_access_after_write;
848     } td[] =
849     {
850         { 0, PAGE_NOACCESS, 0 },
851         { IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
852         { IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
853         { IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
854         { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
855         { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ },
856         { IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
857         { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
858
859         { IMAGE_SCN_CNT_INITIALIZED_DATA, PAGE_NOACCESS, 0 },
860         { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
861         { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
862         { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
863         { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
864         { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
865         { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
866         { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
867
868         { IMAGE_SCN_CNT_UNINITIALIZED_DATA, PAGE_NOACCESS, 0 },
869         { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
870         { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
871         { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
872         { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
873         { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
874         { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
875         { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE }
876     };
877     static const char filler[0x1000];
878     static const char section_data[0x10] = "section data";
879     char buf[256];
880     int i;
881     DWORD dummy, file_align;
882     HANDLE hfile;
883     HMODULE hlib;
884     SYSTEM_INFO si;
885     char temp_path[MAX_PATH];
886     char dll_name[MAX_PATH];
887     SIZE_T size;
888     MEMORY_BASIC_INFORMATION info;
889     STARTUPINFO sti;
890     PROCESS_INFORMATION pi;
891     DWORD ret;
892
893     GetSystemInfo(&si);
894
895     /* prevent displaying of the "Unable to load this DLL" message box */
896     SetErrorMode(SEM_FAILCRITICALERRORS);
897
898     GetTempPath(MAX_PATH, temp_path);
899
900     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
901     {
902         GetTempFileName(temp_path, "ldr", 0, dll_name);
903
904         /*trace("creating %s\n", dll_name);*/
905         hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
906         if (hfile == INVALID_HANDLE_VALUE)
907         {
908             ok(0, "could not create %s\n", dll_name);
909             return;
910         }
911
912         SetLastError(0xdeadbeef);
913         ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
914         ok(ret, "WriteFile error %d\n", GetLastError());
915
916         nt_header.FileHeader.NumberOfSections = 1;
917         nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
918         nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED;
919
920         nt_header.OptionalHeader.SectionAlignment = si.dwPageSize;
921         nt_header.OptionalHeader.FileAlignment = 0x200;
922         nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + si.dwPageSize;
923         nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
924         SetLastError(0xdeadbeef);
925         ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
926         ok(ret, "WriteFile error %d\n", GetLastError());
927         SetLastError(0xdeadbeef);
928         ret = WriteFile(hfile, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
929         ok(ret, "WriteFile error %d\n", GetLastError());
930
931         section.SizeOfRawData = sizeof(section_data);
932         section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
933         section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
934         section.Misc.VirtualSize = section.SizeOfRawData;
935         section.Characteristics = td[i].scn_file_access;
936         SetLastError(0xdeadbeef);
937         ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
938         ok(ret, "WriteFile error %d\n", GetLastError());
939
940         file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
941         assert(file_align < sizeof(filler));
942         SetLastError(0xdeadbeef);
943         ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
944         ok(ret, "WriteFile error %d\n", GetLastError());
945
946         /* section data */
947         SetLastError(0xdeadbeef);
948         ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
949         ok(ret, "WriteFile error %d\n", GetLastError());
950
951         CloseHandle(hfile);
952
953         SetLastError(0xdeadbeef);
954         hlib = LoadLibrary(dll_name);
955         ok(hlib != 0, "LoadLibrary error %d\n", GetLastError());
956
957         SetLastError(0xdeadbeef);
958         size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
959         ok(size == sizeof(info),
960             "%d: VirtualQuery error %d\n", i, GetLastError());
961         ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
962         ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
963         ok(info.Protect == td[i].scn_page_access, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access);
964         ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
965         ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
966         ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
967         ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
968         if (info.Protect != PAGE_NOACCESS)
969             ok(!memcmp((const char *)info.BaseAddress, section_data, section.SizeOfRawData), "wrong section data\n");
970
971         test_VirtualProtect(hlib, (char *)hlib + section.VirtualAddress);
972
973         /* Windows changes the WRITECOPY to WRITE protection on an image section write (for a changed page only) */
974         if (is_mem_writable(info.Protect))
975         {
976             char *p = info.BaseAddress;
977             *p = 0xfe;
978             SetLastError(0xdeadbeef);
979             size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
980             ok(size == sizeof(info), "%d: VirtualQuery error %d\n", i, GetLastError());
981             /* FIXME: remove the condition below once Wine is fixed */
982             if (info.Protect == PAGE_WRITECOPY || info.Protect == PAGE_EXECUTE_WRITECOPY)
983                 todo_wine ok(info.Protect == td[i].scn_page_access_after_write, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access_after_write);
984             else
985                 ok(info.Protect == td[i].scn_page_access_after_write, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access_after_write);
986         }
987
988         SetLastError(0xdeadbeef);
989         ret = FreeLibrary(hlib);
990         ok(ret, "FreeLibrary error %d\n", GetLastError());
991
992         test_image_mapping(dll_name, td[i].scn_page_access, TRUE);
993
994         /* reset IMAGE_FILE_DLL otherwise CreateProcess fails */
995         nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_RELOCS_STRIPPED;
996         SetLastError(0xdeadbeef);
997         hfile = CreateFile(dll_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
998         /* LoadLibrary called on an already memory-mapped file in
999          * test_image_mapping() above leads to a file handle leak
1000          * under nt4, and inability to overwrite and delete the file
1001          * due to sharing violation error. Ignore it and skip the test,
1002          * but leave a not deletable temporary file.
1003          */
1004         ok(hfile != INVALID_HANDLE_VALUE || broken(hfile == INVALID_HANDLE_VALUE) /* nt4 */,
1005             "CreateFile error %d\n", GetLastError());
1006         if (hfile == INVALID_HANDLE_VALUE) goto nt4_is_broken;
1007         SetFilePointer(hfile, sizeof(dos_header), NULL, FILE_BEGIN);
1008         SetLastError(0xdeadbeef);
1009         ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
1010         ok(ret, "WriteFile error %d\n", GetLastError());
1011         CloseHandle(hfile);
1012
1013         memset(&sti, 0, sizeof(sti));
1014         sti.cb = sizeof(sti);
1015         SetLastError(0xdeadbeef);
1016         ret = CreateProcess(dll_name, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &sti, &pi);
1017         ok(ret, "CreateProcess() error %d\n", GetLastError());
1018
1019         SetLastError(0xdeadbeef);
1020         size = VirtualQueryEx(pi.hProcess, (char *)hlib + section.VirtualAddress, &info, sizeof(info));
1021         ok(size == sizeof(info),
1022             "%d: VirtualQuery error %d\n", i, GetLastError());
1023         ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
1024         ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
1025         ok(info.Protect == td[i].scn_page_access, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access);
1026         ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
1027         ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1028         ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1029         ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1030         if (info.Protect != PAGE_NOACCESS)
1031         {
1032             SetLastError(0xdeadbeef);
1033             ret = ReadProcessMemory(pi.hProcess, info.BaseAddress, buf, section.SizeOfRawData, NULL);
1034             ok(ret, "ReadProcessMemory() error %d\n", GetLastError());
1035             ok(!memcmp(buf, section_data, section.SizeOfRawData), "wrong section data\n");
1036         }
1037
1038         SetLastError(0xdeadbeef);
1039         ret = TerminateProcess(pi.hProcess, 0);
1040         ok(ret, "TerminateProcess() error %d\n", GetLastError());
1041         ret = WaitForSingleObject(pi.hProcess, 3000);
1042         ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
1043
1044         CloseHandle(pi.hThread);
1045         CloseHandle(pi.hProcess);
1046
1047         test_image_mapping(dll_name, td[i].scn_page_access, FALSE);
1048
1049 nt4_is_broken:
1050         SetLastError(0xdeadbeef);
1051         ret = DeleteFile(dll_name);
1052         ok(ret || broken(!ret) /* nt4 */, "DeleteFile error %d\n", GetLastError());
1053     }
1054 }
1055
1056 #define MAX_COUNT 10
1057 static HANDLE attached_thread[MAX_COUNT], stop_event, event, mutex, semaphore;
1058 static DWORD attached_thread_count;
1059 static int test_dll_phase;
1060
1061 static DWORD WINAPI mutex_thread_proc(void *param)
1062 {
1063     DWORD ret;
1064
1065     ret = WaitForSingleObject(mutex, 0);
1066     ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1067
1068     SetEvent(param);
1069
1070     while (1)
1071     {
1072         trace("%04u: mutex_thread_proc: still alive\n", GetCurrentThreadId());
1073         if (WaitForSingleObject(stop_event, 50) != WAIT_TIMEOUT) break;
1074     }
1075
1076     trace("%04u: mutex_thread_proc: exiting\n", GetCurrentThreadId());
1077     return 196;
1078 }
1079
1080 static DWORD WINAPI semaphore_thread_proc(void *param)
1081 {
1082     DWORD ret;
1083
1084     ret = WaitForSingleObject(semaphore, 0);
1085     ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1086
1087     SetEvent(param);
1088
1089     while (1)
1090     {
1091         trace("%04u: semaphore_thread_proc: still alive\n", GetCurrentThreadId());
1092         if (WaitForSingleObject(stop_event, 50) != WAIT_TIMEOUT) break;
1093     }
1094
1095     trace("%04u: semaphore_thread_proc: exiting\n", GetCurrentThreadId());
1096     return 196;
1097 }
1098
1099 static DWORD WINAPI noop_thread_proc(void *param)
1100 {
1101     if (param)
1102     {
1103         LONG *noop_thread_started = param;
1104         InterlockedIncrement(noop_thread_started);
1105     }
1106
1107     trace("%04u: noop_thread_proc: exiting\n", GetCurrentThreadId());
1108     return 195;
1109 }
1110
1111 static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param)
1112 {
1113     static LONG noop_thread_started;
1114     DWORD ret;
1115
1116     switch (reason)
1117     {
1118     case DLL_PROCESS_ATTACH:
1119         trace("dll: %p, DLL_PROCESS_ATTACH, %p\n", hinst, param);
1120
1121         ret = pRtlDllShutdownInProgress();
1122         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1123
1124         break;
1125     case DLL_PROCESS_DETACH:
1126     {
1127         DWORD code, expected_code, i;
1128         HANDLE handle, process;
1129         void *addr;
1130         SIZE_T size;
1131         LARGE_INTEGER offset;
1132         DEBUG_EVENT de;
1133
1134         trace("dll: %p, DLL_PROCESS_DETACH, %p\n", hinst, param);
1135
1136         if (test_dll_phase == 0 || test_dll_phase == 3)
1137             ok(param != NULL, "dll: param %p\n", param);
1138         else
1139             ok(!param, "dll: param %p\n", param);
1140
1141         if (test_dll_phase == 0) expected_code = 195;
1142         else if (test_dll_phase == 3) expected_code = 196;
1143         else expected_code = STILL_ACTIVE;
1144
1145         if (test_dll_phase == 3)
1146         {
1147             ret = pRtlDllShutdownInProgress();
1148             ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
1149         }
1150         else
1151         {
1152             ret = pRtlDllShutdownInProgress();
1153
1154             /* FIXME: remove once Wine is fixed */
1155             if (expected_code == STILL_ACTIVE || expected_code == 196)
1156                 ok(!ret || broken(ret) /* before Vista */, "RtlDllShutdownInProgress returned %d\n", ret);
1157             else
1158             todo_wine
1159                 ok(!ret || broken(ret) /* before Vista */, "RtlDllShutdownInProgress returned %d\n", ret);
1160         }
1161
1162         ok(attached_thread_count >= 2, "attached thread count should be >= 2\n");
1163
1164         for (i = 0; i < attached_thread_count; i++)
1165         {
1166             ret = GetExitCodeThread(attached_thread[i], &code);
1167             trace("dll: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
1168             ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
1169             ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code);
1170         }
1171
1172         ret = WaitForSingleObject(event, 0);
1173         ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1174
1175         ret = WaitForSingleObject(mutex, 0);
1176         if (expected_code == STILL_ACTIVE)
1177             ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1178         else
1179             ok(ret == WAIT_ABANDONED, "expected WAIT_ABANDONED, got %#x\n", ret);
1180
1181         /* semaphore is not abandoned on thread termination */
1182         ret = WaitForSingleObject(semaphore, 0);
1183         ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1184
1185         if (expected_code == STILL_ACTIVE)
1186         {
1187             ret = WaitForSingleObject(attached_thread[0], 0);
1188             ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1189             ret = WaitForSingleObject(attached_thread[1], 0);
1190             ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1191         }
1192         else
1193         {
1194             ret = WaitForSingleObject(attached_thread[0], 0);
1195             ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1196             ret = WaitForSingleObject(attached_thread[1], 0);
1197             ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1198         }
1199
1200         /* win7 doesn't allow to create a thread during process shutdown,
1201          * earlier Windows versions allow it.
1202          */
1203         noop_thread_started = 0;
1204         SetLastError(0xdeadbeef);
1205         handle = CreateThread(NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
1206         if (param)
1207         {
1208             ok(!handle || broken(handle != 0) /* before win7 */, "CreateThread should fail\n");
1209             if (!handle)
1210                 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1211             else
1212             {
1213                 ret = WaitForSingleObject(handle, 1000);
1214                 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1215                 CloseHandle(handle);
1216             }
1217         }
1218         else
1219         {
1220             ok(handle != 0, "CreateThread error %d\n", GetLastError());
1221             ret = WaitForSingleObject(handle, 1000);
1222             ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1223             ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n");
1224             CloseHandle(handle);
1225         }
1226
1227         SetLastError(0xdeadbeef);
1228         process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
1229         ok(process != NULL, "OpenProcess error %d\n", GetLastError());
1230
1231         noop_thread_started = 0;
1232         SetLastError(0xdeadbeef);
1233         handle = CreateRemoteThread(process, NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
1234         if (param)
1235         {
1236             ok(!handle || broken(handle != 0) /* before win7 */, "CreateRemoteThread should fail\n");
1237             if (!handle)
1238                 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1239             else
1240             {
1241                 ret = WaitForSingleObject(handle, 1000);
1242                 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1243                 CloseHandle(handle);
1244             }
1245         }
1246         else
1247         {
1248             ok(handle != 0, "CreateRemoteThread error %d\n", GetLastError());
1249             ret = WaitForSingleObject(handle, 1000);
1250             ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1251             ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n");
1252             CloseHandle(handle);
1253         }
1254
1255         SetLastError(0xdeadbeef);
1256         handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
1257         ok(handle != 0, "CreateFileMapping error %d\n", GetLastError());
1258
1259         offset.u.LowPart = 0;
1260         offset.u.HighPart = 0;
1261         addr = NULL;
1262         size = 0;
1263         ret = pNtMapViewOfSection(handle, process, &addr, 0, 0, &offset,
1264                                   &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1265         ok(ret == STATUS_SUCCESS, "NtMapViewOfSection error %#x\n", ret);
1266         ret = pNtUnmapViewOfSection(process, addr);
1267         ok(ret == STATUS_SUCCESS, "NtUnmapViewOfSection error %#x\n", ret);
1268
1269         CloseHandle(handle);
1270         CloseHandle(process);
1271
1272         handle = GetModuleHandle("winver.exe");
1273         ok(!handle, "winver.exe shouldn't be loaded yet\n");
1274         SetLastError(0xdeadbeef);
1275         handle = LoadLibrary("winver.exe");
1276         ok(handle != 0, "LoadLibrary error %d\n", GetLastError());
1277         SetLastError(0xdeadbeef);
1278         ret = FreeLibrary(handle);
1279         ok(ret, "FreeLibrary error %d\n", GetLastError());
1280         handle = GetModuleHandle("winver.exe");
1281         if (param)
1282             ok(handle != 0, "winver.exe should not be unloaded\n");
1283         else
1284         todo_wine
1285             ok(!handle || broken(handle != 0) /* before win7 */, "winver.exe should be unloaded\n");
1286
1287         SetLastError(0xdeadbeef);
1288         ret = WaitForDebugEvent(&de, 0);
1289         ok(!ret, "WaitForDebugEvent should fail\n");
1290 todo_wine
1291         ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
1292
1293         SetLastError(0xdeadbeef);
1294         ret = DebugActiveProcess(GetCurrentProcessId());
1295         ok(!ret, "DebugActiveProcess should fail\n");
1296         ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1297
1298         SetLastError(0xdeadbeef);
1299         ret = WaitForDebugEvent(&de, 0);
1300         ok(!ret, "WaitForDebugEvent should fail\n");
1301         ok(GetLastError() == ERROR_SEM_TIMEOUT, "expected ERROR_SEM_TIMEOUT, got %d\n", GetLastError());
1302
1303         if (test_dll_phase == 2)
1304         {
1305             trace("dll: call ExitProcess()\n");
1306             *child_failures = winetest_get_failures();
1307             ExitProcess(197);
1308         }
1309         trace("dll: %p, DLL_PROCESS_DETACH, %p => DONE\n", hinst, param);
1310         break;
1311     }
1312     case DLL_THREAD_ATTACH:
1313         trace("dll: %p, DLL_THREAD_ATTACH, %p\n", hinst, param);
1314
1315         ret = pRtlDllShutdownInProgress();
1316         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1317
1318         if (attached_thread_count < MAX_COUNT)
1319         {
1320             DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &attached_thread[attached_thread_count],
1321                             0, TRUE, DUPLICATE_SAME_ACCESS);
1322             attached_thread_count++;
1323         }
1324         break;
1325     case DLL_THREAD_DETACH:
1326         trace("dll: %p, DLL_THREAD_DETACH, %p\n", hinst, param);
1327
1328         ret = pRtlDllShutdownInProgress();
1329         /* win7 doesn't allow to create a thread during process shutdown,
1330          * earlier Windows versions allow it, and DLL_THREAD_DETACH is
1331          * sent on thread exit, but DLL_THREAD_ATTACH is never received.
1332          */
1333         if (noop_thread_started)
1334             ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
1335         else
1336             ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1337
1338         break;
1339     default:
1340         trace("dll: %p, %d, %p\n", hinst, reason, param);
1341         break;
1342     }
1343
1344     *child_failures = winetest_get_failures();
1345
1346     return TRUE;
1347 }
1348
1349 static void child_process(const char *dll_name, DWORD target_offset)
1350 {
1351     void *target;
1352     DWORD ret, dummy, i, code, expected_code;
1353     HANDLE file, thread, process;
1354     HMODULE hmod;
1355     struct PROCESS_BASIC_INFORMATION_PRIVATE pbi;
1356     DWORD_PTR affinity;
1357
1358     trace("phase %d: writing %p at %#x\n", test_dll_phase, dll_entry_point, target_offset);
1359
1360     SetLastError(0xdeadbeef);
1361     mutex = CreateMutex(NULL, FALSE, NULL);
1362     ok(mutex != 0, "CreateMutex error %d\n", GetLastError());
1363
1364     SetLastError(0xdeadbeef);
1365     semaphore = CreateSemaphore(NULL, 1, 1, NULL);
1366     ok(semaphore != 0, "CreateSemaphore error %d\n", GetLastError());
1367
1368     SetLastError(0xdeadbeef);
1369     event = CreateEvent(NULL, TRUE, FALSE, NULL);
1370     ok(event != 0, "CreateEvent error %d\n", GetLastError());
1371
1372     file = CreateFile(dll_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1373     if (file == INVALID_HANDLE_VALUE)
1374     {
1375         ok(0, "could not open %s\n", dll_name);
1376         return;
1377     }
1378     SetFilePointer(file, target_offset, NULL, FILE_BEGIN);
1379     SetLastError(0xdeadbeef);
1380     target = dll_entry_point;
1381     ret = WriteFile(file, &target, sizeof(target), &dummy, NULL);
1382     ok(ret, "WriteFile error %d\n", GetLastError());
1383     CloseHandle(file);
1384
1385     SetLastError(0xdeadbeef);
1386     hmod = LoadLibrary(dll_name);
1387     ok(hmod != 0, "LoadLibrary error %d\n", GetLastError());
1388
1389     SetLastError(0xdeadbeef);
1390     stop_event = CreateEvent(NULL, TRUE, FALSE, NULL);
1391     ok(stop_event != 0, "CreateEvent error %d\n", GetLastError());
1392
1393     SetLastError(0xdeadbeef);
1394     thread = CreateThread(NULL, 0, mutex_thread_proc, event, 0, &dummy);
1395     ok(thread != 0, "CreateThread error %d\n", GetLastError());
1396     WaitForSingleObject(event, 3000);
1397     CloseHandle(thread);
1398
1399     ResetEvent(event);
1400
1401     SetLastError(0xdeadbeef);
1402     thread = CreateThread(NULL, 0, semaphore_thread_proc, event, 0, &dummy);
1403     ok(thread != 0, "CreateThread error %d\n", GetLastError());
1404     WaitForSingleObject(event, 3000);
1405     CloseHandle(thread);
1406
1407     ResetEvent(event);
1408     Sleep(100);
1409
1410     ok(attached_thread_count == 2, "attached thread count should be 2\n");
1411     for (i = 0; i < attached_thread_count; i++)
1412     {
1413         ret = GetExitCodeThread(attached_thread[i], &code);
1414         trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
1415         ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
1416         ok(code == STILL_ACTIVE, "expected thread exit code STILL_ACTIVE, got %u\n", code);
1417     }
1418
1419     ret = WaitForSingleObject(attached_thread[0], 0);
1420     ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1421     ret = WaitForSingleObject(attached_thread[1], 0);
1422     ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1423
1424     ret = WaitForSingleObject(event, 0);
1425     ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1426     ret = WaitForSingleObject(mutex, 0);
1427     ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1428     ret = WaitForSingleObject(semaphore, 0);
1429     ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1430
1431     ret = pRtlDllShutdownInProgress();
1432     ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1433
1434     SetLastError(0xdeadbeef);
1435     process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
1436     ok(process != NULL, "OpenProcess error %d\n", GetLastError());
1437
1438     SetLastError(0xdeadbeef);
1439     ret = TerminateProcess(0, 195);
1440     ok(!ret, "TerminateProcess(0) should fail\n");
1441     ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
1442
1443     Sleep(100);
1444
1445     affinity = 1;
1446     ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
1447     ok(!ret, "NtSetInformationProcess error %#x\n", ret);
1448
1449     switch (test_dll_phase)
1450     {
1451     case 0:
1452         ret = pRtlDllShutdownInProgress();
1453         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1454
1455         trace("call NtTerminateProcess(0, 195)\n");
1456         ret = pNtTerminateProcess(0, 195);
1457         ok(!ret, "NtTerminateProcess error %#x\n", ret);
1458
1459         memset(&pbi, 0, sizeof(pbi));
1460         ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
1461         ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
1462         ok(pbi.ExitStatus == STILL_ACTIVE, "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus);
1463         affinity = 1;
1464         ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
1465         ok(!ret, "NtSetInformationProcess error %#x\n", ret);
1466
1467         ret = pRtlDllShutdownInProgress();
1468         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1469
1470         hmod = GetModuleHandle(dll_name);
1471         ok(hmod != 0, "DLL should not be unloaded\n");
1472
1473         SetLastError(0xdeadbeef);
1474         thread = CreateThread(NULL, 0, noop_thread_proc, &dummy, 0, &ret);
1475 todo_wine
1476         ok(!thread || broken(thread != 0) /* before win7 */, "CreateThread should fail\n");
1477         if (!thread)
1478             ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1479         else
1480         {
1481             ret = WaitForSingleObject(thread, 1000);
1482             ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1483             CloseHandle(thread);
1484         }
1485
1486         trace("call LdrShutdownProcess()\n");
1487         pLdrShutdownProcess();
1488
1489         ret = pRtlDllShutdownInProgress();
1490         ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
1491
1492         hmod = GetModuleHandle(dll_name);
1493         ok(hmod != 0, "DLL should not be unloaded\n");
1494
1495         memset(&pbi, 0, sizeof(pbi));
1496         ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
1497         ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
1498         ok(pbi.ExitStatus == STILL_ACTIVE, "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus);
1499         affinity = 1;
1500         ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
1501         ok(!ret, "NtSetInformationProcess error %#x\n", ret);
1502         break;
1503
1504     case 1:
1505     case 2: /* ExitProcess will be called by the PROCESS_DETACH handler */
1506         ret = pRtlDllShutdownInProgress();
1507         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1508
1509         trace("call FreeLibrary(%p)\n", hmod);
1510         SetLastError(0xdeadbeef);
1511         ret = FreeLibrary(hmod);
1512         ok(ret, "FreeLibrary error %d\n", GetLastError());
1513         hmod = GetModuleHandle(dll_name);
1514         ok(!hmod, "DLL should be unloaded\n");
1515
1516         if (test_dll_phase == 2)
1517             ok(0, "FreeLibrary+ExitProcess should never return\n");
1518
1519         ret = pRtlDllShutdownInProgress();
1520         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1521
1522         break;
1523
1524     case 3:
1525         trace("signalling thread exit\n");
1526         SetEvent(stop_event);
1527         CloseHandle(stop_event);
1528         break;
1529
1530     default:
1531         assert(0);
1532         break;
1533     }
1534
1535     if (test_dll_phase == 0) expected_code = 195;
1536     else if (test_dll_phase == 3) expected_code = 196;
1537     else expected_code = STILL_ACTIVE;
1538
1539     if (expected_code == STILL_ACTIVE)
1540     {
1541         ret = WaitForSingleObject(attached_thread[0], 100);
1542         ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1543         ret = WaitForSingleObject(attached_thread[1], 100);
1544         ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1545     }
1546     else
1547     {
1548         ret = WaitForSingleObject(attached_thread[0], 100);
1549         ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1550         ret = WaitForSingleObject(attached_thread[1], 100);
1551         ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1552     }
1553
1554     for (i = 0; i < attached_thread_count; i++)
1555     {
1556         ret = GetExitCodeThread(attached_thread[i], &code);
1557         trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
1558         ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
1559         ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code);
1560     }
1561
1562     *child_failures = winetest_get_failures();
1563
1564     trace("call ExitProcess()\n");
1565     ExitProcess(195);
1566 }
1567
1568 static void test_ExitProcess(void)
1569 {
1570 #include "pshpack1.h"
1571 #ifdef __x86_64__
1572     static struct section_data
1573     {
1574         BYTE mov_rax[2];
1575         void *target;
1576         BYTE jmp_rax[2];
1577     } section_data = { { 0x48,0xb8 }, dll_entry_point, { 0xff,0xe0 } };
1578 #else
1579     static struct section_data
1580     {
1581         BYTE mov_eax;
1582         void *target;
1583         BYTE jmp_eax[2];
1584     } section_data = { 0xb8, dll_entry_point, { 0xff,0xe0 } };
1585 #endif
1586 #include "poppack.h"
1587     static const char filler[0x1000];
1588     DWORD dummy, file_align;
1589     HANDLE file, thread, hmap;
1590     char temp_path[MAX_PATH], dll_name[MAX_PATH], cmdline[MAX_PATH * 2];
1591     DWORD ret, target_offset, old_prot;
1592     char **argv, buf[256];
1593     PROCESS_INFORMATION pi;
1594     STARTUPINFO si = { sizeof(si) };
1595     CONTEXT ctx;
1596     struct PROCESS_BASIC_INFORMATION_PRIVATE pbi;
1597     DWORD_PTR affinity;
1598     void *addr;
1599     LARGE_INTEGER offset;
1600     SIZE_T size;
1601
1602 #if !defined(__i386__) && !defined(__x86_64__)
1603     skip("x86 specific ExitProcess test\n");
1604     return;
1605 #endif
1606
1607     if (!pRtlDllShutdownInProgress)
1608     {
1609         win_skip("RtlDllShutdownInProgress is not available on this platform (XP+)\n");
1610         return;
1611     }
1612     if (!pNtQueryInformationProcess || !pNtSetInformationProcess)
1613     {
1614         win_skip("NtQueryInformationProcess/NtSetInformationProcess are not available on this platform\n");
1615         return;
1616     }
1617     if (!pNtAllocateVirtualMemory || !pNtFreeVirtualMemory)
1618     {
1619         win_skip("NtAllocateVirtualMemory/NtFreeVirtualMemory are not available on this platform\n");
1620         return;
1621     }
1622
1623     /* prevent displaying of the "Unable to load this DLL" message box */
1624     SetErrorMode(SEM_FAILCRITICALERRORS);
1625
1626     GetTempPath(MAX_PATH, temp_path);
1627     GetTempFileName(temp_path, "ldr", 0, dll_name);
1628
1629     /*trace("creating %s\n", dll_name);*/
1630     file = CreateFile(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
1631     if (file == INVALID_HANDLE_VALUE)
1632     {
1633         ok(0, "could not create %s\n", dll_name);
1634         return;
1635     }
1636
1637     SetLastError(0xdeadbeef);
1638     ret = WriteFile(file, &dos_header, sizeof(dos_header), &dummy, NULL);
1639     ok(ret, "WriteFile error %d\n", GetLastError());
1640
1641     nt_header.FileHeader.NumberOfSections = 1;
1642     nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1643     nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED;
1644
1645     nt_header.OptionalHeader.AddressOfEntryPoint = 0x1000;
1646     nt_header.OptionalHeader.SectionAlignment = 0x1000;
1647     nt_header.OptionalHeader.FileAlignment = 0x200;
1648     nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000;
1649     nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
1650     SetLastError(0xdeadbeef);
1651     ret = WriteFile(file, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
1652     ok(ret, "WriteFile error %d\n", GetLastError());
1653     SetLastError(0xdeadbeef);
1654     ret = WriteFile(file, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
1655     ok(ret, "WriteFile error %d\n", GetLastError());
1656
1657     section.SizeOfRawData = sizeof(section_data);
1658     section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
1659     section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
1660     section.Misc.VirtualSize = sizeof(section_data);
1661     section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
1662     SetLastError(0xdeadbeef);
1663     ret = WriteFile(file, &section, sizeof(section), &dummy, NULL);
1664     ok(ret, "WriteFile error %d\n", GetLastError());
1665
1666     file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
1667     assert(file_align < sizeof(filler));
1668     SetLastError(0xdeadbeef);
1669     ret = WriteFile(file, filler, file_align, &dummy, NULL);
1670     ok(ret, "WriteFile error %d\n", GetLastError());
1671
1672     target_offset = SetFilePointer(file, 0, NULL, FILE_CURRENT) + FIELD_OFFSET(struct section_data, target);
1673
1674     /* section data */
1675     SetLastError(0xdeadbeef);
1676     ret = WriteFile(file, &section_data, sizeof(section_data), &dummy, NULL);
1677     ok(ret, "WriteFile error %d\n", GetLastError());
1678
1679     CloseHandle(file);
1680
1681     winetest_get_mainargs(&argv);
1682
1683     /* phase 0 */
1684     *child_failures = -1;
1685     sprintf(cmdline, "\"%s\" loader %s %u 0", argv[0], dll_name, target_offset);
1686     ret = CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1687     ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
1688     ret = WaitForSingleObject(pi.hProcess, 30000);
1689     ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
1690     GetExitCodeProcess(pi.hProcess, &ret);
1691     ok(ret == 195, "expected exit code 195, got %u\n", ret);
1692     if (*child_failures)
1693     {
1694         trace("%d failures in child process\n", *child_failures);
1695         winetest_add_failures(*child_failures);
1696     }
1697     CloseHandle(pi.hThread);
1698     CloseHandle(pi.hProcess);
1699
1700     /* phase 1 */
1701     *child_failures = -1;
1702     sprintf(cmdline, "\"%s\" loader %s %u 1", argv[0], dll_name, target_offset);
1703     ret = CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1704     ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
1705     ret = WaitForSingleObject(pi.hProcess, 30000);
1706     ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
1707     GetExitCodeProcess(pi.hProcess, &ret);
1708     ok(ret == 195, "expected exit code 195, got %u\n", ret);
1709     if (*child_failures)
1710     {
1711         trace("%d failures in child process\n", *child_failures);
1712         winetest_add_failures(*child_failures);
1713     }
1714     CloseHandle(pi.hThread);
1715     CloseHandle(pi.hProcess);
1716
1717     /* phase 2 */
1718     *child_failures = -1;
1719     sprintf(cmdline, "\"%s\" loader %s %u 2", argv[0], dll_name, target_offset);
1720     ret = CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1721     ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
1722     ret = WaitForSingleObject(pi.hProcess, 30000);
1723     ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
1724     GetExitCodeProcess(pi.hProcess, &ret);
1725     ok(ret == 197, "expected exit code 197, got %u\n", ret);
1726     if (*child_failures)
1727     {
1728         trace("%d failures in child process\n", *child_failures);
1729         winetest_add_failures(*child_failures);
1730     }
1731     CloseHandle(pi.hThread);
1732     CloseHandle(pi.hProcess);
1733
1734     /* phase 3 */
1735     *child_failures = -1;
1736     sprintf(cmdline, "\"%s\" loader %s %u 3", argv[0], dll_name, target_offset);
1737     ret = CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1738     ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
1739     ret = WaitForSingleObject(pi.hProcess, 30000);
1740     ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
1741     GetExitCodeProcess(pi.hProcess, &ret);
1742     ok(ret == 195, "expected exit code 195, got %u\n", ret);
1743     if (*child_failures)
1744     {
1745         trace("%d failures in child process\n", *child_failures);
1746         winetest_add_failures(*child_failures);
1747     }
1748     CloseHandle(pi.hThread);
1749     CloseHandle(pi.hProcess);
1750
1751     /* test remote process termination */
1752     SetLastError(0xdeadbeef);
1753     ret = CreateProcess(argv[0], NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
1754     ok(ret, "CreateProcess(%s) error %d\n", argv[0], GetLastError());
1755
1756     SetLastError(0xdeadbeef);
1757     addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
1758     ok(addr != NULL, "VirtualAllocEx error %d\n", GetLastError());
1759     SetLastError(0xdeadbeef);
1760     ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READONLY, &old_prot);
1761     ok(ret, "VirtualProtectEx error %d\n", GetLastError());
1762     ok(old_prot == PAGE_READWRITE, "expected PAGE_READWRITE, got %#x\n", old_prot);
1763     SetLastError(0xdeadbeef);
1764     ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size);
1765     ok(ret, "ReadProcessMemory error %d\n", GetLastError());
1766     ok(size == 4, "expected 4, got %lu\n", size);
1767
1768     SetLastError(0xdeadbeef);
1769     hmap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
1770     ok(hmap != 0, "CreateFileMapping error %d\n", GetLastError());
1771
1772     offset.u.LowPart = 0;
1773     offset.u.HighPart = 0;
1774     addr = NULL;
1775     size = 0;
1776     ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset,
1777                               &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1778     ok(!ret, "NtMapViewOfSection error %#x\n", ret);
1779     ret = pNtUnmapViewOfSection(pi.hProcess, addr);
1780     ok(!ret, "NtUnmapViewOfSection error %#x\n", ret);
1781
1782     SetLastError(0xdeadbeef);
1783     thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
1784     ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError());
1785     SetLastError(0xdeadbeef);
1786     ctx.ContextFlags = CONTEXT_INTEGER;
1787     ret = GetThreadContext(thread, &ctx);
1788     ok(ret, "GetThreadContext error %d\n", GetLastError());
1789     SetLastError(0xdeadbeef);
1790     ctx.ContextFlags = CONTEXT_INTEGER;
1791     ret = SetThreadContext(thread, &ctx);
1792     ok(ret, "SetThreadContext error %d\n", GetLastError());
1793     SetLastError(0xdeadbeef);
1794     ret = SetThreadPriority(thread, 0);
1795     ok(ret, "SetThreadPriority error %d\n", GetLastError());
1796
1797     SetLastError(0xdeadbeef);
1798     ret = TerminateThread(thread, 199);
1799     ok(ret, "TerminateThread error %d\n", GetLastError());
1800     /* Calling GetExitCodeThread() without waiting for thread termination
1801      * leads to different results due to a race condition.
1802      */
1803     ret = WaitForSingleObject(thread, 100);
1804     ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
1805     GetExitCodeThread(thread, &ret);
1806     ok(ret == 199, "expected exit code 199, got %u\n", ret);
1807
1808     SetLastError(0xdeadbeef);
1809     ret = TerminateProcess(pi.hProcess, 198);
1810     ok(ret, "TerminateProcess error %d\n", GetLastError());
1811     /* Checking process state without waiting for process termination
1812      * leads to different results due to a race condition.
1813      */
1814     ret = WaitForSingleObject(pi.hProcess, 100);
1815     ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
1816
1817     memset(&pbi, 0, sizeof(pbi));
1818     ret = pNtQueryInformationProcess(pi.hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
1819     ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
1820     ok(pbi.ExitStatus == 198, "expected 198, got %lu\n", pbi.ExitStatus);
1821     affinity = 1;
1822     ret = pNtSetInformationProcess(pi.hProcess, ProcessAffinityMask, &affinity, sizeof(affinity));
1823 todo_wine
1824     ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#x\n", ret);
1825
1826     SetLastError(0xdeadbeef);
1827     ctx.ContextFlags = CONTEXT_INTEGER;
1828     ret = GetThreadContext(thread, &ctx);
1829     ok(!ret || broken(ret) /* XP 64-bit */, "GetThreadContext should fail\n");
1830     if (!ret)
1831         ok(GetLastError() == ERROR_INVALID_PARAMETER ||
1832            GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
1833            GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
1834            "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1835     SetLastError(0xdeadbeef);
1836     ctx.ContextFlags = CONTEXT_INTEGER;
1837     ret = SetThreadContext(thread, &ctx);
1838     ok(!ret || broken(ret) /* XP 64-bit */, "SetThreadContext should fail\n");
1839     if (!ret)
1840         ok(GetLastError() == ERROR_ACCESS_DENIED ||
1841            GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
1842            GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
1843            "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1844     SetLastError(0xdeadbeef);
1845     ret = SetThreadPriority(thread, 0);
1846     ok(ret, "SetThreadPriority error %d\n", GetLastError());
1847     CloseHandle(thread);
1848
1849     SetLastError(0xdeadbeef);
1850     ctx.ContextFlags = CONTEXT_INTEGER;
1851     ret = GetThreadContext(pi.hThread, &ctx);
1852     ok(!ret || broken(ret) /* XP 64-bit */, "GetThreadContext should fail\n");
1853     if (!ret)
1854         ok(GetLastError() == ERROR_INVALID_PARAMETER ||
1855            GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
1856            GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
1857            "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1858     SetLastError(0xdeadbeef);
1859     ctx.ContextFlags = CONTEXT_INTEGER;
1860     ret = SetThreadContext(pi.hThread, &ctx);
1861     ok(!ret || broken(ret) /* XP 64-bit */, "SetThreadContext should fail\n");
1862     if (!ret)
1863         ok(GetLastError() == ERROR_ACCESS_DENIED ||
1864            GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
1865            GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
1866            "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1867     SetLastError(0xdeadbeef);
1868     ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READWRITE, &old_prot);
1869     ok(!ret, "VirtualProtectEx should fail\n");
1870     ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1871     SetLastError(0xdeadbeef);
1872     size = 0;
1873     ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size);
1874     ok(!ret, "ReadProcessMemory should fail\n");
1875     ok(GetLastError() == ERROR_PARTIAL_COPY || GetLastError() == ERROR_ACCESS_DENIED,
1876        "expected ERROR_PARTIAL_COPY, got %d\n", GetLastError());
1877     ok(!size, "expected 0, got %lu\n", size);
1878     SetLastError(0xdeadbeef);
1879     ret = VirtualFreeEx(pi.hProcess, addr, 0, MEM_RELEASE);
1880     ok(!ret, "VirtualFreeEx should fail\n");
1881     ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1882     SetLastError(0xdeadbeef);
1883     addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
1884     ok(!addr, "VirtualAllocEx should fail\n");
1885     ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1886
1887     offset.u.LowPart = 0;
1888     offset.u.HighPart = 0;
1889     addr = NULL;
1890     size = 0;
1891     ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset,
1892                               &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1893 todo_wine
1894     ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#x\n", ret);
1895
1896     SetLastError(0xdeadbeef);
1897     thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
1898     ok(!thread, "CreateRemoteThread should fail\n");
1899     ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1900
1901     SetLastError(0xdeadbeef);
1902     ret = DebugActiveProcess(pi.dwProcessId);
1903     ok(!ret, "DebugActiveProcess should fail\n");
1904     ok(GetLastError() == ERROR_ACCESS_DENIED /* 64-bit */ || GetLastError() == ERROR_NOT_SUPPORTED /* 32-bit */,
1905       "ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1906
1907     GetExitCodeProcess(pi.hProcess, &ret);
1908     ok(ret == 198 || broken(ret != 198) /* some 32-bit XP version in a VM returns random exit code */,
1909        "expected exit code 198, got %u\n", ret);
1910     CloseHandle(pi.hThread);
1911     CloseHandle(pi.hProcess);
1912
1913     ret = DeleteFile(dll_name);
1914     ok(ret, "DeleteFile error %d\n", GetLastError());
1915 }
1916
1917 START_TEST(loader)
1918 {
1919     int argc;
1920     char **argv;
1921     HANDLE mapping;
1922
1923     pNtMapViewOfSection = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtMapViewOfSection");
1924     pNtUnmapViewOfSection = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtUnmapViewOfSection");
1925     pNtTerminateProcess = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtTerminateProcess");
1926     pNtQueryInformationProcess = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryInformationProcess");
1927     pNtSetInformationProcess = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtSetInformationProcess");
1928     pLdrShutdownProcess = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "LdrShutdownProcess");
1929     pRtlDllShutdownInProgress = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlDllShutdownInProgress");
1930     pNtAllocateVirtualMemory = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtAllocateVirtualMemory");
1931     pNtFreeVirtualMemory = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtFreeVirtualMemory");
1932
1933     mapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_loader");
1934     ok(mapping != 0, "CreateFileMapping failed\n");
1935     child_failures = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 4096);
1936     if (*child_failures == -1)
1937     {
1938         is_child = 1;
1939         *child_failures = 0;
1940     }
1941     else
1942         *child_failures = -1;
1943
1944     argc = winetest_get_mainargs(&argv);
1945     if (argc > 4)
1946     {
1947         test_dll_phase = atoi(argv[4]);
1948         child_process(argv[2], atol(argv[3]));
1949         return;
1950     }
1951
1952     test_Loader();
1953     test_ImportDescriptors();
1954     test_section_access();
1955     test_ExitProcess();
1956 }