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