wininet: Load persistent cookies from other paths in get_cookie function.
[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) expected_code = 195;
1123         else if (test_dll_phase == 3) expected_code = 196;
1124         else expected_code = STILL_ACTIVE;
1125
1126         if (test_dll_phase == 3 || test_dll_phase == 4)
1127         {
1128             ret = pRtlDllShutdownInProgress();
1129             ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
1130         }
1131         else
1132         {
1133             ret = pRtlDllShutdownInProgress();
1134
1135             /* FIXME: remove once Wine is fixed */
1136             if (expected_code == STILL_ACTIVE || expected_code == 196)
1137                 ok(!ret || broken(ret) /* before Vista */, "RtlDllShutdownInProgress returned %d\n", ret);
1138             else
1139             todo_wine
1140                 ok(!ret || broken(ret) /* before Vista */, "RtlDllShutdownInProgress returned %d\n", ret);
1141         }
1142
1143         ok(attached_thread_count >= 2, "attached thread count should be >= 2\n");
1144
1145         for (i = 0; i < attached_thread_count; i++)
1146         {
1147             ret = GetExitCodeThread(attached_thread[i], &code);
1148             trace("dll: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
1149             ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
1150             ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code);
1151         }
1152
1153         ret = WaitForSingleObject(event, 0);
1154         ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1155
1156         ret = WaitForSingleObject(mutex, 0);
1157         if (expected_code == STILL_ACTIVE)
1158             ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1159         else
1160             ok(ret == WAIT_ABANDONED, "expected WAIT_ABANDONED, got %#x\n", ret);
1161
1162         /* semaphore is not abandoned on thread termination */
1163         ret = WaitForSingleObject(semaphore, 0);
1164         ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1165
1166         if (expected_code == STILL_ACTIVE)
1167         {
1168             ret = WaitForSingleObject(attached_thread[0], 0);
1169             ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1170             ret = WaitForSingleObject(attached_thread[1], 0);
1171             ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1172         }
1173         else
1174         {
1175             ret = WaitForSingleObject(attached_thread[0], 0);
1176             ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1177             ret = WaitForSingleObject(attached_thread[1], 0);
1178             ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1179         }
1180
1181         /* win7 doesn't allow to create a thread during process shutdown,
1182          * earlier Windows versions allow it.
1183          */
1184         noop_thread_started = 0;
1185         SetLastError(0xdeadbeef);
1186         handle = CreateThread(NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
1187         /* manual call to LdrShutdownProcess doesn't prevent thread creation */
1188         if (param && test_dll_phase != 4)
1189         {
1190             ok(!handle || broken(handle != 0) /* before win7 */, "CreateThread should fail\n");
1191             if (!handle)
1192                 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1193             else
1194             {
1195                 ret = WaitForSingleObject(handle, 1000);
1196                 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1197                 CloseHandle(handle);
1198             }
1199         }
1200         else
1201         {
1202             /* FIXME: remove once Wine is fixed */
1203             if (test_dll_phase == 4) todo_wine
1204             {
1205             ok(handle != 0, "CreateThread error %d\n", GetLastError());
1206             }
1207             else
1208             {
1209             ok(handle != 0, "CreateThread error %d\n", GetLastError());
1210             ret = WaitForSingleObject(handle, 1000);
1211             ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1212             ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n");
1213             }
1214             CloseHandle(handle);
1215         }
1216
1217         SetLastError(0xdeadbeef);
1218         process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
1219         ok(process != NULL, "OpenProcess error %d\n", GetLastError());
1220
1221         noop_thread_started = 0;
1222         SetLastError(0xdeadbeef);
1223         handle = CreateRemoteThread(process, NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
1224         /* manual call to LdrShutdownProcess doesn't prevent thread creation */
1225         if (param && test_dll_phase != 4)
1226         {
1227             ok(!handle || broken(handle != 0) /* before win7 */, "CreateRemoteThread should fail\n");
1228             if (!handle)
1229                 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1230             else
1231             {
1232                 ret = WaitForSingleObject(handle, 1000);
1233                 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1234                 CloseHandle(handle);
1235             }
1236         }
1237         else
1238         {
1239             /* FIXME: remove once Wine is fixed */
1240             if (test_dll_phase == 4) todo_wine
1241             {
1242             ok(handle != 0, "CreateRemoteThread error %d\n", GetLastError());
1243             }
1244             else
1245             {
1246             ok(handle != 0, "CreateRemoteThread error %d\n", GetLastError());
1247             ret = WaitForSingleObject(handle, 1000);
1248             ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1249             ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n");
1250             }
1251             CloseHandle(handle);
1252         }
1253
1254         SetLastError(0xdeadbeef);
1255         handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
1256         ok(handle != 0, "CreateFileMapping error %d\n", GetLastError());
1257
1258         offset.u.LowPart = 0;
1259         offset.u.HighPart = 0;
1260         addr = NULL;
1261         size = 0;
1262         ret = pNtMapViewOfSection(handle, process, &addr, 0, 0, &offset,
1263                                   &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1264         ok(ret == STATUS_SUCCESS, "NtMapViewOfSection error %#x\n", ret);
1265         ret = pNtUnmapViewOfSection(process, addr);
1266         ok(ret == STATUS_SUCCESS, "NtUnmapViewOfSection error %#x\n", ret);
1267
1268         CloseHandle(handle);
1269         CloseHandle(process);
1270
1271         handle = GetModuleHandle("winver.exe");
1272         ok(!handle, "winver.exe shouldn't be loaded yet\n");
1273         SetLastError(0xdeadbeef);
1274         handle = LoadLibrary("winver.exe");
1275         ok(handle != 0, "LoadLibrary error %d\n", GetLastError());
1276         SetLastError(0xdeadbeef);
1277         ret = FreeLibrary(handle);
1278         ok(ret, "FreeLibrary error %d\n", GetLastError());
1279         handle = GetModuleHandle("winver.exe");
1280         /* manual call to LdrShutdownProcess doesn't prevent module unloading */
1281         if (param && test_dll_phase != 4)
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;
1354     HMODULE hmod;
1355     NTSTATUS status;
1356
1357     trace("phase %d: writing %p at %#x\n", test_dll_phase, dll_entry_point, target_offset);
1358
1359     SetLastError(0xdeadbeef);
1360     mutex = CreateMutex(NULL, FALSE, NULL);
1361     ok(mutex != 0, "CreateMutex error %d\n", GetLastError());
1362
1363     SetLastError(0xdeadbeef);
1364     semaphore = CreateSemaphore(NULL, 1, 1, NULL);
1365     ok(semaphore != 0, "CreateSemaphore error %d\n", GetLastError());
1366
1367     SetLastError(0xdeadbeef);
1368     event = CreateEvent(NULL, TRUE, FALSE, NULL);
1369     ok(event != 0, "CreateEvent error %d\n", GetLastError());
1370
1371     file = CreateFile(dll_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1372     if (file == INVALID_HANDLE_VALUE)
1373     {
1374         ok(0, "could not open %s\n", dll_name);
1375         return;
1376     }
1377     SetFilePointer(file, target_offset, NULL, FILE_BEGIN);
1378     SetLastError(0xdeadbeef);
1379     target = dll_entry_point;
1380     ret = WriteFile(file, &target, sizeof(target), &dummy, NULL);
1381     ok(ret, "WriteFile error %d\n", GetLastError());
1382     CloseHandle(file);
1383
1384     SetLastError(0xdeadbeef);
1385     hmod = LoadLibrary(dll_name);
1386     ok(hmod != 0, "LoadLibrary error %d\n", GetLastError());
1387
1388     SetLastError(0xdeadbeef);
1389     stop_event = CreateEvent(NULL, TRUE, FALSE, NULL);
1390     ok(stop_event != 0, "CreateEvent error %d\n", GetLastError());
1391
1392     SetLastError(0xdeadbeef);
1393     thread = CreateThread(NULL, 0, mutex_thread_proc, event, 0, &dummy);
1394     ok(thread != 0, "CreateThread error %d\n", GetLastError());
1395     WaitForSingleObject(event, 3000);
1396     CloseHandle(thread);
1397
1398     ResetEvent(event);
1399
1400     SetLastError(0xdeadbeef);
1401     thread = CreateThread(NULL, 0, semaphore_thread_proc, event, 0, &dummy);
1402     ok(thread != 0, "CreateThread error %d\n", GetLastError());
1403     WaitForSingleObject(event, 3000);
1404     CloseHandle(thread);
1405
1406     ResetEvent(event);
1407     Sleep(100);
1408
1409     ok(attached_thread_count == 2, "attached thread count should be 2\n");
1410     for (i = 0; i < attached_thread_count; i++)
1411     {
1412         ret = GetExitCodeThread(attached_thread[i], &code);
1413         trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
1414         ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
1415         ok(code == STILL_ACTIVE, "expected thread exit code STILL_ACTIVE, got %u\n", code);
1416     }
1417
1418     ret = WaitForSingleObject(attached_thread[0], 0);
1419     ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1420     ret = WaitForSingleObject(attached_thread[1], 0);
1421     ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1422
1423     ret = WaitForSingleObject(event, 0);
1424     ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1425     ret = WaitForSingleObject(mutex, 0);
1426     ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1427     ret = WaitForSingleObject(semaphore, 0);
1428     ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1429
1430     ret = pRtlDllShutdownInProgress();
1431     ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1432
1433     SetLastError(0xdeadbeef);
1434     ret = TerminateProcess(0, 195);
1435     ok(!ret, "TerminateProcess(0) should fail\n");
1436     ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
1437
1438     Sleep(100);
1439
1440     switch (test_dll_phase)
1441     {
1442     case 0:
1443         ret = pRtlDllShutdownInProgress();
1444         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1445
1446         trace("call NtTerminateProcess(0, 195)\n");
1447         status = pNtTerminateProcess(0, 195);
1448         ok(!status, "NtTerminateProcess error %#x\n", status);
1449
1450         ret = pRtlDllShutdownInProgress();
1451         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1452
1453         SetLastError(0xdeadbeef);
1454         thread = CreateThread(NULL, 0, noop_thread_proc, &dummy, 0, &ret);
1455 todo_wine
1456         ok(!thread || broken(thread != 0) /* before win7 */, "CreateThread should fail\n");
1457         if (!thread)
1458             ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1459         else
1460         {
1461             ret = WaitForSingleObject(thread, 1000);
1462             ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1463             CloseHandle(thread);
1464         }
1465
1466         break;
1467
1468     case 1:
1469     case 2: /* ExitProcess will be called by the PROCESS_DETACH handler */
1470         ret = pRtlDllShutdownInProgress();
1471         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1472
1473         trace("call FreeLibrary(%p)\n", hmod);
1474         FreeLibrary(hmod);
1475
1476         ret = pRtlDllShutdownInProgress();
1477         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1478
1479         break;
1480
1481     case 3:
1482         trace("signalling thread exit\n");
1483         SetEvent(stop_event);
1484         CloseHandle(stop_event);
1485         break;
1486
1487     case 4:
1488         ret = pRtlDllShutdownInProgress();
1489         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1490
1491         trace("call LdrShutdownProcess()\n");
1492         pLdrShutdownProcess();
1493
1494         ret = pRtlDllShutdownInProgress();
1495         ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
1496
1497         break;
1498
1499     default:
1500         assert(0);
1501         break;
1502     }
1503
1504     Sleep(100);
1505
1506     if (test_dll_phase == 0) expected_code = 195;
1507     else if (test_dll_phase == 3) expected_code = 196;
1508     else expected_code = STILL_ACTIVE;
1509
1510     if (expected_code == STILL_ACTIVE)
1511     {
1512         ret = WaitForSingleObject(attached_thread[0], 0);
1513         ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1514         ret = WaitForSingleObject(attached_thread[1], 0);
1515         ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1516     }
1517     else
1518     {
1519         ret = WaitForSingleObject(attached_thread[0], 50);
1520         ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1521         ret = WaitForSingleObject(attached_thread[1], 50);
1522         ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1523     }
1524
1525     for (i = 0; i < attached_thread_count; i++)
1526     {
1527         ret = GetExitCodeThread(attached_thread[i], &code);
1528         trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
1529         ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
1530         ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code);
1531     }
1532
1533     *child_failures = winetest_get_failures();
1534
1535     trace("call ExitProcess()\n");
1536     ExitProcess(195);
1537 }
1538
1539 static void test_ExitProcess(void)
1540 {
1541 #include "pshpack1.h"
1542 #ifdef __x86_64__
1543     static struct section_data
1544     {
1545         BYTE mov_rax[2];
1546         void *target;
1547         BYTE jmp_rax[2];
1548     } section_data = { { 0x48,0xb8 }, dll_entry_point, { 0xff,0xe0 } };
1549 #else
1550     static struct section_data
1551     {
1552         BYTE mov_eax;
1553         void *target;
1554         BYTE jmp_eax[2];
1555     } section_data = { 0xb8, dll_entry_point, { 0xff,0xe0 } };
1556 #endif
1557 #include "poppack.h"
1558     static const char filler[0x1000];
1559     DWORD dummy, file_align;
1560     HANDLE file;
1561     char temp_path[MAX_PATH], dll_name[MAX_PATH], cmdline[MAX_PATH * 2];
1562     DWORD ret, target_offset;
1563     char **argv;
1564     PROCESS_INFORMATION pi;
1565     STARTUPINFO si = { sizeof(si) };
1566
1567 #if !defined(__i386__) && !defined(__x86_64__)
1568     skip("x86 specific ExitProcess test\n");
1569     return;
1570 #endif
1571
1572     if (!pRtlDllShutdownInProgress)
1573     {
1574         skip("RtlDllShutdownInProgress is not available on this platform (XP+)\n");
1575         return;
1576     }
1577
1578     /* prevent displaying of the "Unable to load this DLL" message box */
1579     SetErrorMode(SEM_FAILCRITICALERRORS);
1580
1581     GetTempPath(MAX_PATH, temp_path);
1582     GetTempFileName(temp_path, "ldr", 0, dll_name);
1583
1584     /*trace("creating %s\n", dll_name);*/
1585     file = CreateFile(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
1586     if (file == INVALID_HANDLE_VALUE)
1587     {
1588         ok(0, "could not create %s\n", dll_name);
1589         return;
1590     }
1591
1592     SetLastError(0xdeadbeef);
1593     ret = WriteFile(file, &dos_header, sizeof(dos_header), &dummy, NULL);
1594     ok(ret, "WriteFile error %d\n", GetLastError());
1595
1596     nt_header.FileHeader.NumberOfSections = 1;
1597     nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1598     nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED;
1599
1600     nt_header.OptionalHeader.AddressOfEntryPoint = 0x1000;
1601     nt_header.OptionalHeader.SectionAlignment = 0x1000;
1602     nt_header.OptionalHeader.FileAlignment = 0x200;
1603     nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000;
1604     nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
1605     SetLastError(0xdeadbeef);
1606     ret = WriteFile(file, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
1607     ok(ret, "WriteFile error %d\n", GetLastError());
1608     SetLastError(0xdeadbeef);
1609     ret = WriteFile(file, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
1610     ok(ret, "WriteFile error %d\n", GetLastError());
1611
1612     section.SizeOfRawData = sizeof(section_data);
1613     section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
1614     section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
1615     section.Misc.VirtualSize = sizeof(section_data);
1616     section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
1617     SetLastError(0xdeadbeef);
1618     ret = WriteFile(file, &section, sizeof(section), &dummy, NULL);
1619     ok(ret, "WriteFile error %d\n", GetLastError());
1620
1621     file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
1622     assert(file_align < sizeof(filler));
1623     SetLastError(0xdeadbeef);
1624     ret = WriteFile(file, filler, file_align, &dummy, NULL);
1625     ok(ret, "WriteFile error %d\n", GetLastError());
1626
1627     target_offset = SetFilePointer(file, 0, NULL, FILE_CURRENT) + FIELD_OFFSET(struct section_data, target);
1628
1629     /* section data */
1630     SetLastError(0xdeadbeef);
1631     ret = WriteFile(file, &section_data, sizeof(section_data), &dummy, NULL);
1632     ok(ret, "WriteFile error %d\n", GetLastError());
1633
1634     CloseHandle(file);
1635
1636     winetest_get_mainargs(&argv);
1637
1638     /* phase 0 */
1639     *child_failures = -1;
1640     sprintf(cmdline, "\"%s\" loader %s %u 0", argv[0], dll_name, target_offset);
1641     ret = CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1642     ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
1643     ret = WaitForSingleObject(pi.hProcess, 30000);
1644     ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
1645     GetExitCodeProcess(pi.hProcess, &ret);
1646     ok(ret == 195, "expected exit code 195, got %u\n", ret);
1647     if (*child_failures)
1648     {
1649         trace("%d failures in child process\n", *child_failures);
1650         winetest_add_failures(*child_failures);
1651     }
1652     CloseHandle(pi.hThread);
1653     CloseHandle(pi.hProcess);
1654
1655     /* phase 1 */
1656     *child_failures = -1;
1657     sprintf(cmdline, "\"%s\" loader %s %u 1", argv[0], dll_name, target_offset);
1658     ret = CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1659     ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
1660     ret = WaitForSingleObject(pi.hProcess, 30000);
1661     ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
1662     GetExitCodeProcess(pi.hProcess, &ret);
1663     ok(ret == 195, "expected exit code 195, got %u\n", ret);
1664     if (*child_failures)
1665     {
1666         trace("%d failures in child process\n", *child_failures);
1667         winetest_add_failures(*child_failures);
1668     }
1669     CloseHandle(pi.hThread);
1670     CloseHandle(pi.hProcess);
1671
1672     /* phase 2 */
1673     *child_failures = -1;
1674     sprintf(cmdline, "\"%s\" loader %s %u 2", argv[0], dll_name, target_offset);
1675     ret = CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1676     ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
1677     ret = WaitForSingleObject(pi.hProcess, 30000);
1678     ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
1679     GetExitCodeProcess(pi.hProcess, &ret);
1680     ok(ret == 197, "expected exit code 197, got %u\n", ret);
1681     if (*child_failures)
1682     {
1683         trace("%d failures in child process\n", *child_failures);
1684         winetest_add_failures(*child_failures);
1685     }
1686     CloseHandle(pi.hThread);
1687     CloseHandle(pi.hProcess);
1688
1689     /* phase 3 */
1690     *child_failures = -1;
1691     sprintf(cmdline, "\"%s\" loader %s %u 3", argv[0], dll_name, target_offset);
1692     ret = CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1693     ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
1694     ret = WaitForSingleObject(pi.hProcess, 30000);
1695     ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
1696     GetExitCodeProcess(pi.hProcess, &ret);
1697     ok(ret == 195, "expected exit code 195, got %u\n", ret);
1698     if (*child_failures)
1699     {
1700         trace("%d failures in child process\n", *child_failures);
1701         winetest_add_failures(*child_failures);
1702     }
1703     CloseHandle(pi.hThread);
1704     CloseHandle(pi.hProcess);
1705
1706     /* phase 4 */
1707     *child_failures = -1;
1708     sprintf(cmdline, "\"%s\" loader %s %u 4", argv[0], dll_name, target_offset);
1709     ret = CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1710     ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
1711     ret = WaitForSingleObject(pi.hProcess, 30000);
1712     ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
1713     GetExitCodeProcess(pi.hProcess, &ret);
1714 todo_wine
1715     ok(ret == 0 || broken(ret == 195) /* before win7 */, "expected exit code 0, got %u\n", ret);
1716     if (*child_failures)
1717     {
1718         trace("%d failures in child process\n", *child_failures);
1719         winetest_add_failures(*child_failures);
1720     }
1721     CloseHandle(pi.hThread);
1722     CloseHandle(pi.hProcess);
1723
1724     ret = DeleteFile(dll_name);
1725     ok(ret, "DeleteFile error %d\n", GetLastError());
1726 }
1727
1728 START_TEST(loader)
1729 {
1730     int argc;
1731     char **argv;
1732     HANDLE mapping;
1733
1734     pNtMapViewOfSection = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtMapViewOfSection");
1735     pNtUnmapViewOfSection = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtUnmapViewOfSection");
1736     pNtTerminateProcess = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtTerminateProcess");
1737     pLdrShutdownProcess = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "LdrShutdownProcess");
1738     pRtlDllShutdownInProgress = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlDllShutdownInProgress");
1739
1740     mapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_loader");
1741     ok(mapping != 0, "CreateFileMapping failed\n");
1742     child_failures = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 4096);
1743     if (*child_failures == -1)
1744     {
1745         is_child = 1;
1746         *child_failures = 0;
1747     }
1748     else
1749         *child_failures = -1;
1750
1751     argc = winetest_get_mainargs(&argv);
1752     if (argc > 4)
1753     {
1754         test_dll_phase = atoi(argv[4]);
1755         child_process(argv[2], atol(argv[3]));
1756         return;
1757     }
1758
1759     test_Loader();
1760     test_ImportDescriptors();
1761     test_section_access();
1762     test_ExitProcess();
1763 }