winealsa: Map ALSA errors to AUDCLNT_E_*.
[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 <assert.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wine/test.h"
27
28 #define ALIGN_SIZE(size, alignment) (((size) + (alignment - 1)) & ~((alignment - 1)))
29
30 static PVOID RVAToAddr(DWORD_PTR rva, HMODULE module)
31 {
32     if (rva == 0)
33         return NULL;
34     return ((char*) module) + rva;
35 }
36
37 static const struct
38 {
39     WORD e_magic;      /* 00: MZ Header signature */
40     WORD unused[29];
41     DWORD e_lfanew;    /* 3c: Offset to extended header */
42 } dos_header =
43 {
44     IMAGE_DOS_SIGNATURE, { 0 }, sizeof(dos_header)
45 };
46
47 static IMAGE_NT_HEADERS nt_header =
48 {
49     IMAGE_NT_SIGNATURE, /* Signature */
50     {
51 #if defined __i386__
52       IMAGE_FILE_MACHINE_I386, /* Machine */
53 #elif defined __x86_64__
54       IMAGE_FILE_MACHINE_AMD64, /* Machine */
55 #elif defined __powerpc__
56       IMAGE_FILE_MACHINE_POWERPC, /* Machine */
57 #elif defined __sparc__
58       IMAGE_FILE_MACHINE_SPARC, /* Machine */
59 #elif defined __arm__
60       IMAGE_FILE_MACHINE_ARMV7, /* Machine */
61 #else
62 # error You must specify the machine type
63 #endif
64       1, /* NumberOfSections */
65       0, /* TimeDateStamp */
66       0, /* PointerToSymbolTable */
67       0, /* NumberOfSymbols */
68       sizeof(IMAGE_OPTIONAL_HEADER), /* SizeOfOptionalHeader */
69       IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL /* Characteristics */
70     },
71     { IMAGE_NT_OPTIONAL_HDR_MAGIC, /* Magic */
72       1, /* MajorLinkerVersion */
73       0, /* MinorLinkerVersion */
74       0, /* SizeOfCode */
75       0, /* SizeOfInitializedData */
76       0, /* SizeOfUninitializedData */
77       0, /* AddressOfEntryPoint */
78       0x10, /* BaseOfCode, also serves as e_lfanew in the truncated MZ header */
79 #ifndef _WIN64
80       0, /* BaseOfData */
81 #endif
82       0x10000000, /* ImageBase */
83       0, /* SectionAlignment */
84       0, /* FileAlignment */
85       4, /* MajorOperatingSystemVersion */
86       0, /* MinorOperatingSystemVersion */
87       1, /* MajorImageVersion */
88       0, /* MinorImageVersion */
89       4, /* MajorSubsystemVersion */
90       0, /* MinorSubsystemVersion */
91       0, /* Win32VersionValue */
92       sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000, /* SizeOfImage */
93       sizeof(dos_header) + sizeof(nt_header), /* SizeOfHeaders */
94       0, /* CheckSum */
95       IMAGE_SUBSYSTEM_WINDOWS_CUI, /* Subsystem */
96       0, /* DllCharacteristics */
97       0, /* SizeOfStackReserve */
98       0, /* SizeOfStackCommit */
99       0, /* SizeOfHeapReserve */
100       0, /* SizeOfHeapCommit */
101       0, /* LoaderFlags */
102       0, /* NumberOfRvaAndSizes */
103       { { 0 } } /* DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] */
104     }
105 };
106
107 static IMAGE_SECTION_HEADER section =
108 {
109     ".rodata", /* Name */
110     { 0x10 }, /* Misc */
111     0, /* VirtualAddress */
112     0x0a, /* SizeOfRawData */
113     0, /* PointerToRawData */
114     0, /* PointerToRelocations */
115     0, /* PointerToLinenumbers */
116     0, /* NumberOfRelocations */
117     0, /* NumberOfLinenumbers */
118     IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, /* Characteristics */
119 };
120
121 static void test_Loader(void)
122 {
123     static const struct test_data
124     {
125         const void *dos_header;
126         DWORD size_of_dos_header;
127         WORD number_of_sections, size_of_optional_header;
128         DWORD section_alignment, file_alignment;
129         DWORD size_of_image, size_of_headers;
130         DWORD errors[4]; /* 0 means LoadLibrary should succeed */
131     } td[] =
132     {
133         { &dos_header, sizeof(dos_header),
134           1, 0, 0, 0, 0, 0,
135           { ERROR_BAD_EXE_FORMAT }
136         },
137         { &dos_header, sizeof(dos_header),
138           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
139           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0xe00,
140           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER),
141           { ERROR_BAD_EXE_FORMAT } /* XP doesn't like too small image size */
142         },
143         { &dos_header, sizeof(dos_header),
144           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
145           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
146           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER),
147           { ERROR_SUCCESS }
148         },
149         { &dos_header, sizeof(dos_header),
150           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
151           0x1f00,
152           0x1000,
153           { ERROR_SUCCESS }
154         },
155         { &dos_header, sizeof(dos_header),
156           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x200,
157           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x200,
158           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER),
159           { ERROR_SUCCESS, ERROR_INVALID_ADDRESS } /* vista is more strict */
160         },
161         { &dos_header, sizeof(dos_header),
162           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x1000,
163           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
164           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER),
165           { ERROR_BAD_EXE_FORMAT } /* XP doesn't like alignments */
166         },
167         { &dos_header, sizeof(dos_header),
168           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
169           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
170           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER),
171           { ERROR_SUCCESS }
172         },
173         { &dos_header, sizeof(dos_header),
174           1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
175           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
176           0x200,
177           { ERROR_SUCCESS }
178         },
179         /* Mandatory are all fields up to SizeOfHeaders, everything else
180          * is really optional (at least that's true for XP).
181          */
182         { &dos_header, sizeof(dos_header),
183           1, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
184           sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER) + 0x10,
185           sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER),
186           { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT, ERROR_INVALID_ADDRESS,
187             ERROR_NOACCESS }
188         },
189         { &dos_header, sizeof(dos_header),
190           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
191           0xd0, /* beyond of the end of file */
192           0xc0, /* beyond of the end of file */
193           { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
194         },
195         { &dos_header, sizeof(dos_header),
196           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
197           0x1000,
198           0,
199           { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
200         },
201         { &dos_header, sizeof(dos_header),
202           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
203           1,
204           0,
205           { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
206         },
207 #if 0 /* not power of 2 alignments need more test cases */
208         { &dos_header, sizeof(dos_header),
209           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x300, 0x300,
210           1,
211           0,
212           { ERROR_BAD_EXE_FORMAT } /* alignment is not power of 2 */
213         },
214 #endif
215         { &dos_header, sizeof(dos_header),
216           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 4, 4,
217           1,
218           0,
219           { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
220         },
221         { &dos_header, sizeof(dos_header),
222           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 1, 1,
223           1,
224           0,
225           { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
226         },
227         { &dos_header, sizeof(dos_header),
228           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
229           0,
230           0,
231           { ERROR_BAD_EXE_FORMAT } /* image size == 0 -> failure */
232         },
233         /* the following data mimics the PE image which upack creates */
234         { &dos_header, 0x10,
235           1, 0x148, 0x1000, 0x200,
236           sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
237           0x200,
238           { ERROR_SUCCESS }
239         },
240         /* Minimal PE image that XP is able to load: 92 bytes */
241         { &dos_header, 0x04,
242           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum),
243           0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
244           1,
245           0,
246           { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
247         }
248     };
249     static const char filler[0x1000];
250     static const char section_data[0x10] = "section data";
251     int i;
252     DWORD dummy, file_size, file_align;
253     HANDLE hfile;
254     HMODULE hlib, hlib_as_data_file;
255     SYSTEM_INFO si;
256     char temp_path[MAX_PATH];
257     char dll_name[MAX_PATH];
258     SIZE_T size;
259     BOOL ret;
260
261     GetSystemInfo(&si);
262     trace("system page size 0x%04x\n", si.dwPageSize);
263
264     /* prevent displaying of the "Unable to load this DLL" message box */
265     SetErrorMode(SEM_FAILCRITICALERRORS);
266
267     GetTempPath(MAX_PATH, temp_path);
268
269     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
270     {
271         GetTempFileName(temp_path, "ldr", 0, dll_name);
272
273         /*trace("creating %s\n", dll_name);*/
274         hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
275         if (hfile == INVALID_HANDLE_VALUE)
276         {
277             ok(0, "could not create %s\n", dll_name);
278             break;
279         }
280
281         SetLastError(0xdeadbeef);
282         ret = WriteFile(hfile, td[i].dos_header, td[i].size_of_dos_header, &dummy, NULL);
283         ok(ret, "WriteFile error %d\n", GetLastError());
284
285         nt_header.FileHeader.NumberOfSections = td[i].number_of_sections;
286         nt_header.FileHeader.SizeOfOptionalHeader = td[i].size_of_optional_header;
287
288         nt_header.OptionalHeader.SectionAlignment = td[i].section_alignment;
289         nt_header.OptionalHeader.FileAlignment = td[i].file_alignment;
290         nt_header.OptionalHeader.SizeOfImage = td[i].size_of_image;
291         nt_header.OptionalHeader.SizeOfHeaders = td[i].size_of_headers;
292         SetLastError(0xdeadbeef);
293         ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
294         ok(ret, "WriteFile error %d\n", GetLastError());
295
296         if (nt_header.FileHeader.SizeOfOptionalHeader)
297         {
298             SetLastError(0xdeadbeef);
299             ret = WriteFile(hfile, &nt_header.OptionalHeader,
300                             min(nt_header.FileHeader.SizeOfOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER)),
301                             &dummy, NULL);
302             ok(ret, "WriteFile error %d\n", GetLastError());
303             if (nt_header.FileHeader.SizeOfOptionalHeader > sizeof(IMAGE_OPTIONAL_HEADER))
304             {
305                 file_align = nt_header.FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER);
306                 assert(file_align < sizeof(filler));
307                 SetLastError(0xdeadbeef);
308                 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
309                 ok(ret, "WriteFile error %d\n", GetLastError());
310             }
311         }
312
313         assert(nt_header.FileHeader.NumberOfSections <= 1);
314         if (nt_header.FileHeader.NumberOfSections)
315         {
316             if (nt_header.OptionalHeader.SectionAlignment >= si.dwPageSize)
317             {
318                 section.PointerToRawData = td[i].size_of_dos_header;
319                 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
320                 section.Misc.VirtualSize = section.SizeOfRawData * 10;
321             }
322             else
323             {
324                 section.PointerToRawData = nt_header.OptionalHeader.SizeOfHeaders;
325                 section.VirtualAddress = nt_header.OptionalHeader.SizeOfHeaders;
326                 section.Misc.VirtualSize = 5;
327             }
328
329             SetLastError(0xdeadbeef);
330             ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
331             ok(ret, "WriteFile error %d\n", GetLastError());
332
333             /* section data */
334             SetLastError(0xdeadbeef);
335             ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
336             ok(ret, "WriteFile error %d\n", GetLastError());
337         }
338
339         file_size = GetFileSize(hfile, NULL);
340         CloseHandle(hfile);
341
342         SetLastError(0xdeadbeef);
343         hlib = LoadLibrary(dll_name);
344         if (hlib)
345         {
346             MEMORY_BASIC_INFORMATION info;
347
348             ok( td[i].errors[0] == ERROR_SUCCESS, "%d: should have failed\n", i );
349
350             SetLastError(0xdeadbeef);
351             size = VirtualQuery(hlib, &info, sizeof(info));
352             ok(size == sizeof(info),
353                 "%d: VirtualQuery error %d\n", i, GetLastError());
354             ok(info.BaseAddress == hlib, "%d: %p != %p\n", i, info.BaseAddress, hlib);
355             ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
356             ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
357             ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize), "%d: got %lx != expected %x\n",
358                i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize));
359             ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
360             if (nt_header.OptionalHeader.SectionAlignment < si.dwPageSize)
361                 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
362             else
363                 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
364             ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
365
366             SetLastError(0xdeadbeef);
367             size = VirtualQuery((char *)hlib + info.RegionSize, &info, sizeof(info));
368             ok(size == sizeof(info),
369                 "%d: VirtualQuery error %d\n", i, GetLastError());
370             if (nt_header.OptionalHeader.SectionAlignment == si.dwPageSize ||
371                 nt_header.OptionalHeader.SectionAlignment == nt_header.OptionalHeader.FileAlignment)
372             {
373                 ok(info.BaseAddress == (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize), "%d: got %p != expected %p\n",
374                    i, info.BaseAddress, (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize));
375                 ok(info.AllocationBase == 0, "%d: %p != 0\n", i, info.AllocationBase);
376                 ok(info.AllocationProtect == 0, "%d: %x != 0\n", i, info.AllocationProtect);
377                 /*ok(info.RegionSize == not_practical_value, "%d: %lx != not_practical_value\n", i, info.RegionSize);*/
378                 ok(info.State == MEM_FREE, "%d: %x != MEM_FREE\n", i, info.State);
379                 ok(info.Type == 0, "%d: %x != 0\n", i, info.Type);
380                 ok(info.Protect == PAGE_NOACCESS, "%d: %x != PAGE_NOACCESS\n", i, info.Protect);
381             }
382             else
383             {
384                 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
385                 ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib);
386                 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
387                 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
388                 ok(info.RegionSize == ALIGN_SIZE(file_size, si.dwPageSize), "%d: got %lx != expected %x\n",
389                    i, info.RegionSize, ALIGN_SIZE(file_size, si.dwPageSize));
390                 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
391                 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
392                 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
393             }
394
395             /* header: check the zeroing of alignment */
396             if (nt_header.OptionalHeader.SectionAlignment >= si.dwPageSize)
397             {
398                 const char *start;
399                 int size;
400
401                 start = (const char *)hlib + nt_header.OptionalHeader.SizeOfHeaders;
402                 size = ALIGN_SIZE((ULONG_PTR)start, si.dwPageSize) - (ULONG_PTR)start;
403                 ok(!memcmp(start, filler, size), "%d: header alignment is not cleared\n", i);
404             }
405
406             if (nt_header.FileHeader.NumberOfSections)
407             {
408                 SetLastError(0xdeadbeef);
409                 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
410                 ok(size == sizeof(info),
411                     "%d: VirtualQuery error %d\n", i, GetLastError());
412                 if (nt_header.OptionalHeader.SectionAlignment < si.dwPageSize)
413                 {
414                     ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib);
415                     ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize), "%d: got %lx != expected %x\n",
416                        i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize));
417                     ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
418                 }
419                 else
420                 {
421                     ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
422                     ok(info.RegionSize == ALIGN_SIZE(section.Misc.VirtualSize, si.dwPageSize), "%d: got %lx != expected %x\n",
423                        i, info.RegionSize, ALIGN_SIZE(section.Misc.VirtualSize, si.dwPageSize));
424                     ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
425                 }
426                 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
427                 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
428                 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
429                 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
430
431                 if (nt_header.OptionalHeader.SectionAlignment >= si.dwPageSize)
432                     ok(!memcmp((const char *)hlib + section.VirtualAddress + section.PointerToRawData, &nt_header, section.SizeOfRawData), "wrong section data\n");
433                 else
434                     ok(!memcmp((const char *)hlib + section.PointerToRawData, section_data, section.SizeOfRawData), "wrong section data\n");
435
436                 /* check the zeroing of alignment */
437                 if (nt_header.OptionalHeader.SectionAlignment >= si.dwPageSize)
438                 {
439                     const char *start;
440                     int size;
441
442                     start = (const char *)hlib + section.VirtualAddress + section.PointerToRawData + section.SizeOfRawData;
443                     size = ALIGN_SIZE((ULONG_PTR)start, si.dwPageSize) - (ULONG_PTR)start;
444                     ok(memcmp(start, filler, size), "%d: alignment should not be cleared\n", i);
445                 }
446             }
447
448             SetLastError(0xdeadbeef);
449             hlib_as_data_file = LoadLibraryEx(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
450             ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
451             ok(hlib_as_data_file == hlib, "hlib_as_file and hlib are different\n");
452
453             SetLastError(0xdeadbeef);
454             ret = FreeLibrary(hlib);
455             ok(ret, "FreeLibrary error %d\n", GetLastError());
456
457             SetLastError(0xdeadbeef);
458             hlib = GetModuleHandle(dll_name);
459             ok(hlib != 0, "GetModuleHandle error %u\n", GetLastError());
460
461             SetLastError(0xdeadbeef);
462             ret = FreeLibrary(hlib_as_data_file);
463             ok(ret, "FreeLibrary error %d\n", GetLastError());
464
465             hlib = GetModuleHandle(dll_name);
466             ok(!hlib, "GetModuleHandle should fail\n");
467
468             SetLastError(0xdeadbeef);
469             hlib_as_data_file = LoadLibraryEx(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
470             ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
471             ok((ULONG_PTR)hlib_as_data_file & 1, "hlib_as_data_file is even\n");
472
473             hlib = GetModuleHandle(dll_name);
474             ok(!hlib, "GetModuleHandle should fail\n");
475
476             SetLastError(0xdeadbeef);
477             ret = FreeLibrary(hlib_as_data_file);
478             ok(ret, "FreeLibrary error %d\n", GetLastError());
479         }
480         else
481         {
482             BOOL error_match;
483             int error_index;
484
485             error_match = FALSE;
486             for (error_index = 0;
487                  ! error_match && error_index < sizeof(td[i].errors) / sizeof(DWORD);
488                  error_index++)
489             {
490                 error_match = td[i].errors[error_index] == GetLastError();
491             }
492             ok(error_match, "%d: unexpected error %d\n", i, GetLastError());
493         }
494
495         SetLastError(0xdeadbeef);
496         ret = DeleteFile(dll_name);
497         ok(ret, "DeleteFile error %d\n", GetLastError());
498     }
499 }
500
501 /* Verify linking style of import descriptors */
502 static void test_ImportDescriptors(void)
503 {
504     HMODULE kernel32_module = NULL;
505     PIMAGE_DOS_HEADER d_header;
506     PIMAGE_NT_HEADERS nt_headers;
507     DWORD import_dir_size;
508     DWORD_PTR dir_offset;
509     PIMAGE_IMPORT_DESCRIPTOR import_chunk;
510
511     /* Load kernel32 module */
512     kernel32_module = GetModuleHandleA("kernel32.dll");
513     assert( kernel32_module != NULL );
514
515     /* Get PE header info from module image */
516     d_header = (PIMAGE_DOS_HEADER) kernel32_module;
517     nt_headers = (PIMAGE_NT_HEADERS) (((char*) d_header) +
518             d_header->e_lfanew);
519
520     /* Get size of import entry directory */
521     import_dir_size = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
522     if (!import_dir_size)
523     {
524         skip("Unable to continue testing due to missing import directory.\n");
525         return;
526     }
527
528     /* Get address of first import chunk */
529     dir_offset = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
530     import_chunk = RVAToAddr(dir_offset, kernel32_module);
531     ok(import_chunk != 0, "Invalid import_chunk: %p\n", import_chunk);
532     if (!import_chunk) return;
533
534     /* Iterate through import descriptors and verify set name,
535      * OriginalFirstThunk, and FirstThunk.  Core Windows DLLs, such as
536      * kernel32.dll, don't use Borland-style linking, where the table of
537      * imported names is stored directly in FirstThunk and overwritten
538      * by the relocation, instead of being stored in OriginalFirstThunk.
539      * */
540     for (; import_chunk->FirstThunk; import_chunk++)
541     {
542         LPCSTR module_name = RVAToAddr(import_chunk->Name, kernel32_module);
543         PIMAGE_THUNK_DATA name_table = RVAToAddr(
544                 U(*import_chunk).OriginalFirstThunk, kernel32_module);
545         PIMAGE_THUNK_DATA iat = RVAToAddr(
546                 import_chunk->FirstThunk, kernel32_module);
547         ok(module_name != NULL, "Imported module name should not be NULL\n");
548         ok(name_table != NULL,
549                 "Name table for imported module %s should not be NULL\n",
550                 module_name);
551         ok(iat != NULL, "IAT for imported module %s should not be NULL\n",
552                 module_name);
553     }
554 }
555
556 static BOOL is_mem_writable(DWORD prot)
557 {
558     switch (prot & 0xff)
559     {
560         case PAGE_READWRITE:
561         case PAGE_WRITECOPY:
562         case PAGE_EXECUTE_READWRITE:
563         case PAGE_EXECUTE_WRITECOPY:
564             return TRUE;
565
566         default:
567             return FALSE;
568     }
569 }
570
571 static void test_VirtualProtect(void *base, void *section)
572 {
573     static const struct test_data
574     {
575         DWORD prot_set, prot_get;
576     } td[] =
577     {
578         { 0, 0 }, /* 0x00 */
579         { PAGE_NOACCESS, PAGE_NOACCESS }, /* 0x01 */
580         { PAGE_READONLY, PAGE_READONLY }, /* 0x02 */
581         { PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x03 */
582         { PAGE_READWRITE, PAGE_WRITECOPY }, /* 0x04 */
583         { PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x05 */
584         { PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x06 */
585         { PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x07 */
586         { PAGE_WRITECOPY, PAGE_WRITECOPY }, /* 0x08 */
587         { PAGE_WRITECOPY | PAGE_NOACCESS, 0 }, /* 0x09 */
588         { PAGE_WRITECOPY | PAGE_READONLY, 0 }, /* 0x0a */
589         { PAGE_WRITECOPY | PAGE_NOACCESS | PAGE_READONLY, 0 }, /* 0x0b */
590         { PAGE_WRITECOPY | PAGE_READWRITE, 0 }, /* 0x0c */
591         { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x0d */
592         { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x0e */
593         { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x0f */
594
595         { PAGE_EXECUTE, PAGE_EXECUTE }, /* 0x10 */
596         { PAGE_EXECUTE_READ, PAGE_EXECUTE_READ }, /* 0x20 */
597         { PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x30 */
598         { PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY }, /* 0x40 */
599         { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0x50 */
600         { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0x60 */
601         { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x70 */
602         { PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_WRITECOPY }, /* 0x80 */
603         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE, 0 }, /* 0x90 */
604         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ, 0 }, /* 0xa0 */
605         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0xb0 */
606         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE, 0 }, /* 0xc0 */
607         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0xd0 */
608         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0xe0 */
609         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 } /* 0xf0 */
610     };
611     DWORD ret, orig_prot, old_prot, rw_prot, exec_prot, i, j;
612     MEMORY_BASIC_INFORMATION info;
613     SYSTEM_INFO si;
614
615     GetSystemInfo(&si);
616     trace("system page size %#x\n", si.dwPageSize);
617
618     SetLastError(0xdeadbeef);
619     ret = VirtualProtect(section, si.dwPageSize, PAGE_NOACCESS, &old_prot);
620     ok(ret, "VirtualProtect error %d\n", GetLastError());
621
622     orig_prot = old_prot;
623
624     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
625     {
626         SetLastError(0xdeadbeef);
627         ret = VirtualQuery(section, &info, sizeof(info));
628         ok(ret, "VirtualQuery failed %d\n", GetLastError());
629         ok(info.BaseAddress == section, "%d: got %p != expected %p\n", i, info.BaseAddress, section);
630         ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
631         ok(info.Protect == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, info.Protect);
632         ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
633         ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
634         ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
635         ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
636
637         old_prot = 0xdeadbeef;
638         SetLastError(0xdeadbeef);
639         ret = VirtualProtect(section, si.dwPageSize, td[i].prot_set, &old_prot);
640         if (td[i].prot_get)
641         {
642             ok(ret, "%d: VirtualProtect error %d, requested prot %#x\n", i, GetLastError(), td[i].prot_set);
643             ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
644
645             SetLastError(0xdeadbeef);
646             ret = VirtualQuery(section, &info, sizeof(info));
647             ok(ret, "VirtualQuery failed %d\n", GetLastError());
648             ok(info.BaseAddress == section, "%d: got %p != expected %p\n", i, info.BaseAddress, section);
649             ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
650             ok(info.Protect == td[i].prot_get, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_get);
651             ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
652             ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
653             ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
654             ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
655         }
656         else
657         {
658             ok(!ret, "%d: VirtualProtect should fail\n", i);
659             ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
660         }
661
662         old_prot = 0xdeadbeef;
663         SetLastError(0xdeadbeef);
664         ret = VirtualProtect(section, si.dwPageSize, PAGE_NOACCESS, &old_prot);
665         ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
666         if (td[i].prot_get)
667             ok(old_prot == td[i].prot_get, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_get);
668         else
669             ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
670     }
671
672     exec_prot = 0;
673
674     for (i = 0; i <= 4; i++)
675     {
676         rw_prot = 0;
677
678         for (j = 0; j <= 4; j++)
679         {
680             DWORD prot = exec_prot | rw_prot;
681
682             SetLastError(0xdeadbeef);
683             ret = VirtualProtect(section, si.dwPageSize, prot, &old_prot);
684             if ((rw_prot && exec_prot) || (!rw_prot && !exec_prot))
685             {
686                 ok(!ret, "VirtualProtect(%02x) should fail\n", prot);
687                 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
688             }
689             else
690                 ok(ret, "VirtualProtect(%02x) error %d\n", prot, GetLastError());
691
692             rw_prot = 1 << j;
693         }
694
695         exec_prot = 1 << (i + 4);
696     }
697
698     SetLastError(0xdeadbeef);
699     ret = VirtualProtect(section, si.dwPageSize, orig_prot, &old_prot);
700     ok(ret, "VirtualProtect error %d\n", GetLastError());
701 }
702
703 static void test_section_access(void)
704 {
705     static const struct test_data
706     {
707         DWORD scn_file_access, scn_page_access, scn_page_access_after_write;
708     } td[] =
709     {
710         { 0, PAGE_NOACCESS, 0 },
711         { IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
712         { IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
713         { IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
714         { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
715         { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ },
716         { IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
717         { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
718
719         { IMAGE_SCN_CNT_INITIALIZED_DATA, PAGE_NOACCESS, 0 },
720         { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
721         { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
722         { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
723         { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
724         { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
725         { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
726         { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
727
728         { IMAGE_SCN_CNT_UNINITIALIZED_DATA, PAGE_NOACCESS, 0 },
729         { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
730         { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
731         { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
732         { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
733         { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
734         { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
735         { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE }
736     };
737     static const char filler[0x1000];
738     static const char section_data[0x10] = "section data";
739     char buf[256];
740     int i;
741     DWORD dummy, file_align;
742     HANDLE hfile;
743     HMODULE hlib;
744     SYSTEM_INFO si;
745     char temp_path[MAX_PATH];
746     char dll_name[MAX_PATH];
747     SIZE_T size;
748     MEMORY_BASIC_INFORMATION info;
749     STARTUPINFO sti;
750     PROCESS_INFORMATION pi;
751     DWORD ret;
752
753     GetSystemInfo(&si);
754     trace("system page size %#x\n", si.dwPageSize);
755
756     /* prevent displaying of the "Unable to load this DLL" message box */
757     SetErrorMode(SEM_FAILCRITICALERRORS);
758
759     GetTempPath(MAX_PATH, temp_path);
760
761     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
762     {
763         GetTempFileName(temp_path, "ldr", 0, dll_name);
764
765         /*trace("creating %s\n", dll_name);*/
766         hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
767         if (hfile == INVALID_HANDLE_VALUE)
768         {
769             ok(0, "could not create %s\n", dll_name);
770             return;
771         }
772
773         SetLastError(0xdeadbeef);
774         ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
775         ok(ret, "WriteFile error %d\n", GetLastError());
776
777         nt_header.FileHeader.NumberOfSections = 1;
778         nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
779
780         /* don't set IMAGE_FILE_DLL to show that it doesn't change anything for a DLL or a process image */
781         nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
782
783         nt_header.OptionalHeader.SectionAlignment = si.dwPageSize;
784         nt_header.OptionalHeader.FileAlignment = 0x200;
785         nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + si.dwPageSize;
786         nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
787         SetLastError(0xdeadbeef);
788         ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
789         ok(ret, "WriteFile error %d\n", GetLastError());
790         SetLastError(0xdeadbeef);
791         ret = WriteFile(hfile, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
792         ok(ret, "WriteFile error %d\n", GetLastError());
793
794         section.SizeOfRawData = sizeof(section_data);
795         section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
796         section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
797         section.Misc.VirtualSize = section.SizeOfRawData;
798         section.Characteristics = td[i].scn_file_access;
799         SetLastError(0xdeadbeef);
800         ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
801         ok(ret, "WriteFile error %d\n", GetLastError());
802
803         file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
804         assert(file_align < sizeof(filler));
805         SetLastError(0xdeadbeef);
806         ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
807         ok(ret, "WriteFile error %d\n", GetLastError());
808
809         /* section data */
810         SetLastError(0xdeadbeef);
811         ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
812         ok(ret, "WriteFile error %d\n", GetLastError());
813
814         CloseHandle(hfile);
815
816         SetLastError(0xdeadbeef);
817         hlib = LoadLibrary(dll_name);
818         ok(hlib != 0, "LoadLibrary error %d\n", GetLastError());
819
820         SetLastError(0xdeadbeef);
821         size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
822         ok(size == sizeof(info),
823             "%d: VirtualQuery error %d\n", i, GetLastError());
824         ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
825         ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
826         ok(info.Protect == td[i].scn_page_access, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access);
827         ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
828         ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
829         ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
830         ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
831         if (info.Protect != PAGE_NOACCESS)
832             ok(!memcmp((const char *)info.BaseAddress, section_data, section.SizeOfRawData), "wrong section data\n");
833
834         test_VirtualProtect(hlib, (char *)hlib + section.VirtualAddress);
835
836         /* Windows changes the WRITECOPY to WRITE protection on an image section write (for a changed page only) */
837         if (is_mem_writable(info.Protect))
838         {
839             char *p = info.BaseAddress;
840             *p = 0xfe;
841             SetLastError(0xdeadbeef);
842             size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
843             ok(size == sizeof(info), "%d: VirtualQuery error %d\n", i, GetLastError());
844             /* FIXME: remove the condition below once Wine is fixed */
845             if (info.Protect == PAGE_WRITECOPY || info.Protect == PAGE_EXECUTE_WRITECOPY)
846                 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);
847             else
848                 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);
849         }
850
851         SetLastError(0xdeadbeef);
852         ret = FreeLibrary(hlib);
853         ok(ret, "FreeLibrary error %d\n", GetLastError());
854
855         memset(&sti, 0, sizeof(sti));
856         sti.cb = sizeof(sti);
857         SetLastError(0xdeadbeef);
858         ret = CreateProcess(dll_name, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &sti, &pi);
859         ok(ret, "CreateProcess() error %d\n", GetLastError());
860
861         SetLastError(0xdeadbeef);
862         size = VirtualQueryEx(pi.hProcess, (char *)hlib + section.VirtualAddress, &info, sizeof(info));
863         ok(size == sizeof(info),
864             "%d: VirtualQuery error %d\n", i, GetLastError());
865         ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
866         ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
867         ok(info.Protect == td[i].scn_page_access, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access);
868         ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
869         ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
870         ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
871         ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
872         if (info.Protect != PAGE_NOACCESS)
873         {
874             SetLastError(0xdeadbeef);
875             ret = ReadProcessMemory(pi.hProcess, info.BaseAddress, buf, section.SizeOfRawData, NULL);
876             ok(ret, "ReadProcessMemory() error %d\n", GetLastError());
877             ok(!memcmp(buf, section_data, section.SizeOfRawData), "wrong section data\n");
878         }
879
880         SetLastError(0xdeadbeef);
881         ret = TerminateProcess(pi.hProcess, 0);
882         ok(ret, "TerminateProcess() error %d\n", GetLastError());
883         ret = WaitForSingleObject(pi.hProcess, 3000);
884         ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
885
886         CloseHandle(pi.hThread);
887         CloseHandle(pi.hProcess);
888
889         SetLastError(0xdeadbeef);
890         ret = DeleteFile(dll_name);
891         ok(ret, "DeleteFile error %d\n", GetLastError());
892     }
893 }
894
895 START_TEST(loader)
896 {
897     test_Loader();
898     test_ImportDescriptors();
899     test_section_access();
900 }