jscript: Store concatenated strings as a rope string to avoid useless copying.
[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 LONG noop_thread_started;
1046 static int test_dll_phase;
1047
1048 static DWORD WINAPI mutex_thread_proc(void *param)
1049 {
1050     DWORD ret;
1051
1052     ret = WaitForSingleObject(mutex, 0);
1053     ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1054
1055     SetEvent(param);
1056
1057     while (1)
1058     {
1059         trace("%04u: mutex_thread_proc: still alive\n", GetCurrentThreadId());
1060         if (WaitForSingleObject(stop_event, 50) != WAIT_TIMEOUT) break;
1061     }
1062
1063     trace("%04u: mutex_thread_proc: exiting\n", GetCurrentThreadId());
1064     return 196;
1065 }
1066
1067 static DWORD WINAPI semaphore_thread_proc(void *param)
1068 {
1069     DWORD ret;
1070
1071     ret = WaitForSingleObject(semaphore, 0);
1072     ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1073
1074     SetEvent(param);
1075
1076     while (1)
1077     {
1078         trace("%04u: semaphore_thread_proc: still alive\n", GetCurrentThreadId());
1079         if (WaitForSingleObject(stop_event, 50) != WAIT_TIMEOUT) break;
1080     }
1081
1082     trace("%04u: semaphore_thread_proc: exiting\n", GetCurrentThreadId());
1083     return 196;
1084 }
1085
1086 static DWORD WINAPI noop_thread_proc(void *param)
1087 {
1088     InterlockedIncrement(&noop_thread_started);
1089
1090     trace("%04u: noop_thread_proc: exiting\n", GetCurrentThreadId());
1091     return 196;
1092 }
1093
1094 static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param)
1095 {
1096     DWORD ret;
1097
1098     switch (reason)
1099     {
1100     case DLL_PROCESS_ATTACH:
1101         trace("dll: %p, DLL_PROCESS_ATTACH, %p\n", hinst, param);
1102
1103         ret = pRtlDllShutdownInProgress();
1104         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1105
1106         break;
1107     case DLL_PROCESS_DETACH:
1108     {
1109         DWORD code, expected_code, i;
1110         HANDLE handle, process;
1111         void *addr;
1112         SIZE_T size;
1113         LARGE_INTEGER offset;
1114         DEBUG_EVENT de;
1115
1116         trace("dll: %p, DLL_PROCESS_DETACH, %p\n", hinst, param);
1117
1118         if (test_dll_phase == 0) expected_code = 195;
1119         else if (test_dll_phase == 3) expected_code = 196;
1120         else expected_code = STILL_ACTIVE;
1121
1122         if (test_dll_phase == 3 || test_dll_phase == 4)
1123         {
1124             ret = pRtlDllShutdownInProgress();
1125             ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
1126         }
1127         else
1128         {
1129             ret = pRtlDllShutdownInProgress();
1130
1131             /* FIXME: remove once Wine is fixed */
1132             if (expected_code == STILL_ACTIVE || expected_code == 196)
1133                 ok(!ret || broken(ret) /* before Vista */, "RtlDllShutdownInProgress returned %d\n", ret);
1134             else
1135             todo_wine
1136                 ok(!ret || broken(ret) /* before Vista */, "RtlDllShutdownInProgress returned %d\n", ret);
1137         }
1138
1139         ok(attached_thread_count == 2, "attached thread count should be 2\n");
1140
1141         for (i = 0; i < attached_thread_count; i++)
1142         {
1143             ret = GetExitCodeThread(attached_thread[i], &code);
1144             trace("dll: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
1145             ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
1146             ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code);
1147         }
1148
1149         ret = WaitForSingleObject(event, 0);
1150         ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1151
1152         ret = WaitForSingleObject(mutex, 0);
1153         if (expected_code == STILL_ACTIVE)
1154             ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1155         else
1156             ok(ret == WAIT_ABANDONED, "expected WAIT_ABANDONED, got %#x\n", ret);
1157
1158         /* semaphore is not abandoned on thread termination */
1159         ret = WaitForSingleObject(semaphore, 0);
1160         ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1161
1162         if (expected_code == STILL_ACTIVE)
1163         {
1164             ret = WaitForSingleObject(attached_thread[0], 0);
1165             ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1166             ret = WaitForSingleObject(attached_thread[1], 0);
1167             ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1168         }
1169         else
1170         {
1171             ret = WaitForSingleObject(attached_thread[0], 0);
1172             ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1173             ret = WaitForSingleObject(attached_thread[1], 0);
1174             ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1175         }
1176
1177         /* win7 doesn't allow to create a thread during process shutdown,
1178          * earlier Windows versions allow it.
1179          */
1180         noop_thread_started = 0;
1181         SetLastError(0xdeadbeef);
1182         handle = CreateThread(NULL, 0, noop_thread_proc, NULL, 0, &ret);
1183         /* manual call to LdrShutdownProcess doesn't prevent thread creation */
1184         if (param && test_dll_phase != 4)
1185         {
1186             ok(!handle || broken(handle != 0) /* before win7 */, "CreateThread should fail\n");
1187             if (!handle)
1188                 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1189             else
1190                 CloseHandle(handle);
1191         }
1192         else
1193         {
1194             /* FIXME: remove once Wine is fixed */
1195             if (test_dll_phase == 4) todo_wine
1196             {
1197             ok(handle != 0, "CreateThread error %d\n", GetLastError());
1198             }
1199             else
1200             {
1201             ok(handle != 0, "CreateThread error %d\n", GetLastError());
1202             ret = WaitForSingleObject(handle, 1000);
1203             ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1204             ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n");
1205             }
1206             CloseHandle(handle);
1207         }
1208
1209         SetLastError(0xdeadbeef);
1210         process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
1211         ok(process != NULL, "OpenProcess error %d\n", GetLastError());
1212
1213         noop_thread_started = 0;
1214         SetLastError(0xdeadbeef);
1215         handle = CreateRemoteThread(process, NULL, 0, noop_thread_proc, NULL, 0, &ret);
1216         /* manual call to LdrShutdownProcess doesn't prevent thread creation */
1217         if (param && test_dll_phase != 4)
1218         {
1219             ok(!handle || broken(handle != 0) /* before win7 */, "CreateRemoteThread should fail\n");
1220             if (!handle)
1221                 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1222             else
1223                 CloseHandle(handle);
1224         }
1225         else
1226         {
1227             /* FIXME: remove once Wine is fixed */
1228             if (test_dll_phase == 4) todo_wine
1229             {
1230             ok(handle != 0, "CreateRemoteThread error %d\n", GetLastError());
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             }
1239             CloseHandle(handle);
1240         }
1241
1242         SetLastError(0xdeadbeef);
1243         handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
1244         ok(handle != 0, "CreateFileMapping error %d\n", GetLastError());
1245
1246         offset.u.LowPart = 0;
1247         offset.u.HighPart = 0;
1248         addr = NULL;
1249         size = 0;
1250         ret = pNtMapViewOfSection(handle, process, &addr, 0, 0, &offset,
1251                                   &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1252         ok(ret == STATUS_SUCCESS, "NtMapViewOfSection error %#x\n", ret);
1253         ret = pNtUnmapViewOfSection(process, addr);
1254         ok(ret == STATUS_SUCCESS, "NtUnmapViewOfSection error %#x\n", ret);
1255
1256         CloseHandle(handle);
1257         CloseHandle(process);
1258
1259         handle = GetModuleHandle("winver.exe");
1260         ok(!handle, "winver.exe shouldn't be loaded yet\n");
1261         SetLastError(0xdeadbeef);
1262         handle = LoadLibrary("winver.exe");
1263         ok(handle != 0, "LoadLibrary error %d\n", GetLastError());
1264         SetLastError(0xdeadbeef);
1265         ret = FreeLibrary(handle);
1266         ok(ret, "FreeLibrary error %d\n", GetLastError());
1267         handle = GetModuleHandle("winver.exe");
1268         /* manual call to LdrShutdownProcess doesn't prevent module unloading */
1269         if (param && test_dll_phase != 4)
1270             ok(handle != 0, "winver.exe should not be unloaded\n");
1271         else
1272         todo_wine
1273             ok(!handle || broken(handle != 0) /* before win7 */, "winver.exe should be unloaded\n");
1274
1275         SetLastError(0xdeadbeef);
1276         ret = WaitForDebugEvent(&de, 0);
1277         ok(!ret, "WaitForDebugEvent should fail\n");
1278 todo_wine
1279         ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
1280
1281         SetLastError(0xdeadbeef);
1282         ret = DebugActiveProcess(GetCurrentProcessId());
1283         ok(!ret, "DebugActiveProcess should fail\n");
1284         ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1285
1286         SetLastError(0xdeadbeef);
1287         ret = WaitForDebugEvent(&de, 0);
1288         ok(!ret, "WaitForDebugEvent should fail\n");
1289         ok(GetLastError() == ERROR_SEM_TIMEOUT, "expected ERROR_SEM_TIMEOUT, got %d\n", GetLastError());
1290
1291         if (test_dll_phase == 2)
1292         {
1293             trace("dll: call ExitProcess()\n");
1294             *child_failures = winetest_get_failures();
1295             ExitProcess(197);
1296         }
1297         trace("dll: %p, DLL_PROCESS_DETACH, %p => DONE\n", hinst, param);
1298         break;
1299     }
1300     case DLL_THREAD_ATTACH:
1301         trace("dll: %p, DLL_THREAD_ATTACH, %p\n", hinst, param);
1302
1303         ret = pRtlDllShutdownInProgress();
1304         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1305
1306         if (attached_thread_count < MAX_COUNT)
1307         {
1308             DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &attached_thread[attached_thread_count],
1309                             0, TRUE, DUPLICATE_SAME_ACCESS);
1310             attached_thread_count++;
1311         }
1312         break;
1313     case DLL_THREAD_DETACH:
1314         trace("dll: %p, DLL_THREAD_DETACH, %p\n", hinst, param);
1315
1316         ret = pRtlDllShutdownInProgress();
1317         /* win7 doesn't allow to create a thread during process shutdown,
1318          * earlier Windows versions allow it, and DLL_THREAD_DETACH is
1319          * sent on thread exit, but DLL_THREAD_ATTACH is never received.
1320          */
1321         if (noop_thread_started)
1322             ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
1323         else
1324             ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1325
1326         break;
1327     default:
1328         trace("dll: %p, %d, %p\n", hinst, reason, param);
1329         break;
1330     }
1331
1332     *child_failures = winetest_get_failures();
1333
1334     return TRUE;
1335 }
1336
1337 static void child_process(const char *dll_name, DWORD target_offset)
1338 {
1339     void *target;
1340     DWORD ret, dummy, i, code, expected_code;
1341     HANDLE file, thread;
1342     HMODULE hmod;
1343     NTSTATUS status;
1344
1345     trace("phase %d: writing %p at %#x\n", test_dll_phase, dll_entry_point, target_offset);
1346
1347     SetLastError(0xdeadbeef);
1348     mutex = CreateMutex(NULL, FALSE, NULL);
1349     ok(mutex != 0, "CreateMutex error %d\n", GetLastError());
1350
1351     SetLastError(0xdeadbeef);
1352     semaphore = CreateSemaphore(NULL, 1, 1, NULL);
1353     ok(semaphore != 0, "CreateSemaphore error %d\n", GetLastError());
1354
1355     SetLastError(0xdeadbeef);
1356     event = CreateEvent(NULL, TRUE, FALSE, NULL);
1357     ok(event != 0, "CreateEvent error %d\n", GetLastError());
1358
1359     file = CreateFile(dll_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1360     if (file == INVALID_HANDLE_VALUE)
1361     {
1362         ok(0, "could not open %s\n", dll_name);
1363         return;
1364     }
1365     SetFilePointer(file, target_offset, NULL, FILE_BEGIN);
1366     SetLastError(0xdeadbeef);
1367     target = dll_entry_point;
1368     ret = WriteFile(file, &target, sizeof(target), &dummy, NULL);
1369     ok(ret, "WriteFile error %d\n", GetLastError());
1370     CloseHandle(file);
1371
1372     SetLastError(0xdeadbeef);
1373     hmod = LoadLibrary(dll_name);
1374     ok(hmod != 0, "LoadLibrary error %d\n", GetLastError());
1375
1376     SetLastError(0xdeadbeef);
1377     stop_event = CreateEvent(NULL, TRUE, FALSE, NULL);
1378     ok(stop_event != 0, "CreateEvent error %d\n", GetLastError());
1379
1380     SetLastError(0xdeadbeef);
1381     thread = CreateThread(NULL, 0, mutex_thread_proc, event, 0, &dummy);
1382     ok(thread != 0, "CreateThread error %d\n", GetLastError());
1383     WaitForSingleObject(event, 3000);
1384     CloseHandle(thread);
1385
1386     ResetEvent(event);
1387
1388     SetLastError(0xdeadbeef);
1389     thread = CreateThread(NULL, 0, semaphore_thread_proc, event, 0, &dummy);
1390     ok(thread != 0, "CreateThread error %d\n", GetLastError());
1391     WaitForSingleObject(event, 3000);
1392     CloseHandle(thread);
1393
1394     ResetEvent(event);
1395     Sleep(100);
1396
1397     ok(attached_thread_count == 2, "attached thread count should be 2\n");
1398     for (i = 0; i < attached_thread_count; i++)
1399     {
1400         ret = GetExitCodeThread(attached_thread[i], &code);
1401         trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
1402         ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
1403         ok(code == STILL_ACTIVE, "expected thread exit code STILL_ACTIVE, got %u\n", code);
1404     }
1405
1406     ret = WaitForSingleObject(attached_thread[0], 0);
1407     ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1408     ret = WaitForSingleObject(attached_thread[1], 0);
1409     ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1410
1411     ret = WaitForSingleObject(event, 0);
1412     ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1413     ret = WaitForSingleObject(mutex, 0);
1414     ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1415     ret = WaitForSingleObject(semaphore, 0);
1416     ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1417
1418     ret = pRtlDllShutdownInProgress();
1419     ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1420
1421     SetLastError(0xdeadbeef);
1422     ret = TerminateProcess(0, 195);
1423     ok(!ret, "TerminateProcess(0) should fail\n");
1424     ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
1425
1426     Sleep(100);
1427
1428     switch (test_dll_phase)
1429     {
1430     case 0:
1431         ret = pRtlDllShutdownInProgress();
1432         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1433
1434         trace("call NtTerminateProcess(0, 195)\n");
1435         status = pNtTerminateProcess(0, 195);
1436         ok(!status, "NtTerminateProcess error %#x\n", status);
1437
1438         ret = pRtlDllShutdownInProgress();
1439         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1440
1441         break;
1442
1443     case 1:
1444     case 2: /* ExitProcess will be called by the PROCESS_DETACH handler */
1445         ret = pRtlDllShutdownInProgress();
1446         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1447
1448         trace("call FreeLibrary(%p)\n", hmod);
1449         FreeLibrary(hmod);
1450
1451         ret = pRtlDllShutdownInProgress();
1452         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1453
1454         break;
1455
1456     case 3:
1457         trace("signalling thread exit\n");
1458         SetEvent(stop_event);
1459         CloseHandle(stop_event);
1460         break;
1461
1462     case 4:
1463         ret = pRtlDllShutdownInProgress();
1464         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1465
1466         trace("call LdrShutdownProcess()\n");
1467         pLdrShutdownProcess();
1468
1469         ret = pRtlDllShutdownInProgress();
1470         ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
1471
1472         break;
1473
1474     default:
1475         assert(0);
1476         break;
1477     }
1478
1479     Sleep(100);
1480
1481     if (test_dll_phase == 0) expected_code = 195;
1482     else if (test_dll_phase == 3) expected_code = 196;
1483     else expected_code = STILL_ACTIVE;
1484
1485     if (expected_code == STILL_ACTIVE)
1486     {
1487         ret = WaitForSingleObject(attached_thread[0], 0);
1488         ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1489         ret = WaitForSingleObject(attached_thread[1], 0);
1490         ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1491     }
1492     else
1493     {
1494         ret = WaitForSingleObject(attached_thread[0], 50);
1495         ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1496         ret = WaitForSingleObject(attached_thread[1], 50);
1497         ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1498     }
1499
1500     for (i = 0; i < attached_thread_count; i++)
1501     {
1502         ret = GetExitCodeThread(attached_thread[i], &code);
1503         trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
1504         ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
1505         ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code);
1506     }
1507
1508     *child_failures = winetest_get_failures();
1509
1510     trace("call ExitProcess()\n");
1511     ExitProcess(195);
1512 }
1513
1514 static void test_ExitProcess(void)
1515 {
1516 #include "pshpack1.h"
1517 #ifdef __x86_64__
1518     static struct section_data
1519     {
1520         BYTE mov_rax[2];
1521         void *target;
1522         BYTE jmp_rax[2];
1523     } section_data = { { 0x48,0xb8 }, dll_entry_point, { 0xff,0xe0 } };
1524 #else
1525     static struct section_data
1526     {
1527         BYTE mov_eax;
1528         void *target;
1529         BYTE jmp_eax[2];
1530     } section_data = { 0xb8, dll_entry_point, { 0xff,0xe0 } };
1531 #endif
1532 #include "poppack.h"
1533     static const char filler[0x1000];
1534     DWORD dummy, file_align;
1535     HANDLE file;
1536     char temp_path[MAX_PATH], dll_name[MAX_PATH], cmdline[MAX_PATH * 2];
1537     DWORD ret, target_offset;
1538     char **argv;
1539     PROCESS_INFORMATION pi;
1540     STARTUPINFO si = { sizeof(si) };
1541
1542 #if !defined(__i386__) && !defined(__x86_64__)
1543     skip("x86 specific ExitProcess test\n");
1544     return;
1545 #endif
1546
1547     if (!pRtlDllShutdownInProgress)
1548     {
1549         skip("RtlDllShutdownInProgress is not available on this platform (XP+)\n");
1550         return;
1551     }
1552
1553     /* prevent displaying of the "Unable to load this DLL" message box */
1554     SetErrorMode(SEM_FAILCRITICALERRORS);
1555
1556     GetTempPath(MAX_PATH, temp_path);
1557     GetTempFileName(temp_path, "ldr", 0, dll_name);
1558
1559     /*trace("creating %s\n", dll_name);*/
1560     file = CreateFile(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
1561     if (file == INVALID_HANDLE_VALUE)
1562     {
1563         ok(0, "could not create %s\n", dll_name);
1564         return;
1565     }
1566
1567     SetLastError(0xdeadbeef);
1568     ret = WriteFile(file, &dos_header, sizeof(dos_header), &dummy, NULL);
1569     ok(ret, "WriteFile error %d\n", GetLastError());
1570
1571     nt_header.FileHeader.NumberOfSections = 1;
1572     nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1573     nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED;
1574
1575     nt_header.OptionalHeader.AddressOfEntryPoint = 0x1000;
1576     nt_header.OptionalHeader.SectionAlignment = 0x1000;
1577     nt_header.OptionalHeader.FileAlignment = 0x200;
1578     nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000;
1579     nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
1580     SetLastError(0xdeadbeef);
1581     ret = WriteFile(file, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
1582     ok(ret, "WriteFile error %d\n", GetLastError());
1583     SetLastError(0xdeadbeef);
1584     ret = WriteFile(file, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
1585     ok(ret, "WriteFile error %d\n", GetLastError());
1586
1587     section.SizeOfRawData = sizeof(section_data);
1588     section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
1589     section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
1590     section.Misc.VirtualSize = sizeof(section_data);
1591     section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
1592     SetLastError(0xdeadbeef);
1593     ret = WriteFile(file, &section, sizeof(section), &dummy, NULL);
1594     ok(ret, "WriteFile error %d\n", GetLastError());
1595
1596     file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
1597     assert(file_align < sizeof(filler));
1598     SetLastError(0xdeadbeef);
1599     ret = WriteFile(file, filler, file_align, &dummy, NULL);
1600     ok(ret, "WriteFile error %d\n", GetLastError());
1601
1602     target_offset = SetFilePointer(file, 0, NULL, FILE_CURRENT) + FIELD_OFFSET(struct section_data, target);
1603
1604     /* section data */
1605     SetLastError(0xdeadbeef);
1606     ret = WriteFile(file, &section_data, sizeof(section_data), &dummy, NULL);
1607     ok(ret, "WriteFile error %d\n", GetLastError());
1608
1609     CloseHandle(file);
1610
1611     winetest_get_mainargs(&argv);
1612
1613     /* phase 0 */
1614     *child_failures = -1;
1615     sprintf(cmdline, "\"%s\" loader %s %u 0", argv[0], dll_name, target_offset);
1616     ret = CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1617     ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
1618     ret = WaitForSingleObject(pi.hProcess, 30000);
1619     ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
1620     GetExitCodeProcess(pi.hProcess, &ret);
1621     ok(ret == 195, "expected exit code 195, got %u\n", ret);
1622     if (*child_failures)
1623     {
1624         trace("%d failures in child process\n", *child_failures);
1625         winetest_add_failures(*child_failures);
1626     }
1627     CloseHandle(pi.hThread);
1628     CloseHandle(pi.hProcess);
1629
1630     /* phase 1 */
1631     *child_failures = -1;
1632     sprintf(cmdline, "\"%s\" loader %s %u 1", argv[0], dll_name, target_offset);
1633     ret = CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1634     ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
1635     ret = WaitForSingleObject(pi.hProcess, 30000);
1636     ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
1637     GetExitCodeProcess(pi.hProcess, &ret);
1638     ok(ret == 195, "expected exit code 195, got %u\n", ret);
1639     if (*child_failures)
1640     {
1641         trace("%d failures in child process\n", *child_failures);
1642         winetest_add_failures(*child_failures);
1643     }
1644     CloseHandle(pi.hThread);
1645     CloseHandle(pi.hProcess);
1646
1647     /* phase 2 */
1648     *child_failures = -1;
1649     sprintf(cmdline, "\"%s\" loader %s %u 2", argv[0], dll_name, target_offset);
1650     ret = CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1651     ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
1652     ret = WaitForSingleObject(pi.hProcess, 30000);
1653     ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
1654     GetExitCodeProcess(pi.hProcess, &ret);
1655     ok(ret == 197, "expected exit code 197, got %u\n", ret);
1656     if (*child_failures)
1657     {
1658         trace("%d failures in child process\n", *child_failures);
1659         winetest_add_failures(*child_failures);
1660     }
1661     CloseHandle(pi.hThread);
1662     CloseHandle(pi.hProcess);
1663
1664     /* phase 3 */
1665     *child_failures = -1;
1666     sprintf(cmdline, "\"%s\" loader %s %u 3", argv[0], dll_name, target_offset);
1667     ret = CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1668     ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
1669     ret = WaitForSingleObject(pi.hProcess, 30000);
1670     ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
1671     GetExitCodeProcess(pi.hProcess, &ret);
1672     ok(ret == 195, "expected exit code 195, got %u\n", ret);
1673     if (*child_failures)
1674     {
1675         trace("%d failures in child process\n", *child_failures);
1676         winetest_add_failures(*child_failures);
1677     }
1678     CloseHandle(pi.hThread);
1679     CloseHandle(pi.hProcess);
1680
1681     /* phase 4 */
1682     *child_failures = -1;
1683     sprintf(cmdline, "\"%s\" loader %s %u 4", argv[0], dll_name, target_offset);
1684     ret = CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1685     ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
1686     ret = WaitForSingleObject(pi.hProcess, 30000);
1687     ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
1688     GetExitCodeProcess(pi.hProcess, &ret);
1689 todo_wine
1690     ok(ret == 0 || broken(ret == 195) /* before win7 */, "expected exit code 0, got %u\n", ret);
1691     if (*child_failures)
1692     {
1693         trace("%d failures in child process\n", *child_failures);
1694         winetest_add_failures(*child_failures);
1695     }
1696     CloseHandle(pi.hThread);
1697     CloseHandle(pi.hProcess);
1698
1699     ret = DeleteFile(dll_name);
1700     ok(ret, "DeleteFile error %d\n", GetLastError());
1701 }
1702
1703 START_TEST(loader)
1704 {
1705     int argc;
1706     char **argv;
1707     HANDLE mapping;
1708
1709     pNtMapViewOfSection = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtMapViewOfSection");
1710     pNtUnmapViewOfSection = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtUnmapViewOfSection");
1711     pNtTerminateProcess = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtTerminateProcess");
1712     pLdrShutdownProcess = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "LdrShutdownProcess");
1713     pRtlDllShutdownInProgress = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlDllShutdownInProgress");
1714
1715     mapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_loader");
1716     ok(mapping != 0, "CreateFileMapping failed\n");
1717     child_failures = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 4096);
1718     if (*child_failures == -1)
1719     {
1720         is_child = 1;
1721         *child_failures = 0;
1722     }
1723     else
1724         *child_failures = -1;
1725
1726     argc = winetest_get_mainargs(&argv);
1727     if (argc > 4)
1728     {
1729         test_dll_phase = atoi(argv[4]);
1730         child_process(argv[2], atol(argv[3]));
1731         return;
1732     }
1733
1734     test_Loader();
1735     test_ImportDescriptors();
1736     test_section_access();
1737     test_ExitProcess();
1738 }