kernel32/tests: Fix loader test failures on some Windows versions.
[wine.git] / dlls / kernel32 / tests / loader.c
blob8ff511f7c0eb97c4d20caa77b0c72e151d3c9ae8
1 /*
2 * Unit test suite for the PE loader.
4 * Copyright 2006,2011 Dmitry Timoshkov
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.
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.
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
21 #define NONAMELESSUNION
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <assert.h>
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winternl.h"
31 #include "wine/test.h"
32 #include "delayloadhandler.h"
34 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
35 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
37 #define ALIGN_SIZE(size, alignment) (((size) + (alignment - 1)) & ~((alignment - 1)))
39 struct PROCESS_BASIC_INFORMATION_PRIVATE
41 DWORD_PTR ExitStatus;
42 PPEB PebBaseAddress;
43 DWORD_PTR AffinityMask;
44 DWORD_PTR BasePriority;
45 ULONG_PTR UniqueProcessId;
46 ULONG_PTR InheritedFromUniqueProcessId;
49 static LONG *child_failures;
50 static WORD cb_count;
51 static DWORD page_size;
53 static NTSTATUS (WINAPI *pNtCreateSection)(HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *,
54 const LARGE_INTEGER *, ULONG, ULONG, HANDLE );
55 static NTSTATUS (WINAPI *pNtQuerySection)(HANDLE, SECTION_INFORMATION_CLASS, void *, ULONG, ULONG *);
56 static NTSTATUS (WINAPI *pNtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG, SIZE_T, const LARGE_INTEGER *, SIZE_T *, ULONG, ULONG, ULONG);
57 static NTSTATUS (WINAPI *pNtUnmapViewOfSection)(HANDLE, PVOID);
58 static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
59 static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
60 static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE, DWORD);
61 static void (WINAPI *pLdrShutdownProcess)(void);
62 static BOOLEAN (WINAPI *pRtlDllShutdownInProgress)(void);
63 static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG, SIZE_T *, ULONG, ULONG);
64 static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG);
65 static NTSTATUS (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG *, ULONG_PTR *);
66 static NTSTATUS (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG_PTR);
67 static void (WINAPI *pRtlAcquirePebLock)(void);
68 static void (WINAPI *pRtlReleasePebLock)(void);
69 static PVOID (WINAPI *pResolveDelayLoadedAPI)(PVOID, PCIMAGE_DELAYLOAD_DESCRIPTOR,
70 PDELAYLOAD_FAILURE_DLL_CALLBACK, PVOID,
71 PIMAGE_THUNK_DATA ThunkAddress,ULONG);
72 static PVOID (WINAPI *pRtlImageDirectoryEntryToData)(HMODULE,BOOL,WORD,ULONG *);
74 static PVOID RVAToAddr(DWORD_PTR rva, HMODULE module)
76 if (rva == 0)
77 return NULL;
78 return ((char*) module) + rva;
81 static IMAGE_DOS_HEADER dos_header;
83 static const IMAGE_NT_HEADERS nt_header_template =
85 IMAGE_NT_SIGNATURE, /* Signature */
87 #if defined __i386__
88 IMAGE_FILE_MACHINE_I386, /* Machine */
89 #elif defined __x86_64__
90 IMAGE_FILE_MACHINE_AMD64, /* Machine */
91 #elif defined __powerpc__
92 IMAGE_FILE_MACHINE_POWERPC, /* Machine */
93 #elif defined __arm__
94 IMAGE_FILE_MACHINE_ARMNT, /* Machine */
95 #elif defined __aarch64__
96 IMAGE_FILE_MACHINE_ARM64, /* Machine */
97 #else
98 # error You must specify the machine type
99 #endif
100 1, /* NumberOfSections */
101 0, /* TimeDateStamp */
102 0, /* PointerToSymbolTable */
103 0, /* NumberOfSymbols */
104 sizeof(IMAGE_OPTIONAL_HEADER), /* SizeOfOptionalHeader */
105 IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL /* Characteristics */
107 { IMAGE_NT_OPTIONAL_HDR_MAGIC, /* Magic */
108 1, /* MajorLinkerVersion */
109 0, /* MinorLinkerVersion */
110 0, /* SizeOfCode */
111 0, /* SizeOfInitializedData */
112 0, /* SizeOfUninitializedData */
113 0, /* AddressOfEntryPoint */
114 0x10, /* BaseOfCode, also serves as e_lfanew in the truncated MZ header */
115 #ifndef _WIN64
116 0, /* BaseOfData */
117 #endif
118 0x10000000, /* ImageBase */
119 0, /* SectionAlignment */
120 0, /* FileAlignment */
121 4, /* MajorOperatingSystemVersion */
122 0, /* MinorOperatingSystemVersion */
123 1, /* MajorImageVersion */
124 0, /* MinorImageVersion */
125 4, /* MajorSubsystemVersion */
126 0, /* MinorSubsystemVersion */
127 0, /* Win32VersionValue */
128 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000, /* SizeOfImage */
129 sizeof(dos_header) + sizeof(nt_header_template), /* SizeOfHeaders */
130 0, /* CheckSum */
131 IMAGE_SUBSYSTEM_WINDOWS_CUI, /* Subsystem */
132 0, /* DllCharacteristics */
133 0, /* SizeOfStackReserve */
134 0, /* SizeOfStackCommit */
135 0, /* SizeOfHeapReserve */
136 0, /* SizeOfHeapCommit */
137 0, /* LoaderFlags */
138 0, /* NumberOfRvaAndSizes */
139 { { 0 } } /* DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] */
143 static IMAGE_SECTION_HEADER section =
145 ".rodata", /* Name */
146 { 0x10 }, /* Misc */
147 0, /* VirtualAddress */
148 0x0a, /* SizeOfRawData */
149 0, /* PointerToRawData */
150 0, /* PointerToRelocations */
151 0, /* PointerToLinenumbers */
152 0, /* NumberOfRelocations */
153 0, /* NumberOfLinenumbers */
154 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, /* Characteristics */
158 static const char filler[0x1000];
159 static const char section_data[0x10] = "section data";
161 static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size,
162 const IMAGE_NT_HEADERS *nt_header, const char *dll_name )
164 DWORD dummy, size, file_align;
165 HANDLE hfile;
166 BOOL ret;
168 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
169 if (hfile == INVALID_HANDLE_VALUE) return 0;
171 SetLastError(0xdeadbeef);
172 ret = WriteFile(hfile, dos_header, dos_size, &dummy, NULL);
173 ok(ret, "WriteFile error %d\n", GetLastError());
175 SetLastError(0xdeadbeef);
176 ret = WriteFile(hfile, nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
177 ok(ret, "WriteFile error %d\n", GetLastError());
179 if (nt_header->FileHeader.SizeOfOptionalHeader)
181 SetLastError(0xdeadbeef);
182 ret = WriteFile(hfile, &nt_header->OptionalHeader,
183 min(nt_header->FileHeader.SizeOfOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER)),
184 &dummy, NULL);
185 ok(ret, "WriteFile error %d\n", GetLastError());
186 if (nt_header->FileHeader.SizeOfOptionalHeader > sizeof(IMAGE_OPTIONAL_HEADER))
188 file_align = nt_header->FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER);
189 assert(file_align < sizeof(filler));
190 SetLastError(0xdeadbeef);
191 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
192 ok(ret, "WriteFile error %d\n", GetLastError());
196 assert(nt_header->FileHeader.NumberOfSections <= 1);
197 if (nt_header->FileHeader.NumberOfSections)
199 if (nt_header->OptionalHeader.SectionAlignment >= page_size)
201 section.PointerToRawData = dos_size;
202 section.VirtualAddress = nt_header->OptionalHeader.SectionAlignment;
203 section.Misc.VirtualSize = section.SizeOfRawData * 10;
205 else
207 section.PointerToRawData = nt_header->OptionalHeader.SizeOfHeaders;
208 section.VirtualAddress = nt_header->OptionalHeader.SizeOfHeaders;
209 section.Misc.VirtualSize = 5;
212 SetLastError(0xdeadbeef);
213 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
214 ok(ret, "WriteFile error %d\n", GetLastError());
216 /* section data */
217 SetLastError(0xdeadbeef);
218 ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
219 ok(ret, "WriteFile error %d\n", GetLastError());
221 size = GetFileSize(hfile, NULL);
222 CloseHandle(hfile);
223 return size;
226 static void query_image_section( int id, const char *dll_name, const IMAGE_NT_HEADERS *nt_header )
228 SECTION_IMAGE_INFORMATION image;
229 ULONG info_size = 0xdeadbeef;
230 NTSTATUS status;
231 HANDLE file, mapping;
232 ULONG file_size;
233 /* truncated header is not handled correctly in windows <= w2k3 */
234 BOOL truncated = nt_header->FileHeader.SizeOfOptionalHeader < sizeof(nt_header->OptionalHeader);
236 file = CreateFileA( dll_name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE,
237 NULL, OPEN_EXISTING, 0, 0 );
238 ok( file != INVALID_HANDLE_VALUE, "%u: CreateFile error %d\n", id, GetLastError() );
239 file_size = GetFileSize( file, NULL );
241 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
242 NULL, NULL, PAGE_READONLY, SEC_IMAGE, file );
243 ok( !status, "%u: NtCreateSection failed err %x\n", id, status );
244 if (status)
246 CloseHandle( file );
247 return;
249 status = pNtQuerySection( mapping, SectionImageInformation, &image, sizeof(image), &info_size );
250 ok( !status, "%u: NtQuerySection failed err %x\n", id, status );
251 ok( info_size == sizeof(image), "%u: NtQuerySection wrong size %u\n", id, info_size );
252 ok( (char *)image.TransferAddress == (char *)nt_header->OptionalHeader.ImageBase + nt_header->OptionalHeader.AddressOfEntryPoint,
253 "%u: TransferAddress wrong %p / %p+%08x\n", id,
254 image.TransferAddress, (char *)nt_header->OptionalHeader.ImageBase,
255 nt_header->OptionalHeader.AddressOfEntryPoint );
256 ok( image.ZeroBits == 0, "%u: ZeroBits wrong %08x\n", id, image.ZeroBits );
257 ok( image.MaximumStackSize == nt_header->OptionalHeader.SizeOfStackReserve || broken(truncated),
258 "%u: MaximumStackSize wrong %lx / %lx\n", id,
259 image.MaximumStackSize, (SIZE_T)nt_header->OptionalHeader.SizeOfStackReserve );
260 ok( image.CommittedStackSize == nt_header->OptionalHeader.SizeOfStackCommit || broken(truncated),
261 "%u: CommittedStackSize wrong %lx / %lx\n", id,
262 image.CommittedStackSize, (SIZE_T)nt_header->OptionalHeader.SizeOfStackCommit );
263 ok( image.SubSystemType == nt_header->OptionalHeader.Subsystem || broken(truncated),
264 "%u: SubSystemType wrong %08x / %08x\n", id,
265 image.SubSystemType, nt_header->OptionalHeader.Subsystem );
266 ok( image.SubsystemVersionLow == nt_header->OptionalHeader.MinorSubsystemVersion,
267 "%u: SubsystemVersionLow wrong %04x / %04x\n", id,
268 image.SubsystemVersionLow, nt_header->OptionalHeader.MinorSubsystemVersion );
269 ok( image.SubsystemVersionHigh == nt_header->OptionalHeader.MajorSubsystemVersion,
270 "%u: SubsystemVersionHigh wrong %04x / %04x\n", id,
271 image.SubsystemVersionHigh, nt_header->OptionalHeader.MajorSubsystemVersion );
272 ok( image.ImageCharacteristics == nt_header->FileHeader.Characteristics,
273 "%u: ImageCharacteristics wrong %04x / %04x\n", id,
274 image.ImageCharacteristics, nt_header->FileHeader.Characteristics );
275 ok( image.DllCharacteristics == nt_header->OptionalHeader.DllCharacteristics || broken(truncated),
276 "%u: DllCharacteristics wrong %04x / %04x\n", id,
277 image.DllCharacteristics, nt_header->OptionalHeader.DllCharacteristics );
278 ok( image.Machine == nt_header->FileHeader.Machine, "%u: Machine wrong %04x / %04x\n", id,
279 image.Machine, nt_header->FileHeader.Machine );
280 ok( image.LoaderFlags == nt_header->OptionalHeader.LoaderFlags,
281 "%u: LoaderFlags wrong %08x / %08x\n", id,
282 image.LoaderFlags, nt_header->OptionalHeader.LoaderFlags );
283 ok( image.ImageFileSize == file_size || broken(!image.ImageFileSize), /* winxpsp1 */
284 "%u: ImageFileSize wrong %08x / %08x\n", id, image.ImageFileSize, file_size );
285 ok( image.CheckSum == nt_header->OptionalHeader.CheckSum, "%u: CheckSum wrong %08x / %08x\n", id,
286 image.CheckSum, nt_header->OptionalHeader.CheckSum );
287 /* FIXME: needs more work: */
288 /* image.GpValue */
289 /* image.ImageFlags */
290 /* image.ImageContainsCode */
291 CloseHandle( mapping );
292 CloseHandle( file );
295 /* helper to test image section mapping */
296 static NTSTATUS map_image_section( const IMAGE_NT_HEADERS *nt_header )
298 char temp_path[MAX_PATH];
299 char dll_name[MAX_PATH];
300 LARGE_INTEGER size;
301 HANDLE file, map;
302 NTSTATUS status;
304 GetTempPathA(MAX_PATH, temp_path);
305 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
307 size.u.LowPart = create_test_dll( &dos_header, sizeof(dos_header), nt_header, dll_name );
308 ok( size.u.LowPart, "could not create %s\n", dll_name);
309 size.u.HighPart = 0;
311 file = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
312 ok(file != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError());
314 status = pNtCreateSection(&map, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
315 NULL, &size, PAGE_READONLY, SEC_IMAGE, file );
316 if (!status)
318 SECTION_BASIC_INFORMATION info;
319 ULONG info_size = 0xdeadbeef;
320 NTSTATUS ret = pNtQuerySection( map, SectionBasicInformation, &info, sizeof(info), &info_size );
321 ok( !ret, "NtQuerySection failed err %x\n", ret );
322 ok( info_size == sizeof(info), "NtQuerySection wrong size %u\n", info_size );
323 ok( info.Attributes == (SEC_IMAGE | SEC_FILE), "NtQuerySection wrong attr %x\n", info.Attributes );
324 ok( info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", info.BaseAddress );
325 todo_wine
326 ok( info.Size.QuadPart == size.QuadPart, "NtQuerySection wrong size %x%08x / %x%08x\n",
327 info.Size.u.HighPart, info.Size.u.LowPart, size.u.HighPart, size.u.LowPart );
328 query_image_section( 1000, dll_name, nt_header );
330 if (map) CloseHandle( map );
331 CloseHandle( file );
332 DeleteFileA( dll_name );
333 return status;
337 static void test_Loader(void)
339 static const struct test_data
341 DWORD size_of_dos_header;
342 WORD number_of_sections, size_of_optional_header;
343 DWORD section_alignment, file_alignment;
344 DWORD size_of_image, size_of_headers;
345 DWORD errors[4]; /* 0 means LoadLibrary should succeed */
346 } td[] =
348 { sizeof(dos_header),
349 1, 0, 0, 0, 0, 0,
350 { ERROR_BAD_EXE_FORMAT }
352 { sizeof(dos_header),
353 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
354 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0xe00,
355 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
356 { ERROR_BAD_EXE_FORMAT } /* XP doesn't like too small image size */
358 { sizeof(dos_header),
359 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
360 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
361 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
362 { ERROR_SUCCESS }
364 { sizeof(dos_header),
365 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
366 0x1f00,
367 0x1000,
368 { ERROR_SUCCESS }
370 { sizeof(dos_header),
371 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x200,
372 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x200,
373 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
374 { ERROR_SUCCESS, ERROR_INVALID_ADDRESS } /* vista is more strict */
376 { sizeof(dos_header),
377 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x1000,
378 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
379 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
380 { ERROR_BAD_EXE_FORMAT } /* XP doesn't like alignments */
382 { sizeof(dos_header),
383 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
384 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
385 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
386 { ERROR_SUCCESS }
388 { sizeof(dos_header),
389 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
390 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
391 0x200,
392 { ERROR_SUCCESS }
394 /* Mandatory are all fields up to SizeOfHeaders, everything else
395 * is really optional (at least that's true for XP).
397 { sizeof(dos_header),
398 1, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
399 sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER) + 0x10,
400 sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER),
401 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT, ERROR_INVALID_ADDRESS,
402 ERROR_NOACCESS }
404 { sizeof(dos_header),
405 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
406 0xd0, /* beyond of the end of file */
407 0xc0, /* beyond of the end of file */
408 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
410 { sizeof(dos_header),
411 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
412 0x1000,
414 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
416 { sizeof(dos_header),
417 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
420 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
422 #if 0 /* not power of 2 alignments need more test cases */
423 { sizeof(dos_header),
424 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x300, 0x300,
427 { ERROR_BAD_EXE_FORMAT } /* alignment is not power of 2 */
429 #endif
430 { sizeof(dos_header),
431 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 4, 4,
434 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
436 { sizeof(dos_header),
437 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 1, 1,
440 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
442 { sizeof(dos_header),
443 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
446 { ERROR_BAD_EXE_FORMAT } /* image size == 0 -> failure */
448 /* the following data mimics the PE image which upack creates */
449 { 0x10,
450 1, 0x148, 0x1000, 0x200,
451 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
452 0x200,
453 { ERROR_SUCCESS }
455 /* Minimal PE image that XP is able to load: 92 bytes */
456 { 0x04,
457 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum),
458 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
461 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
463 /* Minimal PE image that Windows7 is able to load: 268 bytes */
464 { 0x04,
465 0, 0xf0, /* optional header size just forces 0xf0 bytes to be written,
466 0 or another number don't change the behaviour, what really
467 matters is file size regardless of values in the headers */
468 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
469 0x40, /* minimal image size that Windows7 accepts */
471 { ERROR_SUCCESS }
474 int i;
475 DWORD file_size;
476 HMODULE hlib, hlib_as_data_file;
477 char temp_path[MAX_PATH];
478 char dll_name[MAX_PATH];
479 SIZE_T size;
480 BOOL ret;
481 NTSTATUS status;
482 WORD orig_machine = nt_header_template.FileHeader.Machine;
483 IMAGE_NT_HEADERS nt_header;
485 /* prevent displaying of the "Unable to load this DLL" message box */
486 SetErrorMode(SEM_FAILCRITICALERRORS);
488 GetTempPathA(MAX_PATH, temp_path);
490 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
492 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
494 nt_header = nt_header_template;
495 nt_header.FileHeader.NumberOfSections = td[i].number_of_sections;
496 nt_header.FileHeader.SizeOfOptionalHeader = td[i].size_of_optional_header;
498 nt_header.OptionalHeader.SectionAlignment = td[i].section_alignment;
499 nt_header.OptionalHeader.FileAlignment = td[i].file_alignment;
500 nt_header.OptionalHeader.SizeOfImage = td[i].size_of_image;
501 nt_header.OptionalHeader.SizeOfHeaders = td[i].size_of_headers;
503 file_size = create_test_dll( &dos_header, td[i].size_of_dos_header, &nt_header, dll_name );
504 if (!file_size)
506 ok(0, "could not create %s\n", dll_name);
507 break;
510 SetLastError(0xdeadbeef);
511 hlib = LoadLibraryA(dll_name);
512 if (hlib)
514 MEMORY_BASIC_INFORMATION info;
515 void *ptr;
517 ok( td[i].errors[0] == ERROR_SUCCESS, "%d: should have failed\n", i );
519 SetLastError(0xdeadbeef);
520 size = VirtualQuery(hlib, &info, sizeof(info));
521 ok(size == sizeof(info),
522 "%d: VirtualQuery error %d\n", i, GetLastError());
523 ok(info.BaseAddress == hlib, "%d: %p != %p\n", i, info.BaseAddress, hlib);
524 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
525 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
526 ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %lx != expected %x\n",
527 i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
528 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
529 if (nt_header.OptionalHeader.SectionAlignment < page_size)
530 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
531 else
532 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
533 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
535 SetLastError(0xdeadbeef);
536 ptr = VirtualAlloc(hlib, page_size, MEM_COMMIT, info.Protect);
537 ok(!ptr, "%d: VirtualAlloc should fail\n", i);
538 /* FIXME: Remove once Wine is fixed */
539 todo_wine_if (info.Protect == PAGE_WRITECOPY || info.Protect == PAGE_EXECUTE_WRITECOPY)
540 ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError());
542 SetLastError(0xdeadbeef);
543 size = VirtualQuery((char *)hlib + info.RegionSize, &info, sizeof(info));
544 ok(size == sizeof(info),
545 "%d: VirtualQuery error %d\n", i, GetLastError());
546 if (nt_header.OptionalHeader.SectionAlignment == page_size ||
547 nt_header.OptionalHeader.SectionAlignment == nt_header.OptionalHeader.FileAlignment)
549 ok(info.BaseAddress == (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %p != expected %p\n",
550 i, info.BaseAddress, (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
551 ok(info.AllocationBase == 0, "%d: %p != 0\n", i, info.AllocationBase);
552 ok(info.AllocationProtect == 0, "%d: %x != 0\n", i, info.AllocationProtect);
553 /*ok(info.RegionSize == not_practical_value, "%d: %lx != not_practical_value\n", i, info.RegionSize);*/
554 ok(info.State == MEM_FREE, "%d: %x != MEM_FREE\n", i, info.State);
555 ok(info.Type == 0, "%d: %x != 0\n", i, info.Type);
556 ok(info.Protect == PAGE_NOACCESS, "%d: %x != PAGE_NOACCESS\n", i, info.Protect);
558 else
560 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
561 ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib);
562 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
563 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
564 ok(info.RegionSize == ALIGN_SIZE(file_size, page_size), "%d: got %lx != expected %x\n",
565 i, info.RegionSize, ALIGN_SIZE(file_size, page_size));
566 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
567 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
568 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
571 /* header: check the zeroing of alignment */
572 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
574 const char *start;
576 start = (const char *)hlib + nt_header.OptionalHeader.SizeOfHeaders;
577 size = ALIGN_SIZE((ULONG_PTR)start, page_size) - (ULONG_PTR)start;
578 ok(!memcmp(start, filler, size), "%d: header alignment is not cleared\n", i);
581 if (nt_header.FileHeader.NumberOfSections)
583 SetLastError(0xdeadbeef);
584 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
585 ok(size == sizeof(info),
586 "%d: VirtualQuery error %d\n", i, GetLastError());
587 if (nt_header.OptionalHeader.SectionAlignment < page_size)
589 ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib);
590 ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %lx != expected %x\n",
591 i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
592 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
594 else
596 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
597 ok(info.RegionSize == ALIGN_SIZE(section.Misc.VirtualSize, page_size), "%d: got %lx != expected %x\n",
598 i, info.RegionSize, ALIGN_SIZE(section.Misc.VirtualSize, page_size));
599 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
601 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
602 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
603 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
604 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
606 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
607 ok(!memcmp((const char *)hlib + section.VirtualAddress + section.PointerToRawData, &nt_header, section.SizeOfRawData), "wrong section data\n");
608 else
609 ok(!memcmp((const char *)hlib + section.PointerToRawData, section_data, section.SizeOfRawData), "wrong section data\n");
611 /* check the zeroing of alignment */
612 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
614 const char *start;
616 start = (const char *)hlib + section.VirtualAddress + section.PointerToRawData + section.SizeOfRawData;
617 size = ALIGN_SIZE((ULONG_PTR)start, page_size) - (ULONG_PTR)start;
618 ok(memcmp(start, filler, size), "%d: alignment should not be cleared\n", i);
621 SetLastError(0xdeadbeef);
622 ptr = VirtualAlloc((char *)hlib + section.VirtualAddress, page_size, MEM_COMMIT, info.Protect);
623 ok(!ptr, "%d: VirtualAlloc should fail\n", i);
624 /* FIXME: Remove once Wine is fixed */
625 todo_wine_if (info.Protect == PAGE_WRITECOPY || info.Protect == PAGE_EXECUTE_WRITECOPY)
626 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_INVALID_ADDRESS,
627 "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError());
630 SetLastError(0xdeadbeef);
631 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
632 ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
633 ok(hlib_as_data_file == hlib, "hlib_as_file and hlib are different\n");
635 SetLastError(0xdeadbeef);
636 ret = FreeLibrary(hlib);
637 ok(ret, "FreeLibrary error %d\n", GetLastError());
639 SetLastError(0xdeadbeef);
640 hlib = GetModuleHandleA(dll_name);
641 ok(hlib != 0, "GetModuleHandle error %u\n", GetLastError());
643 SetLastError(0xdeadbeef);
644 ret = FreeLibrary(hlib_as_data_file);
645 ok(ret, "FreeLibrary error %d\n", GetLastError());
647 hlib = GetModuleHandleA(dll_name);
648 ok(!hlib, "GetModuleHandle should fail\n");
650 SetLastError(0xdeadbeef);
651 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
652 ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
653 ok((ULONG_PTR)hlib_as_data_file & 1, "hlib_as_data_file is even\n");
655 hlib = GetModuleHandleA(dll_name);
656 ok(!hlib, "GetModuleHandle should fail\n");
658 SetLastError(0xdeadbeef);
659 ret = FreeLibrary(hlib_as_data_file);
660 ok(ret, "FreeLibrary error %d\n", GetLastError());
662 query_image_section( i, dll_name, &nt_header );
664 else
666 BOOL error_match;
667 int error_index;
669 error_match = FALSE;
670 for (error_index = 0;
671 ! error_match && error_index < sizeof(td[i].errors) / sizeof(DWORD);
672 error_index++)
674 error_match = td[i].errors[error_index] == GetLastError();
676 ok(error_match, "%d: unexpected error %d\n", i, GetLastError());
679 SetLastError(0xdeadbeef);
680 ret = DeleteFileA(dll_name);
681 ok(ret, "DeleteFile error %d\n", GetLastError());
684 nt_header = nt_header_template;
685 nt_header.FileHeader.NumberOfSections = 1;
686 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
688 nt_header.OptionalHeader.SectionAlignment = page_size;
689 nt_header.OptionalHeader.AddressOfEntryPoint = 0x1234;
690 nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
691 nt_header.OptionalHeader.FileAlignment = page_size;
692 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
693 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
695 status = map_image_section( &nt_header );
696 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
698 dos_header.e_magic = 0;
699 status = map_image_section( &nt_header );
700 ok( status == STATUS_INVALID_IMAGE_NOT_MZ, "NtCreateSection error %08x\n", status );
702 dos_header.e_magic = IMAGE_DOS_SIGNATURE;
703 nt_header.Signature = IMAGE_OS2_SIGNATURE;
704 status = map_image_section( &nt_header );
705 ok( status == STATUS_INVALID_IMAGE_NE_FORMAT, "NtCreateSection error %08x\n", status );
707 nt_header.Signature = 0xdeadbeef;
708 status = map_image_section( &nt_header );
709 ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection error %08x\n", status );
711 nt_header.Signature = IMAGE_NT_SIGNATURE;
712 nt_header.OptionalHeader.Magic = 0xdead;
713 status = map_image_section( &nt_header );
714 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08x\n", status );
716 nt_header.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC;
717 nt_header.FileHeader.Machine = 0xdead;
718 status = map_image_section( &nt_header );
719 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
720 "NtCreateSection error %08x\n", status );
722 nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_UNKNOWN;
723 status = map_image_section( &nt_header );
724 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
725 "NtCreateSection error %08x\n", status );
727 switch (orig_machine)
729 case IMAGE_FILE_MACHINE_I386: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64; break;
730 case IMAGE_FILE_MACHINE_AMD64: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_I386; break;
731 case IMAGE_FILE_MACHINE_ARMNT: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_ARM64; break;
732 case IMAGE_FILE_MACHINE_ARM64: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_ARMNT; break;
734 status = map_image_section( &nt_header );
735 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
736 "NtCreateSection error %08x\n", status );
738 if (nt_header.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
740 IMAGE_NT_HEADERS64 nt64;
742 memset( &nt64, 0, sizeof(nt64) );
743 nt64.Signature = IMAGE_NT_SIGNATURE;
744 nt64.FileHeader.Machine = orig_machine;
745 nt64.FileHeader.NumberOfSections = 1;
746 nt64.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
747 nt64.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
748 nt64.OptionalHeader.MajorLinkerVersion = 1;
749 nt64.OptionalHeader.ImageBase = 0x10000000;
750 nt64.OptionalHeader.MajorOperatingSystemVersion = 4;
751 nt64.OptionalHeader.MajorImageVersion = 1;
752 nt64.OptionalHeader.MajorSubsystemVersion = 4;
753 nt64.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt64) + sizeof(IMAGE_SECTION_HEADER);
754 nt64.OptionalHeader.SizeOfImage = nt64.OptionalHeader.SizeOfHeaders + 0x1000;
755 nt64.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
756 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64 );
757 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08x\n", status );
759 else
761 IMAGE_NT_HEADERS32 nt32;
763 memset( &nt32, 0, sizeof(nt32) );
764 nt32.Signature = IMAGE_NT_SIGNATURE;
765 nt32.FileHeader.Machine = orig_machine;
766 nt32.FileHeader.NumberOfSections = 1;
767 nt32.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32);
768 nt32.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
769 nt32.OptionalHeader.MajorLinkerVersion = 1;
770 nt32.OptionalHeader.ImageBase = 0x10000000;
771 nt32.OptionalHeader.MajorOperatingSystemVersion = 4;
772 nt32.OptionalHeader.MajorImageVersion = 1;
773 nt32.OptionalHeader.MajorSubsystemVersion = 4;
774 nt32.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt32) + sizeof(IMAGE_SECTION_HEADER);
775 nt32.OptionalHeader.SizeOfImage = nt32.OptionalHeader.SizeOfHeaders + 0x1000;
776 nt32.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
777 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32 );
778 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08x\n", status );
781 nt_header.FileHeader.Machine = orig_machine; /* restore it for the next tests */
784 /* Verify linking style of import descriptors */
785 static void test_ImportDescriptors(void)
787 HMODULE kernel32_module = NULL;
788 PIMAGE_DOS_HEADER d_header;
789 PIMAGE_NT_HEADERS nt_headers;
790 DWORD import_dir_size;
791 DWORD_PTR dir_offset;
792 PIMAGE_IMPORT_DESCRIPTOR import_chunk;
794 /* Load kernel32 module */
795 kernel32_module = GetModuleHandleA("kernel32.dll");
796 assert( kernel32_module != NULL );
798 /* Get PE header info from module image */
799 d_header = (PIMAGE_DOS_HEADER) kernel32_module;
800 nt_headers = (PIMAGE_NT_HEADERS) (((char*) d_header) +
801 d_header->e_lfanew);
803 /* Get size of import entry directory */
804 import_dir_size = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
805 if (!import_dir_size)
807 skip("Unable to continue testing due to missing import directory.\n");
808 return;
811 /* Get address of first import chunk */
812 dir_offset = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
813 import_chunk = RVAToAddr(dir_offset, kernel32_module);
814 ok(import_chunk != 0, "Invalid import_chunk: %p\n", import_chunk);
815 if (!import_chunk) return;
817 /* Iterate through import descriptors and verify set name,
818 * OriginalFirstThunk, and FirstThunk. Core Windows DLLs, such as
819 * kernel32.dll, don't use Borland-style linking, where the table of
820 * imported names is stored directly in FirstThunk and overwritten
821 * by the relocation, instead of being stored in OriginalFirstThunk.
822 * */
823 for (; import_chunk->FirstThunk; import_chunk++)
825 LPCSTR module_name = RVAToAddr(import_chunk->Name, kernel32_module);
826 PIMAGE_THUNK_DATA name_table = RVAToAddr(
827 U(*import_chunk).OriginalFirstThunk, kernel32_module);
828 PIMAGE_THUNK_DATA iat = RVAToAddr(
829 import_chunk->FirstThunk, kernel32_module);
830 ok(module_name != NULL, "Imported module name should not be NULL\n");
831 ok(name_table != NULL,
832 "Name table for imported module %s should not be NULL\n",
833 module_name);
834 ok(iat != NULL, "IAT for imported module %s should not be NULL\n",
835 module_name);
839 static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL is_dll)
841 HANDLE hfile, hmap;
842 NTSTATUS status;
843 LARGE_INTEGER offset;
844 SIZE_T size;
845 void *addr1, *addr2;
846 MEMORY_BASIC_INFORMATION info;
848 if (!pNtMapViewOfSection) return;
850 SetLastError(0xdeadbeef);
851 hfile = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
852 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError());
854 SetLastError(0xdeadbeef);
855 hmap = CreateFileMappingW(hfile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, 0);
856 ok(hmap != 0, "CreateFileMapping error %d\n", GetLastError());
858 offset.u.LowPart = 0;
859 offset.u.HighPart = 0;
861 addr1 = NULL;
862 size = 0;
863 status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr1, 0, 0, &offset,
864 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
865 ok(status == STATUS_SUCCESS, "NtMapViewOfSection error %x\n", status);
866 ok(addr1 != 0, "mapped address should be valid\n");
868 SetLastError(0xdeadbeef);
869 size = VirtualQuery((char *)addr1 + section.VirtualAddress, &info, sizeof(info));
870 ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
871 ok(info.BaseAddress == (char *)addr1 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr1 + section.VirtualAddress);
872 ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size);
873 ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
874 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
875 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
876 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
877 ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
879 addr2 = NULL;
880 size = 0;
881 status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr2, 0, 0, &offset,
882 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
883 ok(status == STATUS_IMAGE_NOT_AT_BASE, "expected STATUS_IMAGE_NOT_AT_BASE, got %x\n", status);
884 ok(addr2 != 0, "mapped address should be valid\n");
885 ok(addr2 != addr1, "mapped addresses should be different\n");
887 SetLastError(0xdeadbeef);
888 size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info));
889 ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
890 ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress);
891 ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size);
892 ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
893 ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2);
894 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
895 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
896 ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
898 status = pNtUnmapViewOfSection(GetCurrentProcess(), addr2);
899 ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status);
901 addr2 = MapViewOfFile(hmap, 0, 0, 0, 0);
902 ok(addr2 != 0, "mapped address should be valid\n");
903 ok(addr2 != addr1, "mapped addresses should be different\n");
905 SetLastError(0xdeadbeef);
906 size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info));
907 ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
908 ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress);
909 ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size);
910 ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
911 ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2);
912 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
913 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
914 ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
916 UnmapViewOfFile(addr2);
918 SetLastError(0xdeadbeef);
919 addr2 = LoadLibraryA(dll_name);
920 if (is_dll)
922 ok(!addr2, "LoadLibrary should fail, is_dll %d\n", is_dll);
923 ok(GetLastError() == ERROR_INVALID_ADDRESS, "expected ERROR_INVALID_ADDRESS, got %d\n", GetLastError());
925 else
927 BOOL ret;
928 ok(addr2 != 0, "LoadLibrary error %d, is_dll %d\n", GetLastError(), is_dll);
929 ok(addr2 != addr1, "mapped addresses should be different\n");
931 SetLastError(0xdeadbeef);
932 ret = FreeLibrary(addr2);
933 ok(ret, "FreeLibrary error %d\n", GetLastError());
936 status = pNtUnmapViewOfSection(GetCurrentProcess(), addr1);
937 ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status);
939 CloseHandle(hmap);
940 CloseHandle(hfile);
943 static BOOL is_mem_writable(DWORD prot)
945 switch (prot & 0xff)
947 case PAGE_READWRITE:
948 case PAGE_WRITECOPY:
949 case PAGE_EXECUTE_READWRITE:
950 case PAGE_EXECUTE_WRITECOPY:
951 return TRUE;
953 default:
954 return FALSE;
958 static void test_VirtualProtect(void *base, void *section)
960 static const struct test_data
962 DWORD prot_set, prot_get;
963 } td[] =
965 { 0, 0 }, /* 0x00 */
966 { PAGE_NOACCESS, PAGE_NOACCESS }, /* 0x01 */
967 { PAGE_READONLY, PAGE_READONLY }, /* 0x02 */
968 { PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x03 */
969 { PAGE_READWRITE, PAGE_WRITECOPY }, /* 0x04 */
970 { PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x05 */
971 { PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x06 */
972 { PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x07 */
973 { PAGE_WRITECOPY, PAGE_WRITECOPY }, /* 0x08 */
974 { PAGE_WRITECOPY | PAGE_NOACCESS, 0 }, /* 0x09 */
975 { PAGE_WRITECOPY | PAGE_READONLY, 0 }, /* 0x0a */
976 { PAGE_WRITECOPY | PAGE_NOACCESS | PAGE_READONLY, 0 }, /* 0x0b */
977 { PAGE_WRITECOPY | PAGE_READWRITE, 0 }, /* 0x0c */
978 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x0d */
979 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x0e */
980 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x0f */
982 { PAGE_EXECUTE, PAGE_EXECUTE }, /* 0x10 */
983 { PAGE_EXECUTE_READ, PAGE_EXECUTE_READ }, /* 0x20 */
984 { PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x30 */
985 { PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY }, /* 0x40 */
986 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0x50 */
987 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0x60 */
988 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x70 */
989 { PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_WRITECOPY }, /* 0x80 */
990 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE, 0 }, /* 0x90 */
991 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ, 0 }, /* 0xa0 */
992 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0xb0 */
993 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE, 0 }, /* 0xc0 */
994 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0xd0 */
995 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0xe0 */
996 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 } /* 0xf0 */
998 DWORD ret, orig_prot, old_prot, rw_prot, exec_prot, i, j;
999 MEMORY_BASIC_INFORMATION info;
1001 SetLastError(0xdeadbeef);
1002 ret = VirtualProtect(section, page_size, PAGE_NOACCESS, &old_prot);
1003 ok(ret, "VirtualProtect error %d\n", GetLastError());
1005 orig_prot = old_prot;
1007 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
1009 SetLastError(0xdeadbeef);
1010 ret = VirtualQuery(section, &info, sizeof(info));
1011 ok(ret, "VirtualQuery failed %d\n", GetLastError());
1012 ok(info.BaseAddress == section, "%d: got %p != expected %p\n", i, info.BaseAddress, section);
1013 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1014 ok(info.Protect == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, info.Protect);
1015 ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
1016 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1017 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1018 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1020 old_prot = 0xdeadbeef;
1021 SetLastError(0xdeadbeef);
1022 ret = VirtualProtect(section, page_size, td[i].prot_set, &old_prot);
1023 if (td[i].prot_get)
1025 ok(ret, "%d: VirtualProtect error %d, requested prot %#x\n", i, GetLastError(), td[i].prot_set);
1026 ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
1028 SetLastError(0xdeadbeef);
1029 ret = VirtualQuery(section, &info, sizeof(info));
1030 ok(ret, "VirtualQuery failed %d\n", GetLastError());
1031 ok(info.BaseAddress == section, "%d: got %p != expected %p\n", i, info.BaseAddress, section);
1032 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1033 ok(info.Protect == td[i].prot_get, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_get);
1034 ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
1035 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1036 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1037 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1039 else
1041 ok(!ret, "%d: VirtualProtect should fail\n", i);
1042 ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
1045 old_prot = 0xdeadbeef;
1046 SetLastError(0xdeadbeef);
1047 ret = VirtualProtect(section, page_size, PAGE_NOACCESS, &old_prot);
1048 ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
1049 if (td[i].prot_get)
1050 ok(old_prot == td[i].prot_get, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_get);
1051 else
1052 ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
1055 exec_prot = 0;
1057 for (i = 0; i <= 4; i++)
1059 rw_prot = 0;
1061 for (j = 0; j <= 4; j++)
1063 DWORD prot = exec_prot | rw_prot;
1065 SetLastError(0xdeadbeef);
1066 ret = VirtualProtect(section, page_size, prot, &old_prot);
1067 if ((rw_prot && exec_prot) || (!rw_prot && !exec_prot))
1069 ok(!ret, "VirtualProtect(%02x) should fail\n", prot);
1070 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1072 else
1073 ok(ret, "VirtualProtect(%02x) error %d\n", prot, GetLastError());
1075 rw_prot = 1 << j;
1078 exec_prot = 1 << (i + 4);
1081 SetLastError(0xdeadbeef);
1082 ret = VirtualProtect(section, page_size, orig_prot, &old_prot);
1083 ok(ret, "VirtualProtect error %d\n", GetLastError());
1086 static void test_section_access(void)
1088 static const struct test_data
1090 DWORD scn_file_access, scn_page_access, scn_page_access_after_write;
1091 } td[] =
1093 { 0, PAGE_NOACCESS, 0 },
1094 { IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1095 { IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1096 { IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1097 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1098 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ },
1099 { IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1100 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1102 { IMAGE_SCN_CNT_INITIALIZED_DATA, PAGE_NOACCESS, 0 },
1103 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1104 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1105 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1106 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1107 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
1108 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1109 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1111 { IMAGE_SCN_CNT_UNINITIALIZED_DATA, PAGE_NOACCESS, 0 },
1112 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1113 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1114 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1115 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1116 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
1117 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1118 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE }
1120 char buf[256];
1121 int i;
1122 DWORD dummy, file_align;
1123 HANDLE hfile;
1124 HMODULE hlib;
1125 char temp_path[MAX_PATH];
1126 char dll_name[MAX_PATH];
1127 SIZE_T size;
1128 MEMORY_BASIC_INFORMATION info;
1129 STARTUPINFOA sti;
1130 PROCESS_INFORMATION pi;
1131 DWORD ret;
1133 /* prevent displaying of the "Unable to load this DLL" message box */
1134 SetErrorMode(SEM_FAILCRITICALERRORS);
1136 GetTempPathA(MAX_PATH, temp_path);
1138 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
1140 IMAGE_NT_HEADERS nt_header;
1142 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
1144 /*trace("creating %s\n", dll_name);*/
1145 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
1146 if (hfile == INVALID_HANDLE_VALUE)
1148 ok(0, "could not create %s\n", dll_name);
1149 return;
1152 SetLastError(0xdeadbeef);
1153 ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
1154 ok(ret, "WriteFile error %d\n", GetLastError());
1156 nt_header = nt_header_template;
1157 nt_header.FileHeader.NumberOfSections = 1;
1158 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1159 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED;
1161 nt_header.OptionalHeader.SectionAlignment = page_size;
1162 nt_header.OptionalHeader.FileAlignment = 0x200;
1163 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
1164 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
1165 SetLastError(0xdeadbeef);
1166 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
1167 ok(ret, "WriteFile error %d\n", GetLastError());
1168 SetLastError(0xdeadbeef);
1169 ret = WriteFile(hfile, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
1170 ok(ret, "WriteFile error %d\n", GetLastError());
1172 section.SizeOfRawData = sizeof(section_data);
1173 section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
1174 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
1175 section.Misc.VirtualSize = section.SizeOfRawData;
1176 section.Characteristics = td[i].scn_file_access;
1177 SetLastError(0xdeadbeef);
1178 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
1179 ok(ret, "WriteFile error %d\n", GetLastError());
1181 file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
1182 assert(file_align < sizeof(filler));
1183 SetLastError(0xdeadbeef);
1184 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
1185 ok(ret, "WriteFile error %d\n", GetLastError());
1187 /* section data */
1188 SetLastError(0xdeadbeef);
1189 ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
1190 ok(ret, "WriteFile error %d\n", GetLastError());
1192 CloseHandle(hfile);
1194 SetLastError(0xdeadbeef);
1195 hlib = LoadLibraryA(dll_name);
1196 ok(hlib != 0, "LoadLibrary error %d\n", GetLastError());
1198 SetLastError(0xdeadbeef);
1199 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
1200 ok(size == sizeof(info),
1201 "%d: VirtualQuery error %d\n", i, GetLastError());
1202 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
1203 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1204 ok(info.Protect == td[i].scn_page_access, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access);
1205 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
1206 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1207 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1208 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1209 if (info.Protect != PAGE_NOACCESS)
1210 ok(!memcmp((const char *)info.BaseAddress, section_data, section.SizeOfRawData), "wrong section data\n");
1212 test_VirtualProtect(hlib, (char *)hlib + section.VirtualAddress);
1214 /* Windows changes the WRITECOPY to WRITE protection on an image section write (for a changed page only) */
1215 if (is_mem_writable(info.Protect))
1217 char *p = info.BaseAddress;
1218 *p = 0xfe;
1219 SetLastError(0xdeadbeef);
1220 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
1221 ok(size == sizeof(info), "%d: VirtualQuery error %d\n", i, GetLastError());
1222 /* FIXME: remove the condition below once Wine is fixed */
1223 todo_wine_if (info.Protect == PAGE_WRITECOPY || info.Protect == PAGE_EXECUTE_WRITECOPY)
1224 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);
1227 SetLastError(0xdeadbeef);
1228 ret = FreeLibrary(hlib);
1229 ok(ret, "FreeLibrary error %d\n", GetLastError());
1231 test_image_mapping(dll_name, td[i].scn_page_access, TRUE);
1233 /* reset IMAGE_FILE_DLL otherwise CreateProcess fails */
1234 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_RELOCS_STRIPPED;
1235 SetLastError(0xdeadbeef);
1236 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1237 /* LoadLibrary called on an already memory-mapped file in
1238 * test_image_mapping() above leads to a file handle leak
1239 * under nt4, and inability to overwrite and delete the file
1240 * due to sharing violation error. Ignore it and skip the test,
1241 * but leave a not deletable temporary file.
1243 ok(hfile != INVALID_HANDLE_VALUE || broken(hfile == INVALID_HANDLE_VALUE) /* nt4 */,
1244 "CreateFile error %d\n", GetLastError());
1245 if (hfile == INVALID_HANDLE_VALUE) goto nt4_is_broken;
1246 SetFilePointer(hfile, sizeof(dos_header), NULL, FILE_BEGIN);
1247 SetLastError(0xdeadbeef);
1248 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
1249 ok(ret, "WriteFile error %d\n", GetLastError());
1250 CloseHandle(hfile);
1252 memset(&sti, 0, sizeof(sti));
1253 sti.cb = sizeof(sti);
1254 SetLastError(0xdeadbeef);
1255 ret = CreateProcessA(dll_name, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &sti, &pi);
1256 ok(ret, "CreateProcess() error %d\n", GetLastError());
1258 SetLastError(0xdeadbeef);
1259 size = VirtualQueryEx(pi.hProcess, (char *)hlib + section.VirtualAddress, &info, sizeof(info));
1260 ok(size == sizeof(info),
1261 "%d: VirtualQuery error %d\n", i, GetLastError());
1262 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
1263 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1264 ok(info.Protect == td[i].scn_page_access, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access);
1265 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
1266 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1267 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1268 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1269 if (info.Protect != PAGE_NOACCESS)
1271 SetLastError(0xdeadbeef);
1272 ret = ReadProcessMemory(pi.hProcess, info.BaseAddress, buf, section.SizeOfRawData, NULL);
1273 ok(ret, "ReadProcessMemory() error %d\n", GetLastError());
1274 ok(!memcmp(buf, section_data, section.SizeOfRawData), "wrong section data\n");
1277 SetLastError(0xdeadbeef);
1278 ret = TerminateProcess(pi.hProcess, 0);
1279 ok(ret, "TerminateProcess() error %d\n", GetLastError());
1280 ret = WaitForSingleObject(pi.hProcess, 3000);
1281 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
1283 CloseHandle(pi.hThread);
1284 CloseHandle(pi.hProcess);
1286 test_image_mapping(dll_name, td[i].scn_page_access, FALSE);
1288 nt4_is_broken:
1289 SetLastError(0xdeadbeef);
1290 ret = DeleteFileA(dll_name);
1291 ok(ret || broken(!ret) /* nt4 */, "DeleteFile error %d\n", GetLastError());
1295 static void test_import_resolution(void)
1297 char temp_path[MAX_PATH];
1298 char dll_name[MAX_PATH];
1299 DWORD dummy;
1300 void *expect;
1301 char *str;
1302 HANDLE hfile;
1303 HMODULE mod, mod2;
1304 struct imports
1306 IMAGE_IMPORT_DESCRIPTOR descr[2];
1307 IMAGE_THUNK_DATA original_thunks[2];
1308 IMAGE_THUNK_DATA thunks[2];
1309 char module[16];
1310 struct { WORD hint; char name[32]; } function;
1311 IMAGE_TLS_DIRECTORY tls;
1312 char tls_data[16];
1313 SHORT tls_index;
1314 } data, *ptr;
1315 IMAGE_NT_HEADERS nt;
1316 IMAGE_SECTION_HEADER section;
1317 int test;
1319 for (test = 0; test < 3; test++)
1321 #define DATA_RVA(ptr) (page_size + ((char *)(ptr) - (char *)&data))
1322 nt = nt_header_template;
1323 nt.FileHeader.NumberOfSections = 1;
1324 nt.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1325 nt.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_RELOCS_STRIPPED;
1326 if (test != 2) nt.FileHeader.Characteristics |= IMAGE_FILE_DLL;
1327 nt.OptionalHeader.SectionAlignment = page_size;
1328 nt.OptionalHeader.FileAlignment = 0x200;
1329 nt.OptionalHeader.ImageBase = 0x12340000;
1330 nt.OptionalHeader.SizeOfImage = 2 * page_size;
1331 nt.OptionalHeader.SizeOfHeaders = nt.OptionalHeader.FileAlignment;
1332 nt.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
1333 memset( nt.OptionalHeader.DataDirectory, 0, sizeof(nt.OptionalHeader.DataDirectory) );
1334 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = sizeof(data.descr);
1335 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = DATA_RVA(data.descr);
1336 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = sizeof(data.tls);
1337 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = DATA_RVA(&data.tls);
1339 memset( &data, 0, sizeof(data) );
1340 data.descr[0].u.OriginalFirstThunk = DATA_RVA( data.original_thunks );
1341 data.descr[0].FirstThunk = DATA_RVA( data.thunks );
1342 data.descr[0].Name = DATA_RVA( data.module );
1343 strcpy( data.module, "kernel32.dll" );
1344 strcpy( data.function.name, "CreateEventA" );
1345 data.original_thunks[0].u1.AddressOfData = DATA_RVA( &data.function );
1346 data.thunks[0].u1.AddressOfData = 0xdeadbeef;
1348 data.tls.StartAddressOfRawData = nt.OptionalHeader.ImageBase + DATA_RVA( data.tls_data );
1349 data.tls.EndAddressOfRawData = data.tls.StartAddressOfRawData + sizeof(data.tls_data);
1350 data.tls.AddressOfIndex = nt.OptionalHeader.ImageBase + DATA_RVA( &data.tls_index );
1351 strcpy( data.tls_data, "hello world" );
1352 data.tls_index = 9999;
1354 GetTempPathA(MAX_PATH, temp_path);
1355 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
1357 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
1358 ok( hfile != INVALID_HANDLE_VALUE, "creation failed\n" );
1360 memset( &section, 0, sizeof(section) );
1361 memcpy( section.Name, ".text", sizeof(".text") );
1362 section.PointerToRawData = nt.OptionalHeader.FileAlignment;
1363 section.VirtualAddress = nt.OptionalHeader.SectionAlignment;
1364 section.Misc.VirtualSize = sizeof(data);
1365 section.SizeOfRawData = sizeof(data);
1366 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
1368 WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
1369 WriteFile(hfile, &nt, sizeof(nt), &dummy, NULL);
1370 WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
1372 SetFilePointer( hfile, section.PointerToRawData, NULL, SEEK_SET );
1373 WriteFile(hfile, &data, sizeof(data), &dummy, NULL);
1375 CloseHandle( hfile );
1377 switch (test)
1379 case 0: /* normal load */
1380 mod = LoadLibraryA( dll_name );
1381 ok( mod != NULL, "failed to load err %u\n", GetLastError() );
1382 if (!mod) break;
1383 ptr = (struct imports *)((char *)mod + page_size);
1384 expect = GetProcAddress( GetModuleHandleA( data.module ), data.function.name );
1385 ok( (void *)ptr->thunks[0].u1.Function == expect, "thunk %p instead of %p for %s.%s\n",
1386 (void *)ptr->thunks[0].u1.Function, expect, data.module, data.function.name );
1387 ok( ptr->tls_index < 32 || broken(ptr->tls_index == 9999), /* before vista */
1388 "wrong tls index %d\n", ptr->tls_index );
1389 if (ptr->tls_index != 9999)
1391 str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index];
1392 ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str );
1394 FreeLibrary( mod );
1395 break;
1396 case 1: /* load with DONT_RESOLVE_DLL_REFERENCES doesn't resolve imports */
1397 mod = LoadLibraryExA( dll_name, 0, DONT_RESOLVE_DLL_REFERENCES );
1398 ok( mod != NULL, "failed to load err %u\n", GetLastError() );
1399 if (!mod) break;
1400 ptr = (struct imports *)((char *)mod + page_size);
1401 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
1402 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
1403 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
1405 mod2 = LoadLibraryA( dll_name );
1406 ok( mod2 == mod, "loaded twice %p / %p\n", mod, mod2 );
1407 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
1408 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
1409 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
1410 FreeLibrary( mod );
1411 break;
1412 case 2: /* load without IMAGE_FILE_DLL doesn't resolve imports */
1413 mod = LoadLibraryA( dll_name );
1414 ok( mod != NULL, "failed to load err %u\n", GetLastError() );
1415 if (!mod) break;
1416 ptr = (struct imports *)((char *)mod + page_size);
1417 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
1418 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
1419 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
1420 FreeLibrary( mod );
1421 break;
1423 DeleteFileA( dll_name );
1424 #undef DATA_RVA
1428 #define MAX_COUNT 10
1429 static HANDLE attached_thread[MAX_COUNT];
1430 static DWORD attached_thread_count;
1431 HANDLE stop_event, event, mutex, semaphore, loader_lock_event, peb_lock_event, heap_lock_event, ack_event;
1432 static int test_dll_phase, inside_loader_lock, inside_peb_lock, inside_heap_lock;
1434 static DWORD WINAPI mutex_thread_proc(void *param)
1436 HANDLE wait_list[4];
1437 DWORD ret;
1439 ret = WaitForSingleObject(mutex, 0);
1440 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1442 SetEvent(param);
1444 wait_list[0] = stop_event;
1445 wait_list[1] = loader_lock_event;
1446 wait_list[2] = peb_lock_event;
1447 wait_list[3] = heap_lock_event;
1449 trace("%04u: mutex_thread_proc: starting\n", GetCurrentThreadId());
1450 while (1)
1452 ret = WaitForMultipleObjects(sizeof(wait_list)/sizeof(wait_list[0]), wait_list, FALSE, 50);
1453 if (ret == WAIT_OBJECT_0) break;
1454 else if (ret == WAIT_OBJECT_0 + 1)
1456 ULONG_PTR loader_lock_magic;
1457 trace("%04u: mutex_thread_proc: Entering loader lock\n", GetCurrentThreadId());
1458 ret = pLdrLockLoaderLock(0, NULL, &loader_lock_magic);
1459 ok(!ret, "LdrLockLoaderLock error %#x\n", ret);
1460 inside_loader_lock++;
1461 SetEvent(ack_event);
1463 else if (ret == WAIT_OBJECT_0 + 2)
1465 trace("%04u: mutex_thread_proc: Entering PEB lock\n", GetCurrentThreadId());
1466 pRtlAcquirePebLock();
1467 inside_peb_lock++;
1468 SetEvent(ack_event);
1470 else if (ret == WAIT_OBJECT_0 + 3)
1472 trace("%04u: mutex_thread_proc: Entering heap lock\n", GetCurrentThreadId());
1473 HeapLock(GetProcessHeap());
1474 inside_heap_lock++;
1475 SetEvent(ack_event);
1479 trace("%04u: mutex_thread_proc: exiting\n", GetCurrentThreadId());
1480 return 196;
1483 static DWORD WINAPI semaphore_thread_proc(void *param)
1485 DWORD ret;
1487 ret = WaitForSingleObject(semaphore, 0);
1488 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1490 SetEvent(param);
1492 while (1)
1494 if (winetest_debug > 1)
1495 trace("%04u: semaphore_thread_proc: still alive\n", GetCurrentThreadId());
1496 if (WaitForSingleObject(stop_event, 50) != WAIT_TIMEOUT) break;
1499 trace("%04u: semaphore_thread_proc: exiting\n", GetCurrentThreadId());
1500 return 196;
1503 static DWORD WINAPI noop_thread_proc(void *param)
1505 if (param)
1507 LONG *noop_thread_started = param;
1508 InterlockedIncrement(noop_thread_started);
1511 trace("%04u: noop_thread_proc: exiting\n", GetCurrentThreadId());
1512 return 195;
1515 static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param)
1517 static LONG noop_thread_started;
1518 DWORD ret;
1520 ok(!inside_loader_lock, "inside_loader_lock should not be set\n");
1521 ok(!inside_peb_lock, "inside_peb_lock should not be set\n");
1523 switch (reason)
1525 case DLL_PROCESS_ATTACH:
1526 trace("dll: %p, DLL_PROCESS_ATTACH, %p\n", hinst, param);
1528 ret = pRtlDllShutdownInProgress();
1529 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1531 break;
1532 case DLL_PROCESS_DETACH:
1534 DWORD code, expected_code, i;
1535 HANDLE handle, process;
1536 void *addr;
1537 SIZE_T size;
1538 LARGE_INTEGER offset;
1539 DEBUG_EVENT de;
1541 trace("dll: %p, DLL_PROCESS_DETACH, %p\n", hinst, param);
1543 if (test_dll_phase == 4 || test_dll_phase == 5)
1545 ok(0, "dll_entry_point(DLL_PROCESS_DETACH) should not be called\n");
1546 break;
1549 /* The process should already deadlock at this point */
1550 if (test_dll_phase == 6)
1552 /* In reality, code below never gets executed, probably some other
1553 * code tries to access process heap and deadlocks earlier, even XP
1554 * doesn't call the DLL entry point on process detach either.
1556 HeapLock(GetProcessHeap());
1557 ok(0, "dll_entry_point: process should already deadlock\n");
1558 break;
1561 if (test_dll_phase == 0 || test_dll_phase == 1 || test_dll_phase == 3)
1562 ok(param != NULL, "dll: param %p\n", param);
1563 else
1564 ok(!param, "dll: param %p\n", param);
1566 if (test_dll_phase == 0 || test_dll_phase == 1) expected_code = 195;
1567 else if (test_dll_phase == 3) expected_code = 196;
1568 else expected_code = STILL_ACTIVE;
1570 if (test_dll_phase == 3)
1572 ret = pRtlDllShutdownInProgress();
1573 ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
1575 else
1577 ret = pRtlDllShutdownInProgress();
1579 /* FIXME: remove once Wine is fixed */
1580 todo_wine_if (!(expected_code == STILL_ACTIVE || expected_code == 196))
1581 ok(!ret || broken(ret) /* before Vista */, "RtlDllShutdownInProgress returned %d\n", ret);
1584 ok(attached_thread_count >= 2, "attached thread count should be >= 2\n");
1586 for (i = 0; i < attached_thread_count; i++)
1588 /* Calling GetExitCodeThread() without waiting for thread termination
1589 * leads to different results due to a race condition.
1591 if (expected_code != STILL_ACTIVE)
1593 ret = WaitForSingleObject(attached_thread[i], 1000);
1594 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1596 ret = GetExitCodeThread(attached_thread[i], &code);
1597 trace("dll: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
1598 ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
1599 ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code);
1602 ret = WaitForSingleObject(event, 0);
1603 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1605 ret = WaitForSingleObject(mutex, 0);
1606 if (expected_code == STILL_ACTIVE)
1607 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1608 else
1609 ok(ret == WAIT_ABANDONED, "expected WAIT_ABANDONED, got %#x\n", ret);
1611 /* semaphore is not abandoned on thread termination */
1612 ret = WaitForSingleObject(semaphore, 0);
1613 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1615 if (expected_code == STILL_ACTIVE)
1617 ret = WaitForSingleObject(attached_thread[0], 0);
1618 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1619 ret = WaitForSingleObject(attached_thread[1], 0);
1620 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1622 else
1624 ret = WaitForSingleObject(attached_thread[0], 0);
1625 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1626 ret = WaitForSingleObject(attached_thread[1], 0);
1627 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1630 /* win7 doesn't allow creating a thread during process shutdown but
1631 * earlier Windows versions allow it.
1633 noop_thread_started = 0;
1634 SetLastError(0xdeadbeef);
1635 handle = CreateThread(NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
1636 if (param)
1638 ok(!handle || broken(handle != 0) /* before win7 */, "CreateThread should fail\n");
1639 if (!handle)
1640 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1641 else
1643 ret = WaitForSingleObject(handle, 1000);
1644 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1645 CloseHandle(handle);
1648 else
1650 ok(handle != 0, "CreateThread error %d\n", GetLastError());
1651 ret = WaitForSingleObject(handle, 1000);
1652 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1653 ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n");
1654 CloseHandle(handle);
1657 SetLastError(0xdeadbeef);
1658 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, GetCurrentProcessId());
1659 ok(process != NULL, "OpenProcess error %d\n", GetLastError());
1661 noop_thread_started = 0;
1662 SetLastError(0xdeadbeef);
1663 handle = CreateRemoteThread(process, NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
1664 if (param)
1666 ok(!handle || broken(handle != 0) /* before win7 */, "CreateRemoteThread should fail\n");
1667 if (!handle)
1668 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1669 else
1671 ret = WaitForSingleObject(handle, 1000);
1672 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1673 CloseHandle(handle);
1676 else
1678 ok(handle != 0, "CreateRemoteThread error %d\n", GetLastError());
1679 ret = WaitForSingleObject(handle, 1000);
1680 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1681 ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n");
1682 CloseHandle(handle);
1685 SetLastError(0xdeadbeef);
1686 handle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
1687 ok(handle != 0, "CreateFileMapping error %d\n", GetLastError());
1689 offset.u.LowPart = 0;
1690 offset.u.HighPart = 0;
1691 addr = NULL;
1692 size = 0;
1693 ret = pNtMapViewOfSection(handle, process, &addr, 0, 0, &offset,
1694 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1695 ok(ret == STATUS_SUCCESS, "NtMapViewOfSection error %#x\n", ret);
1696 ret = pNtUnmapViewOfSection(process, addr);
1697 ok(ret == STATUS_SUCCESS, "NtUnmapViewOfSection error %#x\n", ret);
1699 CloseHandle(handle);
1700 CloseHandle(process);
1702 handle = GetModuleHandleA("winver.exe");
1703 ok(!handle, "winver.exe shouldn't be loaded yet\n");
1704 SetLastError(0xdeadbeef);
1705 handle = LoadLibraryA("winver.exe");
1706 ok(handle != 0, "LoadLibrary error %d\n", GetLastError());
1707 SetLastError(0xdeadbeef);
1708 ret = FreeLibrary(handle);
1709 ok(ret, "FreeLibrary error %d\n", GetLastError());
1710 handle = GetModuleHandleA("winver.exe");
1711 if (param)
1712 ok(handle != 0, "winver.exe should not be unloaded\n");
1713 else
1714 todo_wine
1715 ok(!handle || broken(handle != 0) /* before win7 */, "winver.exe should be unloaded\n");
1717 SetLastError(0xdeadbeef);
1718 ret = WaitForDebugEvent(&de, 0);
1719 ok(!ret, "WaitForDebugEvent should fail\n");
1720 todo_wine
1721 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
1723 SetLastError(0xdeadbeef);
1724 ret = DebugActiveProcess(GetCurrentProcessId());
1725 ok(!ret, "DebugActiveProcess should fail\n");
1726 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1728 SetLastError(0xdeadbeef);
1729 ret = WaitForDebugEvent(&de, 0);
1730 ok(!ret, "WaitForDebugEvent should fail\n");
1731 ok(GetLastError() == ERROR_SEM_TIMEOUT, "expected ERROR_SEM_TIMEOUT, got %d\n", GetLastError());
1733 if (test_dll_phase == 2)
1735 trace("dll: call ExitProcess()\n");
1736 *child_failures = winetest_get_failures();
1737 ExitProcess(197);
1739 trace("dll: %p, DLL_PROCESS_DETACH, %p => DONE\n", hinst, param);
1740 break;
1742 case DLL_THREAD_ATTACH:
1743 trace("dll: %p, DLL_THREAD_ATTACH, %p\n", hinst, param);
1745 ret = pRtlDllShutdownInProgress();
1746 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1748 if (attached_thread_count < MAX_COUNT)
1750 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &attached_thread[attached_thread_count],
1751 0, TRUE, DUPLICATE_SAME_ACCESS);
1752 attached_thread_count++;
1754 break;
1755 case DLL_THREAD_DETACH:
1756 trace("dll: %p, DLL_THREAD_DETACH, %p\n", hinst, param);
1758 ret = pRtlDllShutdownInProgress();
1759 /* win7 doesn't allow creating a thread during process shutdown but
1760 * earlier Windows versions allow it. In that case DLL_THREAD_DETACH is
1761 * sent on thread exit, but DLL_THREAD_ATTACH is never received.
1763 if (noop_thread_started)
1764 ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
1765 else
1766 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1768 break;
1769 default:
1770 trace("dll: %p, %d, %p\n", hinst, reason, param);
1771 break;
1774 *child_failures = winetest_get_failures();
1776 return TRUE;
1779 static void child_process(const char *dll_name, DWORD target_offset)
1781 void *target;
1782 DWORD ret, dummy, i, code, expected_code;
1783 HANDLE file, thread, process;
1784 HMODULE hmod;
1785 struct PROCESS_BASIC_INFORMATION_PRIVATE pbi;
1786 DWORD_PTR affinity;
1788 trace("phase %d: writing %p at %#x\n", test_dll_phase, dll_entry_point, target_offset);
1790 SetLastError(0xdeadbeef);
1791 mutex = CreateMutexW(NULL, FALSE, NULL);
1792 ok(mutex != 0, "CreateMutex error %d\n", GetLastError());
1794 SetLastError(0xdeadbeef);
1795 semaphore = CreateSemaphoreW(NULL, 1, 1, NULL);
1796 ok(semaphore != 0, "CreateSemaphore error %d\n", GetLastError());
1798 SetLastError(0xdeadbeef);
1799 event = CreateEventW(NULL, TRUE, FALSE, NULL);
1800 ok(event != 0, "CreateEvent error %d\n", GetLastError());
1802 SetLastError(0xdeadbeef);
1803 loader_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1804 ok(loader_lock_event != 0, "CreateEvent error %d\n", GetLastError());
1806 SetLastError(0xdeadbeef);
1807 peb_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1808 ok(peb_lock_event != 0, "CreateEvent error %d\n", GetLastError());
1810 SetLastError(0xdeadbeef);
1811 heap_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1812 ok(heap_lock_event != 0, "CreateEvent error %d\n", GetLastError());
1814 SetLastError(0xdeadbeef);
1815 ack_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1816 ok(ack_event != 0, "CreateEvent error %d\n", GetLastError());
1818 file = CreateFileA(dll_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1819 if (file == INVALID_HANDLE_VALUE)
1821 ok(0, "could not open %s\n", dll_name);
1822 return;
1824 SetFilePointer(file, target_offset, NULL, FILE_BEGIN);
1825 SetLastError(0xdeadbeef);
1826 target = dll_entry_point;
1827 ret = WriteFile(file, &target, sizeof(target), &dummy, NULL);
1828 ok(ret, "WriteFile error %d\n", GetLastError());
1829 CloseHandle(file);
1831 SetLastError(0xdeadbeef);
1832 hmod = LoadLibraryA(dll_name);
1833 ok(hmod != 0, "LoadLibrary error %d\n", GetLastError());
1835 SetLastError(0xdeadbeef);
1836 stop_event = CreateEventW(NULL, TRUE, FALSE, NULL);
1837 ok(stop_event != 0, "CreateEvent error %d\n", GetLastError());
1839 SetLastError(0xdeadbeef);
1840 thread = CreateThread(NULL, 0, mutex_thread_proc, event, 0, &dummy);
1841 ok(thread != 0, "CreateThread error %d\n", GetLastError());
1842 WaitForSingleObject(event, 3000);
1843 CloseHandle(thread);
1845 ResetEvent(event);
1847 SetLastError(0xdeadbeef);
1848 thread = CreateThread(NULL, 0, semaphore_thread_proc, event, 0, &dummy);
1849 ok(thread != 0, "CreateThread error %d\n", GetLastError());
1850 WaitForSingleObject(event, 3000);
1851 CloseHandle(thread);
1853 ResetEvent(event);
1854 Sleep(100);
1856 ok(attached_thread_count == 2, "attached thread count should be 2\n");
1857 for (i = 0; i < attached_thread_count; i++)
1859 ret = GetExitCodeThread(attached_thread[i], &code);
1860 trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
1861 ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
1862 ok(code == STILL_ACTIVE, "expected thread exit code STILL_ACTIVE, got %u\n", code);
1865 ret = WaitForSingleObject(attached_thread[0], 0);
1866 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1867 ret = WaitForSingleObject(attached_thread[1], 0);
1868 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1870 ret = WaitForSingleObject(event, 0);
1871 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1872 ret = WaitForSingleObject(mutex, 0);
1873 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1874 ret = WaitForSingleObject(semaphore, 0);
1875 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1877 ret = pRtlDllShutdownInProgress();
1878 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1880 SetLastError(0xdeadbeef);
1881 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, GetCurrentProcessId());
1882 ok(process != NULL, "OpenProcess error %d\n", GetLastError());
1884 SetLastError(0xdeadbeef);
1885 ret = TerminateProcess(0, 195);
1886 ok(!ret, "TerminateProcess(0) should fail\n");
1887 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
1889 Sleep(100);
1891 affinity = 1;
1892 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
1893 ok(!ret, "NtSetInformationProcess error %#x\n", ret);
1895 switch (test_dll_phase)
1897 case 0:
1898 ret = pRtlDllShutdownInProgress();
1899 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1901 trace("call NtTerminateProcess(0, 195)\n");
1902 ret = pNtTerminateProcess(0, 195);
1903 ok(!ret, "NtTerminateProcess error %#x\n", ret);
1905 memset(&pbi, 0, sizeof(pbi));
1906 ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
1907 ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
1908 ok(pbi.ExitStatus == STILL_ACTIVE, "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus);
1909 affinity = 1;
1910 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
1911 ok(!ret, "NtSetInformationProcess error %#x\n", ret);
1913 ret = pRtlDllShutdownInProgress();
1914 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1916 hmod = GetModuleHandleA(dll_name);
1917 ok(hmod != 0, "DLL should not be unloaded\n");
1919 SetLastError(0xdeadbeef);
1920 thread = CreateThread(NULL, 0, noop_thread_proc, &dummy, 0, &ret);
1921 ok(!thread || broken(thread != 0) /* before win7 */, "CreateThread should fail\n");
1922 if (!thread)
1923 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1924 else
1926 ret = WaitForSingleObject(thread, 1000);
1927 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1928 CloseHandle(thread);
1931 trace("call LdrShutdownProcess()\n");
1932 pLdrShutdownProcess();
1934 ret = pRtlDllShutdownInProgress();
1935 ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
1937 hmod = GetModuleHandleA(dll_name);
1938 ok(hmod != 0, "DLL should not be unloaded\n");
1940 memset(&pbi, 0, sizeof(pbi));
1941 ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
1942 ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
1943 ok(pbi.ExitStatus == STILL_ACTIVE, "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus);
1944 affinity = 1;
1945 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
1946 ok(!ret, "NtSetInformationProcess error %#x\n", ret);
1947 break;
1949 case 1: /* normal ExitProcess */
1950 ret = pRtlDllShutdownInProgress();
1951 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1952 break;
1954 case 2: /* ExitProcess will be called by the PROCESS_DETACH handler */
1955 ret = pRtlDllShutdownInProgress();
1956 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1958 trace("call FreeLibrary(%p)\n", hmod);
1959 SetLastError(0xdeadbeef);
1960 ret = FreeLibrary(hmod);
1961 ok(ret, "FreeLibrary error %d\n", GetLastError());
1962 hmod = GetModuleHandleA(dll_name);
1963 ok(!hmod, "DLL should be unloaded\n");
1965 if (test_dll_phase == 2)
1966 ok(0, "FreeLibrary+ExitProcess should never return\n");
1968 ret = pRtlDllShutdownInProgress();
1969 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1971 break;
1973 case 3:
1974 trace("signalling thread exit\n");
1975 SetEvent(stop_event);
1976 CloseHandle(stop_event);
1977 break;
1979 case 4:
1980 trace("setting loader_lock_event\n");
1981 SetEvent(loader_lock_event);
1982 WaitForSingleObject(ack_event, 1000);
1983 ok(inside_loader_lock != 0, "inside_loader_lock is not set\n");
1985 /* calling NtTerminateProcess should not cause a deadlock */
1986 trace("call NtTerminateProcess(0, 198)\n");
1987 ret = pNtTerminateProcess(0, 198);
1988 ok(!ret, "NtTerminateProcess error %#x\n", ret);
1990 *child_failures = winetest_get_failures();
1992 /* Windows fails to release loader lock acquired from another thread,
1993 * so the LdrUnlockLoaderLock call fails here and ExitProcess deadlocks
1994 * later on, so NtTerminateProcess is used instead.
1996 trace("call NtTerminateProcess(GetCurrentProcess(), 198)\n");
1997 pNtTerminateProcess(GetCurrentProcess(), 198);
1998 ok(0, "NtTerminateProcess should not return\n");
1999 break;
2001 case 5:
2002 trace("setting peb_lock_event\n");
2003 SetEvent(peb_lock_event);
2004 WaitForSingleObject(ack_event, 1000);
2005 ok(inside_peb_lock != 0, "inside_peb_lock is not set\n");
2007 *child_failures = winetest_get_failures();
2009 /* calling ExitProcess should cause a deadlock */
2010 trace("call ExitProcess(198)\n");
2011 ExitProcess(198);
2012 ok(0, "ExitProcess should not return\n");
2013 break;
2015 case 6:
2016 trace("setting heap_lock_event\n");
2017 SetEvent(heap_lock_event);
2018 WaitForSingleObject(ack_event, 1000);
2019 ok(inside_heap_lock != 0, "inside_heap_lock is not set\n");
2021 *child_failures = winetest_get_failures();
2023 /* calling ExitProcess should cause a deadlock */
2024 trace("call ExitProcess(1)\n");
2025 ExitProcess(1);
2026 ok(0, "ExitProcess should not return\n");
2027 break;
2029 default:
2030 assert(0);
2031 break;
2034 if (test_dll_phase == 0) expected_code = 195;
2035 else if (test_dll_phase == 3) expected_code = 196;
2036 else if (test_dll_phase == 4) expected_code = 198;
2037 else expected_code = STILL_ACTIVE;
2039 if (expected_code == STILL_ACTIVE)
2041 ret = WaitForSingleObject(attached_thread[0], 100);
2042 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2043 ret = WaitForSingleObject(attached_thread[1], 100);
2044 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2046 else
2048 ret = WaitForSingleObject(attached_thread[0], 1000);
2049 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2050 ret = WaitForSingleObject(attached_thread[1], 1000);
2051 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2054 for (i = 0; i < attached_thread_count; i++)
2056 ret = GetExitCodeThread(attached_thread[i], &code);
2057 trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
2058 ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
2059 ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code);
2062 *child_failures = winetest_get_failures();
2064 trace("call ExitProcess(195)\n");
2065 ExitProcess(195);
2068 static void test_ExitProcess(void)
2070 #include "pshpack1.h"
2071 #ifdef __x86_64__
2072 static struct section_data
2074 BYTE mov_rax[2];
2075 void *target;
2076 BYTE jmp_rax[2];
2077 } section_data = { { 0x48,0xb8 }, dll_entry_point, { 0xff,0xe0 } };
2078 #else
2079 static struct section_data
2081 BYTE mov_eax;
2082 void *target;
2083 BYTE jmp_eax[2];
2084 } section_data = { 0xb8, dll_entry_point, { 0xff,0xe0 } };
2085 #endif
2086 #include "poppack.h"
2087 static const char filler[0x1000];
2088 DWORD dummy, file_align;
2089 HANDLE file, thread, process, hmap, hmap_dup;
2090 char temp_path[MAX_PATH], dll_name[MAX_PATH], cmdline[MAX_PATH * 2];
2091 DWORD ret, target_offset, old_prot;
2092 char **argv, buf[256];
2093 PROCESS_INFORMATION pi;
2094 STARTUPINFOA si = { sizeof(si) };
2095 CONTEXT ctx;
2096 struct PROCESS_BASIC_INFORMATION_PRIVATE pbi;
2097 MEMORY_BASIC_INFORMATION mbi;
2098 DWORD_PTR affinity;
2099 void *addr;
2100 LARGE_INTEGER offset;
2101 SIZE_T size;
2102 IMAGE_NT_HEADERS nt_header;
2104 #if !defined(__i386__) && !defined(__x86_64__)
2105 skip("x86 specific ExitProcess test\n");
2106 return;
2107 #endif
2109 if (!pRtlDllShutdownInProgress)
2111 win_skip("RtlDllShutdownInProgress is not available on this platform (XP+)\n");
2112 return;
2114 if (!pNtQueryInformationProcess || !pNtSetInformationProcess)
2116 win_skip("NtQueryInformationProcess/NtSetInformationProcess are not available on this platform\n");
2117 return;
2119 if (!pNtAllocateVirtualMemory || !pNtFreeVirtualMemory)
2121 win_skip("NtAllocateVirtualMemory/NtFreeVirtualMemory are not available on this platform\n");
2122 return;
2125 /* prevent displaying of the "Unable to load this DLL" message box */
2126 SetErrorMode(SEM_FAILCRITICALERRORS);
2128 GetTempPathA(MAX_PATH, temp_path);
2129 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
2131 /*trace("creating %s\n", dll_name);*/
2132 file = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2133 if (file == INVALID_HANDLE_VALUE)
2135 ok(0, "could not create %s\n", dll_name);
2136 return;
2139 SetLastError(0xdeadbeef);
2140 ret = WriteFile(file, &dos_header, sizeof(dos_header), &dummy, NULL);
2141 ok(ret, "WriteFile error %d\n", GetLastError());
2143 nt_header = nt_header_template;
2144 nt_header.FileHeader.NumberOfSections = 1;
2145 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
2146 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED;
2148 nt_header.OptionalHeader.AddressOfEntryPoint = 0x1000;
2149 nt_header.OptionalHeader.SectionAlignment = 0x1000;
2150 nt_header.OptionalHeader.FileAlignment = 0x200;
2151 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000;
2152 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
2153 SetLastError(0xdeadbeef);
2154 ret = WriteFile(file, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
2155 ok(ret, "WriteFile error %d\n", GetLastError());
2156 SetLastError(0xdeadbeef);
2157 ret = WriteFile(file, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
2158 ok(ret, "WriteFile error %d\n", GetLastError());
2160 section.SizeOfRawData = sizeof(section_data);
2161 section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
2162 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
2163 section.Misc.VirtualSize = sizeof(section_data);
2164 section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
2165 SetLastError(0xdeadbeef);
2166 ret = WriteFile(file, &section, sizeof(section), &dummy, NULL);
2167 ok(ret, "WriteFile error %d\n", GetLastError());
2169 file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
2170 assert(file_align < sizeof(filler));
2171 SetLastError(0xdeadbeef);
2172 ret = WriteFile(file, filler, file_align, &dummy, NULL);
2173 ok(ret, "WriteFile error %d\n", GetLastError());
2175 target_offset = SetFilePointer(file, 0, NULL, FILE_CURRENT) + FIELD_OFFSET(struct section_data, target);
2177 /* section data */
2178 SetLastError(0xdeadbeef);
2179 ret = WriteFile(file, &section_data, sizeof(section_data), &dummy, NULL);
2180 ok(ret, "WriteFile error %d\n", GetLastError());
2182 CloseHandle(file);
2184 winetest_get_mainargs(&argv);
2186 /* phase 0 */
2187 *child_failures = -1;
2188 sprintf(cmdline, "\"%s\" loader %s %u 0", argv[0], dll_name, target_offset);
2189 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2190 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2191 ret = WaitForSingleObject(pi.hProcess, 10000);
2192 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2193 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2194 GetExitCodeProcess(pi.hProcess, &ret);
2195 ok(ret == 195, "expected exit code 195, got %u\n", ret);
2196 if (*child_failures)
2198 trace("%d failures in child process\n", *child_failures);
2199 winetest_add_failures(*child_failures);
2201 CloseHandle(pi.hThread);
2202 CloseHandle(pi.hProcess);
2204 /* phase 1 */
2205 *child_failures = -1;
2206 sprintf(cmdline, "\"%s\" loader %s %u 1", argv[0], dll_name, target_offset);
2207 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2208 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2209 ret = WaitForSingleObject(pi.hProcess, 10000);
2210 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2211 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2212 GetExitCodeProcess(pi.hProcess, &ret);
2213 ok(ret == 195, "expected exit code 195, got %u\n", ret);
2214 if (*child_failures)
2216 trace("%d failures in child process\n", *child_failures);
2217 winetest_add_failures(*child_failures);
2219 CloseHandle(pi.hThread);
2220 CloseHandle(pi.hProcess);
2222 /* phase 2 */
2223 *child_failures = -1;
2224 sprintf(cmdline, "\"%s\" loader %s %u 2", argv[0], dll_name, target_offset);
2225 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2226 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2227 ret = WaitForSingleObject(pi.hProcess, 10000);
2228 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2229 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2230 GetExitCodeProcess(pi.hProcess, &ret);
2231 ok(ret == 197, "expected exit code 197, got %u\n", ret);
2232 if (*child_failures)
2234 trace("%d failures in child process\n", *child_failures);
2235 winetest_add_failures(*child_failures);
2237 CloseHandle(pi.hThread);
2238 CloseHandle(pi.hProcess);
2240 /* phase 3 */
2241 *child_failures = -1;
2242 sprintf(cmdline, "\"%s\" loader %s %u 3", argv[0], dll_name, target_offset);
2243 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2244 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2245 ret = WaitForSingleObject(pi.hProcess, 10000);
2246 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2247 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2248 GetExitCodeProcess(pi.hProcess, &ret);
2249 ok(ret == 195, "expected exit code 195, got %u\n", ret);
2250 if (*child_failures)
2252 trace("%d failures in child process\n", *child_failures);
2253 winetest_add_failures(*child_failures);
2255 CloseHandle(pi.hThread);
2256 CloseHandle(pi.hProcess);
2258 /* phase 4 */
2259 if (pLdrLockLoaderLock && pLdrUnlockLoaderLock)
2261 *child_failures = -1;
2262 sprintf(cmdline, "\"%s\" loader %s %u 4", argv[0], dll_name, target_offset);
2263 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2264 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2265 ret = WaitForSingleObject(pi.hProcess, 10000);
2266 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2267 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2268 GetExitCodeProcess(pi.hProcess, &ret);
2269 ok(ret == 198, "expected exit code 198, got %u\n", ret);
2270 if (*child_failures)
2272 trace("%d failures in child process\n", *child_failures);
2273 winetest_add_failures(*child_failures);
2275 CloseHandle(pi.hThread);
2276 CloseHandle(pi.hProcess);
2278 else
2279 win_skip("LdrLockLoaderLock/LdrUnlockLoaderLock are not available on this platform\n");
2281 /* phase 5 */
2282 if (pRtlAcquirePebLock && pRtlReleasePebLock)
2284 *child_failures = -1;
2285 sprintf(cmdline, "\"%s\" loader %s %u 5", argv[0], dll_name, target_offset);
2286 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2287 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2288 ret = WaitForSingleObject(pi.hProcess, 5000);
2289 ok(ret == WAIT_TIMEOUT, "child process should fail to terminate\n");
2290 if (ret != WAIT_OBJECT_0)
2292 trace("terminating child process\n");
2293 TerminateProcess(pi.hProcess, 199);
2295 ret = WaitForSingleObject(pi.hProcess, 1000);
2296 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2297 GetExitCodeProcess(pi.hProcess, &ret);
2298 ok(ret == 199, "expected exit code 199, got %u\n", ret);
2299 if (*child_failures)
2301 trace("%d failures in child process\n", *child_failures);
2302 winetest_add_failures(*child_failures);
2304 CloseHandle(pi.hThread);
2305 CloseHandle(pi.hProcess);
2307 else
2308 win_skip("RtlAcquirePebLock/RtlReleasePebLock are not available on this platform\n");
2310 /* phase 6 */
2311 *child_failures = -1;
2312 sprintf(cmdline, "\"%s\" loader %s %u 6", argv[0], dll_name, target_offset);
2313 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2314 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2315 ret = WaitForSingleObject(pi.hProcess, 5000);
2316 ok(ret == WAIT_TIMEOUT || broken(ret == WAIT_OBJECT_0) /* XP */, "child process should fail to terminate\n");
2317 if (ret != WAIT_OBJECT_0)
2319 trace("terminating child process\n");
2320 TerminateProcess(pi.hProcess, 201);
2322 ret = WaitForSingleObject(pi.hProcess, 1000);
2323 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2324 GetExitCodeProcess(pi.hProcess, &ret);
2325 ok(ret == 201 || broken(ret == 1) /* XP */, "expected exit code 201, got %u\n", ret);
2326 if (*child_failures)
2328 trace("%d failures in child process\n", *child_failures);
2329 winetest_add_failures(*child_failures);
2331 CloseHandle(pi.hThread);
2332 CloseHandle(pi.hProcess);
2334 /* test remote process termination */
2335 SetLastError(0xdeadbeef);
2336 ret = CreateProcessA(argv[0], NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
2337 ok(ret, "CreateProcess(%s) error %d\n", argv[0], GetLastError());
2339 SetLastError(0xdeadbeef);
2340 addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
2341 ok(addr != NULL, "VirtualAllocEx error %d\n", GetLastError());
2342 SetLastError(0xdeadbeef);
2343 ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READONLY, &old_prot);
2344 ok(ret, "VirtualProtectEx error %d\n", GetLastError());
2345 ok(old_prot == PAGE_READWRITE, "expected PAGE_READWRITE, got %#x\n", old_prot);
2346 SetLastError(0xdeadbeef);
2347 size = VirtualQueryEx(pi.hProcess, NULL, &mbi, sizeof(mbi));
2348 ok(size == sizeof(mbi), "VirtualQueryEx error %d\n", GetLastError());
2350 SetLastError(0xdeadbeef);
2351 ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size);
2352 ok(ret, "ReadProcessMemory error %d\n", GetLastError());
2353 ok(size == 4, "expected 4, got %lu\n", size);
2355 SetLastError(0xdeadbeef);
2356 hmap = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
2357 ok(hmap != 0, "CreateFileMapping error %d\n", GetLastError());
2359 SetLastError(0xdeadbeef);
2360 ret = DuplicateHandle(GetCurrentProcess(), hmap, pi.hProcess, &hmap_dup,
2361 0, FALSE, DUPLICATE_SAME_ACCESS);
2362 ok(ret, "DuplicateHandle error %d\n", GetLastError());
2364 offset.u.LowPart = 0;
2365 offset.u.HighPart = 0;
2366 addr = NULL;
2367 size = 0;
2368 ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset,
2369 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
2370 ok(!ret, "NtMapViewOfSection error %#x\n", ret);
2371 ret = pNtUnmapViewOfSection(pi.hProcess, addr);
2372 ok(!ret, "NtUnmapViewOfSection error %#x\n", ret);
2374 SetLastError(0xdeadbeef);
2375 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2376 ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError());
2377 SetLastError(0xdeadbeef);
2378 ctx.ContextFlags = CONTEXT_INTEGER;
2379 ret = GetThreadContext(thread, &ctx);
2380 ok(ret, "GetThreadContext error %d\n", GetLastError());
2381 SetLastError(0xdeadbeef);
2382 ctx.ContextFlags = CONTEXT_INTEGER;
2383 ret = SetThreadContext(thread, &ctx);
2384 ok(ret, "SetThreadContext error %d\n", GetLastError());
2385 SetLastError(0xdeadbeef);
2386 ret = SetThreadPriority(thread, 0);
2387 ok(ret, "SetThreadPriority error %d\n", GetLastError());
2389 SetLastError(0xdeadbeef);
2390 ret = TerminateThread(thread, 199);
2391 ok(ret, "TerminateThread error %d\n", GetLastError());
2392 /* Calling GetExitCodeThread() without waiting for thread termination
2393 * leads to different results due to a race condition.
2395 ret = WaitForSingleObject(thread, 1000);
2396 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
2397 GetExitCodeThread(thread, &ret);
2398 ok(ret == 199, "expected exit code 199, got %u\n", ret);
2400 SetLastError(0xdeadbeef);
2401 ret = TerminateProcess(pi.hProcess, 198);
2402 ok(ret, "TerminateProcess error %d\n", GetLastError());
2403 /* Checking process state without waiting for process termination
2404 * leads to different results due to a race condition.
2406 ret = WaitForSingleObject(pi.hProcess, 1000);
2407 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
2409 SetLastError(0xdeadbeef);
2410 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pi.dwProcessId);
2411 ok(process != NULL, "OpenProcess error %d\n", GetLastError());
2412 CloseHandle(process);
2414 memset(&pbi, 0, sizeof(pbi));
2415 ret = pNtQueryInformationProcess(pi.hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
2416 ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
2417 ok(pbi.ExitStatus == 198, "expected 198, got %lu\n", pbi.ExitStatus);
2418 affinity = 1;
2419 ret = pNtSetInformationProcess(pi.hProcess, ProcessAffinityMask, &affinity, sizeof(affinity));
2420 ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#x\n", ret);
2422 SetLastError(0xdeadbeef);
2423 ctx.ContextFlags = CONTEXT_INTEGER;
2424 ret = GetThreadContext(thread, &ctx);
2425 ok(!ret || broken(ret) /* XP 64-bit */, "GetThreadContext should fail\n");
2426 if (!ret)
2427 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
2428 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
2429 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
2430 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2431 SetLastError(0xdeadbeef);
2432 ctx.ContextFlags = CONTEXT_INTEGER;
2433 ret = SetThreadContext(thread, &ctx);
2434 ok(!ret || broken(ret) /* XP 64-bit */, "SetThreadContext should fail\n");
2435 if (!ret)
2436 ok(GetLastError() == ERROR_ACCESS_DENIED ||
2437 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
2438 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
2439 "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2440 SetLastError(0xdeadbeef);
2441 ret = SetThreadPriority(thread, 0);
2442 ok(ret, "SetThreadPriority error %d\n", GetLastError());
2443 CloseHandle(thread);
2445 SetLastError(0xdeadbeef);
2446 ctx.ContextFlags = CONTEXT_INTEGER;
2447 ret = GetThreadContext(pi.hThread, &ctx);
2448 ok(!ret || broken(ret) /* XP 64-bit */, "GetThreadContext should fail\n");
2449 if (!ret)
2450 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
2451 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
2452 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
2453 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2454 SetLastError(0xdeadbeef);
2455 ctx.ContextFlags = CONTEXT_INTEGER;
2456 ret = SetThreadContext(pi.hThread, &ctx);
2457 ok(!ret || broken(ret) /* XP 64-bit */, "SetThreadContext should fail\n");
2458 if (!ret)
2459 ok(GetLastError() == ERROR_ACCESS_DENIED ||
2460 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
2461 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
2462 "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2463 SetLastError(0xdeadbeef);
2464 ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READWRITE, &old_prot);
2465 ok(!ret, "VirtualProtectEx should fail\n");
2466 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2467 SetLastError(0xdeadbeef);
2468 size = 0;
2469 ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size);
2470 ok(!ret, "ReadProcessMemory should fail\n");
2471 ok(GetLastError() == ERROR_PARTIAL_COPY || GetLastError() == ERROR_ACCESS_DENIED,
2472 "expected ERROR_PARTIAL_COPY, got %d\n", GetLastError());
2473 ok(!size, "expected 0, got %lu\n", size);
2474 SetLastError(0xdeadbeef);
2475 ret = VirtualFreeEx(pi.hProcess, addr, 0, MEM_RELEASE);
2476 ok(!ret, "VirtualFreeEx should fail\n");
2477 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2478 SetLastError(0xdeadbeef);
2479 addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
2480 ok(!addr, "VirtualAllocEx should fail\n");
2481 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2482 SetLastError(0xdeadbeef);
2483 size = VirtualQueryEx(pi.hProcess, NULL, &mbi, sizeof(mbi));
2484 ok(!size, "VirtualQueryEx should fail\n");
2485 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2487 /* CloseHandle() call below leads to premature process termination
2488 * under some Windows versions.
2490 if (0)
2492 SetLastError(0xdeadbeef);
2493 ret = CloseHandle(hmap_dup);
2494 ok(ret, "CloseHandle should not fail\n");
2497 SetLastError(0xdeadbeef);
2498 ret = DuplicateHandle(GetCurrentProcess(), hmap, pi.hProcess, &hmap_dup,
2499 0, FALSE, DUPLICATE_SAME_ACCESS);
2500 ok(!ret, "DuplicateHandle should fail\n");
2501 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2503 offset.u.LowPart = 0;
2504 offset.u.HighPart = 0;
2505 addr = NULL;
2506 size = 0;
2507 ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset,
2508 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
2509 ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#x\n", ret);
2511 SetLastError(0xdeadbeef);
2512 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2513 ok(!thread, "CreateRemoteThread should fail\n");
2514 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2516 SetLastError(0xdeadbeef);
2517 ret = DebugActiveProcess(pi.dwProcessId);
2518 ok(!ret, "DebugActiveProcess should fail\n");
2519 ok(GetLastError() == ERROR_ACCESS_DENIED /* 64-bit */ || GetLastError() == ERROR_NOT_SUPPORTED /* 32-bit */,
2520 "ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2522 GetExitCodeProcess(pi.hProcess, &ret);
2523 ok(ret == 198 || broken(ret != 198) /* some 32-bit XP version in a VM returns random exit code */,
2524 "expected exit code 198, got %u\n", ret);
2525 CloseHandle(pi.hThread);
2526 CloseHandle(pi.hProcess);
2528 ret = DeleteFileA(dll_name);
2529 ok(ret, "DeleteFile error %d\n", GetLastError());
2532 static PVOID WINAPI failuredllhook(ULONG ul, DELAYLOAD_INFO* pd)
2534 ok(ul == 4, "expected 4, got %u\n", ul);
2535 ok(!!pd, "no delayload info supplied\n");
2536 if (pd)
2538 ok(pd->Size == sizeof(*pd), "got %u\n", pd->Size);
2539 ok(!!pd->DelayloadDescriptor, "no DelayloadDescriptor supplied\n");
2540 if (pd->DelayloadDescriptor)
2542 ok(pd->DelayloadDescriptor->Attributes.AllAttributes == 1,
2543 "expected 1, got %u\n", pd->DelayloadDescriptor->Attributes.AllAttributes);
2544 ok(pd->DelayloadDescriptor->DllNameRVA == 0x2000,
2545 "expected 0x2000, got %x\n", pd->DelayloadDescriptor->DllNameRVA);
2546 ok(pd->DelayloadDescriptor->ModuleHandleRVA == 0x201a,
2547 "expected 0x201a, got %x\n", pd->DelayloadDescriptor->ModuleHandleRVA);
2548 ok(pd->DelayloadDescriptor->ImportAddressTableRVA > pd->DelayloadDescriptor->ModuleHandleRVA,
2549 "expected %x > %x\n", pd->DelayloadDescriptor->ImportAddressTableRVA,
2550 pd->DelayloadDescriptor->ModuleHandleRVA);
2551 ok(pd->DelayloadDescriptor->ImportNameTableRVA > pd->DelayloadDescriptor->ImportAddressTableRVA,
2552 "expected %x > %x\n", pd->DelayloadDescriptor->ImportNameTableRVA,
2553 pd->DelayloadDescriptor->ImportAddressTableRVA);
2554 ok(pd->DelayloadDescriptor->BoundImportAddressTableRVA == 0,
2555 "expected 0, got %x\n", pd->DelayloadDescriptor->BoundImportAddressTableRVA);
2556 ok(pd->DelayloadDescriptor->UnloadInformationTableRVA == 0,
2557 "expected 0, got %x\n", pd->DelayloadDescriptor->UnloadInformationTableRVA);
2558 ok(pd->DelayloadDescriptor->TimeDateStamp == 0,
2559 "expected 0, got %x\n", pd->DelayloadDescriptor->TimeDateStamp);
2562 ok(!!pd->ThunkAddress, "no ThunkAddress supplied\n");
2563 if (pd->ThunkAddress)
2564 ok(pd->ThunkAddress->u1.Ordinal == 0, "expected 0, got %x\n", (UINT)pd->ThunkAddress->u1.Ordinal);
2566 ok(!!pd->TargetDllName, "no TargetDllName supplied\n");
2567 if (pd->TargetDllName)
2568 ok(!strcmp(pd->TargetDllName, "secur32.dll"),
2569 "expected \"secur32.dll\", got \"%s\"\n", pd->TargetDllName);
2571 ok(pd->TargetApiDescriptor.ImportDescribedByName == 0,
2572 "expected 0, got %x\n", pd->TargetApiDescriptor.ImportDescribedByName);
2573 ok(pd->TargetApiDescriptor.Description.Ordinal == 0 ||
2574 pd->TargetApiDescriptor.Description.Ordinal == 999,
2575 "expected 0, got %x\n", pd->TargetApiDescriptor.Description.Ordinal);
2577 ok(!!pd->TargetModuleBase, "no TargetModuleBase supplied\n");
2578 ok(pd->Unused == NULL, "expected NULL, got %p\n", pd->Unused);
2579 ok(pd->LastError, "no LastError supplied\n");
2581 cb_count++;
2582 return (void*)0xdeadbeef;
2585 static void test_ResolveDelayLoadedAPI(void)
2587 static const char test_dll[] = "secur32.dll";
2588 static const char test_func[] = "SealMessage";
2589 static const char filler[0x1000];
2590 char temp_path[MAX_PATH];
2591 char dll_name[MAX_PATH];
2592 IMAGE_DELAYLOAD_DESCRIPTOR idd, *delaydir;
2593 IMAGE_THUNK_DATA itd32;
2594 HANDLE hfile;
2595 HMODULE hlib;
2596 DWORD dummy, file_size, i;
2597 WORD hint = 0;
2598 BOOL ret;
2599 IMAGE_NT_HEADERS nt_header;
2601 static const struct test_data
2603 BOOL func;
2604 UINT_PTR ordinal;
2605 BOOL succeeds;
2606 } td[] =
2609 TRUE, 0, TRUE
2612 FALSE, IMAGE_ORDINAL_FLAG | 2, TRUE
2615 FALSE, IMAGE_ORDINAL_FLAG | 5, TRUE
2618 FALSE, IMAGE_ORDINAL_FLAG | 0, FALSE
2621 FALSE, IMAGE_ORDINAL_FLAG | 999, FALSE
2625 if (!pResolveDelayLoadedAPI)
2627 win_skip("ResolveDelayLoadedAPI is not available\n");
2628 return;
2631 if (0) /* crashes on native */
2633 SetLastError(0xdeadbeef);
2634 ok(!pResolveDelayLoadedAPI(NULL, NULL, NULL, NULL, NULL, 0),
2635 "ResolveDelayLoadedAPI succeeded\n");
2636 ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %x\n", GetLastError());
2638 cb_count = 0;
2639 SetLastError(0xdeadbeef);
2640 ok(!pResolveDelayLoadedAPI(NULL, NULL, failuredllhook, NULL, NULL, 0),
2641 "ResolveDelayLoadedAPI succeeded\n");
2642 ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %x\n", GetLastError());
2643 ok(cb_count == 1, "Wrong callback count: %d\n", cb_count);
2646 GetTempPathA(MAX_PATH, temp_path);
2647 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
2648 trace("creating %s\n", dll_name);
2649 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2650 if (hfile == INVALID_HANDLE_VALUE)
2652 ok(0, "could not create %s\n", dll_name);
2653 return;
2656 SetLastError(0xdeadbeef);
2657 ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
2658 ok(ret, "WriteFile error %d\n", GetLastError());
2660 nt_header = nt_header_template;
2661 nt_header.FileHeader.NumberOfSections = 2;
2662 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
2664 nt_header.OptionalHeader.SectionAlignment = 0x1000;
2665 nt_header.OptionalHeader.FileAlignment = 0x1000;
2666 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x2200;
2667 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + 2 * sizeof(IMAGE_SECTION_HEADER);
2668 nt_header.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
2669 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress = 0x1000;
2670 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size = 0x100;
2672 SetLastError(0xdeadbeef);
2673 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
2674 ok(ret, "WriteFile error %d\n", GetLastError());
2676 SetLastError(0xdeadbeef);
2677 ret = WriteFile(hfile, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
2678 ok(ret, "WriteFile error %d\n", GetLastError());
2680 /* sections */
2681 section.PointerToRawData = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
2682 section.VirtualAddress = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
2683 section.Misc.VirtualSize = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size;
2684 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
2685 SetLastError(0xdeadbeef);
2686 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
2687 ok(ret, "WriteFile error %d\n", GetLastError());
2689 section.PointerToRawData = 0x2000;
2690 section.VirtualAddress = 0x2000;
2691 i = sizeof(td)/sizeof(td[0]);
2692 section.Misc.VirtualSize = sizeof(test_dll) + sizeof(hint) + sizeof(test_func) + sizeof(HMODULE) +
2693 2 * (i + 1) * sizeof(IMAGE_THUNK_DATA);
2694 ok(section.Misc.VirtualSize <= 0x1000, "Too much tests, add a new section!\n");
2695 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
2696 SetLastError(0xdeadbeef);
2697 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
2698 ok(ret, "WriteFile error %d\n", GetLastError());
2700 /* fill up to delay data */
2701 file_size = GetFileSize(hfile, NULL);
2702 SetLastError(0xdeadbeef);
2703 ret = WriteFile(hfile, filler,
2704 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress - file_size,
2705 &dummy, NULL);
2706 ok(ret, "WriteFile error %d\n", GetLastError());
2708 /* delay data */
2709 idd.Attributes.AllAttributes = 1;
2710 idd.DllNameRVA = 0x2000;
2711 idd.ModuleHandleRVA = idd.DllNameRVA + sizeof(test_dll) + sizeof(hint) + sizeof(test_func);
2712 idd.ImportAddressTableRVA = idd.ModuleHandleRVA + sizeof(HMODULE);
2713 idd.ImportNameTableRVA = idd.ImportAddressTableRVA + (i + 1) * sizeof(IMAGE_THUNK_DATA);
2714 idd.BoundImportAddressTableRVA = 0;
2715 idd.UnloadInformationTableRVA = 0;
2716 idd.TimeDateStamp = 0;
2718 SetLastError(0xdeadbeef);
2719 ret = WriteFile(hfile, &idd, sizeof(idd), &dummy, NULL);
2720 ok(ret, "WriteFile error %d\n", GetLastError());
2722 SetLastError(0xdeadbeef);
2723 ret = WriteFile(hfile, filler, sizeof(idd), &dummy, NULL);
2724 ok(ret, "WriteFile error %d\n", GetLastError());
2726 /* fill up to extended delay data */
2727 file_size = GetFileSize(hfile, NULL);
2728 SetLastError(0xdeadbeef);
2729 ret = WriteFile(hfile, filler, idd.DllNameRVA - file_size, &dummy, NULL);
2730 ok(ret, "WriteFile error %d\n", GetLastError());
2732 /* extended delay data */
2733 SetLastError(0xdeadbeef);
2734 ret = WriteFile(hfile, test_dll, sizeof(test_dll), &dummy, NULL);
2735 ok(ret, "WriteFile error %d\n", GetLastError());
2737 SetLastError(0xdeadbeef);
2738 ret = WriteFile(hfile, &hint, sizeof(hint), &dummy, NULL);
2739 ok(ret, "WriteFile error %d\n", GetLastError());
2741 SetLastError(0xdeadbeef);
2742 ret = WriteFile(hfile, test_func, sizeof(test_func), &dummy, NULL);
2743 ok(ret, "WriteFile error %d\n", GetLastError());
2745 file_size = GetFileSize(hfile, NULL);
2746 SetLastError(0xdeadbeef);
2747 ret = WriteFile(hfile, filler, idd.ImportNameTableRVA - file_size, &dummy, NULL);
2748 ok(ret, "WriteFile error %d\n", GetLastError());
2750 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
2752 if (td[i].func)
2753 itd32.u1.AddressOfData = idd.DllNameRVA + sizeof(test_dll);
2754 else
2755 itd32.u1.Ordinal = td[i].ordinal;
2756 SetLastError(0xdeadbeef);
2757 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
2758 ok(ret, "WriteFile error %d\n", GetLastError());
2761 itd32.u1.Ordinal = 0;
2762 SetLastError(0xdeadbeef);
2763 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
2764 ok(ret, "WriteFile error %d\n", GetLastError());
2766 /* fill up to eof */
2767 file_size = GetFileSize(hfile, NULL);
2768 SetLastError(0xdeadbeef);
2769 ret = WriteFile(hfile, filler, section.VirtualAddress + section.Misc.VirtualSize - file_size, &dummy, NULL);
2770 ok(ret, "WriteFile error %d\n", GetLastError());
2771 CloseHandle(hfile);
2773 SetLastError(0xdeadbeef);
2774 hlib = LoadLibraryA(dll_name);
2775 ok(hlib != NULL, "LoadLibrary error %u\n", GetLastError());
2776 if (!hlib)
2778 skip("couldn't load %s.\n", dll_name);
2779 DeleteFileA(dll_name);
2780 return;
2783 delaydir = pRtlImageDirectoryEntryToData(hlib, TRUE, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, &file_size);
2784 if (!delaydir)
2786 skip("haven't found section for delay import directory.\n");
2787 FreeLibrary(hlib);
2788 DeleteFileA(dll_name);
2789 return;
2792 for (;;)
2794 IMAGE_THUNK_DATA *itdn, *itda;
2795 HMODULE htarget;
2797 if (!delaydir->DllNameRVA ||
2798 !delaydir->ImportAddressTableRVA ||
2799 !delaydir->ImportNameTableRVA) break;
2801 itdn = RVAToAddr(delaydir->ImportNameTableRVA, hlib);
2802 itda = RVAToAddr(delaydir->ImportAddressTableRVA, hlib);
2803 htarget = LoadLibraryA(RVAToAddr(delaydir->DllNameRVA, hlib));
2805 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
2807 void *ret, *load;
2809 if (IMAGE_SNAP_BY_ORDINAL(itdn[i].u1.Ordinal))
2810 load = (void *)GetProcAddress(htarget, (LPSTR)IMAGE_ORDINAL(itdn[i].u1.Ordinal));
2811 else
2813 const IMAGE_IMPORT_BY_NAME* iibn = RVAToAddr(itdn[i].u1.AddressOfData, hlib);
2814 load = (void *)GetProcAddress(htarget, (char*)iibn->Name);
2817 cb_count = 0;
2818 ret = pResolveDelayLoadedAPI(hlib, delaydir, failuredllhook, NULL, &itda[i], 0);
2819 if (td[i].succeeds)
2821 ok(ret != NULL, "Test %u: ResolveDelayLoadedAPI failed\n", i);
2822 ok(ret == load, "Test %u: expected %p, got %p\n", i, load, ret);
2823 ok(ret == (void*)itda[i].u1.AddressOfData, "Test %u: expected %p, got %p\n",
2824 i, ret, (void*)itda[i].u1.AddressOfData);
2825 ok(!cb_count, "Test %u: Wrong callback count: %d\n", i, cb_count);
2827 else
2829 ok(ret == (void*)0xdeadbeef, "Test %u: ResolveDelayLoadedAPI succeeded with %p\n", i, ret);
2830 ok(cb_count, "Test %u: Wrong callback count: %d\n", i, cb_count);
2833 delaydir++;
2836 FreeLibrary(hlib);
2837 trace("deleting %s\n", dll_name);
2838 DeleteFileA(dll_name);
2841 static void test_InMemoryOrderModuleList(void)
2843 LIST_ENTRY *entry1, *mark1 = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
2844 LIST_ENTRY *entry2, *mark2 = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
2845 LDR_MODULE *module1, *module2;
2847 for (entry1 = mark1->Flink, entry2 = mark2->Flink;
2848 entry1 != mark1 && entry2 != mark2;
2849 entry1 = entry1->Flink, entry2 = entry2->Flink)
2851 module1 = CONTAINING_RECORD(entry1, LDR_MODULE, InLoadOrderModuleList);
2852 module2 = CONTAINING_RECORD(entry2, LDR_MODULE, InMemoryOrderModuleList);
2853 ok(module1 == module2, "expected module1 == module2, got %p and %p\n", module1, module2);
2855 ok(entry1 == mark1, "expected entry1 == mark1, got %p and %p\n", entry1, mark1);
2856 ok(entry2 == mark2, "expected entry2 == mark2, got %p and %p\n", entry2, mark2);
2859 START_TEST(loader)
2861 int argc;
2862 char **argv;
2863 HANDLE ntdll, mapping;
2864 SYSTEM_INFO si;
2866 ntdll = GetModuleHandleA("ntdll.dll");
2867 pNtCreateSection = (void *)GetProcAddress(ntdll, "NtCreateSection");
2868 pNtQuerySection = (void *)GetProcAddress(ntdll, "NtQuerySection");
2869 pNtMapViewOfSection = (void *)GetProcAddress(ntdll, "NtMapViewOfSection");
2870 pNtUnmapViewOfSection = (void *)GetProcAddress(ntdll, "NtUnmapViewOfSection");
2871 pNtTerminateProcess = (void *)GetProcAddress(ntdll, "NtTerminateProcess");
2872 pNtQueryInformationProcess = (void *)GetProcAddress(ntdll, "NtQueryInformationProcess");
2873 pNtSetInformationProcess = (void *)GetProcAddress(ntdll, "NtSetInformationProcess");
2874 pLdrShutdownProcess = (void *)GetProcAddress(ntdll, "LdrShutdownProcess");
2875 pRtlDllShutdownInProgress = (void *)GetProcAddress(ntdll, "RtlDllShutdownInProgress");
2876 pNtAllocateVirtualMemory = (void *)GetProcAddress(ntdll, "NtAllocateVirtualMemory");
2877 pNtFreeVirtualMemory = (void *)GetProcAddress(ntdll, "NtFreeVirtualMemory");
2878 pLdrLockLoaderLock = (void *)GetProcAddress(ntdll, "LdrLockLoaderLock");
2879 pLdrUnlockLoaderLock = (void *)GetProcAddress(ntdll, "LdrUnlockLoaderLock");
2880 pRtlAcquirePebLock = (void *)GetProcAddress(ntdll, "RtlAcquirePebLock");
2881 pRtlReleasePebLock = (void *)GetProcAddress(ntdll, "RtlReleasePebLock");
2882 pRtlImageDirectoryEntryToData = (void *)GetProcAddress(ntdll, "RtlImageDirectoryEntryToData");
2883 pResolveDelayLoadedAPI = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "ResolveDelayLoadedAPI");
2885 GetSystemInfo( &si );
2886 page_size = si.dwPageSize;
2887 dos_header.e_magic = IMAGE_DOS_SIGNATURE;
2888 dos_header.e_lfanew = sizeof(dos_header);
2890 mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_loader");
2891 ok(mapping != 0, "CreateFileMapping failed\n");
2892 child_failures = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 4096);
2893 if (*child_failures == -1)
2895 *child_failures = 0;
2897 else
2898 *child_failures = -1;
2900 argc = winetest_get_mainargs(&argv);
2901 if (argc > 4)
2903 test_dll_phase = atoi(argv[4]);
2904 child_process(argv[2], atol(argv[3]));
2905 return;
2908 test_Loader();
2909 test_ResolveDelayLoadedAPI();
2910 test_ImportDescriptors();
2911 test_section_access();
2912 test_import_resolution();
2913 test_ExitProcess();
2914 test_InMemoryOrderModuleList();