include: Make sure __int64 is correctly defined on PPC64.
[wine.git] / dlls / kernel32 / tests / loader.c
blob861fc321729dc14fa04c056a16ed55f1cc4ebce1
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 #define NONAMELESSSTRUCT
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <assert.h>
27 #include "ntstatus.h"
28 #define WIN32_NO_STATUS
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winternl.h"
32 #include "winnls.h"
33 #include "wine/test.h"
34 #include "delayloadhandler.h"
36 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
37 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
39 #define ALIGN_SIZE(size, alignment) (((size) + (alignment - 1)) & ~((alignment - 1)))
41 struct PROCESS_BASIC_INFORMATION_PRIVATE
43 DWORD_PTR ExitStatus;
44 PPEB PebBaseAddress;
45 DWORD_PTR AffinityMask;
46 DWORD_PTR BasePriority;
47 ULONG_PTR UniqueProcessId;
48 ULONG_PTR InheritedFromUniqueProcessId;
51 static LONG *child_failures;
52 static WORD cb_count, cb_count_sys;
53 static DWORD page_size;
54 static BOOL is_win64 = sizeof(void *) > sizeof(int);
55 static BOOL is_wow64;
57 static NTSTATUS (WINAPI *pNtCreateSection)(HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *,
58 const LARGE_INTEGER *, ULONG, ULONG, HANDLE );
59 static NTSTATUS (WINAPI *pNtQuerySection)(HANDLE, SECTION_INFORMATION_CLASS, void *, SIZE_T, SIZE_T *);
60 static NTSTATUS (WINAPI *pNtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG_PTR, SIZE_T, const LARGE_INTEGER *, SIZE_T *, ULONG, ULONG, ULONG);
61 static NTSTATUS (WINAPI *pNtUnmapViewOfSection)(HANDLE, PVOID);
62 static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
63 static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
64 static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE, DWORD);
65 static void (WINAPI *pLdrShutdownProcess)(void);
66 static BOOLEAN (WINAPI *pRtlDllShutdownInProgress)(void);
67 static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG_PTR, SIZE_T *, ULONG, ULONG);
68 static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG);
69 static NTSTATUS (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG *, ULONG_PTR *);
70 static NTSTATUS (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG_PTR);
71 static NTSTATUS (WINAPI *pLdrLoadDll)(LPCWSTR,DWORD,const UNICODE_STRING *,HMODULE*);
72 static NTSTATUS (WINAPI *pLdrUnloadDll)(HMODULE);
73 static void (WINAPI *pRtlInitUnicodeString)(PUNICODE_STRING,LPCWSTR);
74 static void (WINAPI *pRtlAcquirePebLock)(void);
75 static void (WINAPI *pRtlReleasePebLock)(void);
76 static PVOID (WINAPI *pResolveDelayLoadedAPI)(PVOID, PCIMAGE_DELAYLOAD_DESCRIPTOR,
77 PDELAYLOAD_FAILURE_DLL_CALLBACK,
78 PDELAYLOAD_FAILURE_SYSTEM_ROUTINE,
79 PIMAGE_THUNK_DATA ThunkAddress,ULONG);
80 static PVOID (WINAPI *pRtlImageDirectoryEntryToData)(HMODULE,BOOL,WORD,ULONG *);
81 static PIMAGE_NT_HEADERS (WINAPI *pRtlImageNtHeader)(HMODULE);
82 static DWORD (WINAPI *pFlsAlloc)(PFLS_CALLBACK_FUNCTION);
83 static BOOL (WINAPI *pFlsSetValue)(DWORD, PVOID);
84 static PVOID (WINAPI *pFlsGetValue)(DWORD);
85 static BOOL (WINAPI *pFlsFree)(DWORD);
86 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
87 static BOOL (WINAPI *pWow64DisableWow64FsRedirection)(void **);
88 static BOOL (WINAPI *pWow64RevertWow64FsRedirection)(void *);
89 static HMODULE (WINAPI *pLoadPackagedLibrary)(LPCWSTR lpwLibFileName, DWORD Reserved);
91 static PVOID RVAToAddr(DWORD_PTR rva, HMODULE module)
93 if (rva == 0)
94 return NULL;
95 return ((char*) module) + rva;
98 static IMAGE_DOS_HEADER dos_header;
100 static const IMAGE_NT_HEADERS nt_header_template =
102 IMAGE_NT_SIGNATURE, /* Signature */
104 #if defined __i386__
105 IMAGE_FILE_MACHINE_I386, /* Machine */
106 #elif defined __x86_64__
107 IMAGE_FILE_MACHINE_AMD64, /* Machine */
108 #elif defined __arm__
109 IMAGE_FILE_MACHINE_ARMNT, /* Machine */
110 #elif defined __aarch64__
111 IMAGE_FILE_MACHINE_ARM64, /* Machine */
112 #else
113 # error You must specify the machine type
114 #endif
115 1, /* NumberOfSections */
116 0, /* TimeDateStamp */
117 0, /* PointerToSymbolTable */
118 0, /* NumberOfSymbols */
119 sizeof(IMAGE_OPTIONAL_HEADER), /* SizeOfOptionalHeader */
120 IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL /* Characteristics */
122 { IMAGE_NT_OPTIONAL_HDR_MAGIC, /* Magic */
123 1, /* MajorLinkerVersion */
124 0, /* MinorLinkerVersion */
125 0, /* SizeOfCode */
126 0, /* SizeOfInitializedData */
127 0, /* SizeOfUninitializedData */
128 0, /* AddressOfEntryPoint */
129 0x10, /* BaseOfCode, also serves as e_lfanew in the truncated MZ header */
130 #ifndef _WIN64
131 0, /* BaseOfData */
132 #endif
133 0x10000000, /* ImageBase */
134 0, /* SectionAlignment */
135 0, /* FileAlignment */
136 4, /* MajorOperatingSystemVersion */
137 0, /* MinorOperatingSystemVersion */
138 1, /* MajorImageVersion */
139 0, /* MinorImageVersion */
140 4, /* MajorSubsystemVersion */
141 0, /* MinorSubsystemVersion */
142 0, /* Win32VersionValue */
143 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000, /* SizeOfImage */
144 sizeof(dos_header) + sizeof(nt_header_template), /* SizeOfHeaders */
145 0, /* CheckSum */
146 IMAGE_SUBSYSTEM_WINDOWS_CUI, /* Subsystem */
147 0, /* DllCharacteristics */
148 0, /* SizeOfStackReserve */
149 0, /* SizeOfStackCommit */
150 0, /* SizeOfHeapReserve */
151 0, /* SizeOfHeapCommit */
152 0, /* LoaderFlags */
153 0, /* NumberOfRvaAndSizes */
154 { { 0 } } /* DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] */
158 static IMAGE_SECTION_HEADER section =
160 ".rodata", /* Name */
161 { 0 }, /* Misc */
162 0, /* VirtualAddress */
163 0, /* SizeOfRawData */
164 0, /* PointerToRawData */
165 0, /* PointerToRelocations */
166 0, /* PointerToLinenumbers */
167 0, /* NumberOfRelocations */
168 0, /* NumberOfLinenumbers */
169 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, /* Characteristics */
173 static const char filler[0x1000];
174 static const char section_data[0x10] = "section data";
176 /* return an alternate machine of the same 32/64 bitness */
177 static WORD get_alt_machine( WORD orig_machine )
179 switch (orig_machine)
181 case IMAGE_FILE_MACHINE_I386: return IMAGE_FILE_MACHINE_ARMNT;
182 case IMAGE_FILE_MACHINE_AMD64: return IMAGE_FILE_MACHINE_ARM64;
183 case IMAGE_FILE_MACHINE_ARMNT: return IMAGE_FILE_MACHINE_I386;
184 case IMAGE_FILE_MACHINE_ARM64: return IMAGE_FILE_MACHINE_AMD64;
186 return 0;
189 /* return the machine of the alternate 32/64 bitness */
190 static WORD get_alt_bitness_machine( WORD orig_machine )
192 switch (orig_machine)
194 case IMAGE_FILE_MACHINE_I386: return IMAGE_FILE_MACHINE_AMD64;
195 case IMAGE_FILE_MACHINE_AMD64: return IMAGE_FILE_MACHINE_I386;
196 case IMAGE_FILE_MACHINE_ARMNT: return IMAGE_FILE_MACHINE_ARM64;
197 case IMAGE_FILE_MACHINE_ARM64: return IMAGE_FILE_MACHINE_ARMNT;
199 return 0;
202 static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size,
203 const IMAGE_NT_HEADERS *nt_header, char dll_name[MAX_PATH] )
205 char temp_path[MAX_PATH];
206 DWORD dummy, size, file_align;
207 HANDLE hfile;
208 BOOL ret;
210 GetTempPathA(MAX_PATH, temp_path);
211 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
213 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
214 ok( hfile != INVALID_HANDLE_VALUE, "failed to create %s err %u\n", dll_name, GetLastError() );
215 if (hfile == INVALID_HANDLE_VALUE) return 0;
217 SetLastError(0xdeadbeef);
218 ret = WriteFile(hfile, dos_header, dos_size, &dummy, NULL);
219 ok(ret, "WriteFile error %d\n", GetLastError());
221 SetLastError(0xdeadbeef);
222 ret = WriteFile(hfile, nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
223 ok(ret, "WriteFile error %d\n", GetLastError());
225 if (nt_header->FileHeader.SizeOfOptionalHeader)
227 SetLastError(0xdeadbeef);
228 ret = WriteFile(hfile, &nt_header->OptionalHeader,
229 sizeof(IMAGE_OPTIONAL_HEADER),
230 &dummy, NULL);
231 ok(ret, "WriteFile error %d\n", GetLastError());
232 if (nt_header->FileHeader.SizeOfOptionalHeader > sizeof(IMAGE_OPTIONAL_HEADER))
234 file_align = nt_header->FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER);
235 assert(file_align < sizeof(filler));
236 SetLastError(0xdeadbeef);
237 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
238 ok(ret, "WriteFile error %d\n", GetLastError());
242 assert(nt_header->FileHeader.NumberOfSections <= 1);
243 if (nt_header->FileHeader.NumberOfSections)
245 SetFilePointer(hfile, dos_size + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + nt_header->FileHeader.SizeOfOptionalHeader, NULL, FILE_BEGIN);
247 section.SizeOfRawData = 10;
249 if (nt_header->OptionalHeader.SectionAlignment >= page_size)
251 section.PointerToRawData = dos_size;
252 section.VirtualAddress = nt_header->OptionalHeader.SectionAlignment;
253 section.Misc.VirtualSize = section.SizeOfRawData * 10;
255 else
257 section.PointerToRawData = nt_header->OptionalHeader.SizeOfHeaders;
258 section.VirtualAddress = nt_header->OptionalHeader.SizeOfHeaders;
259 section.Misc.VirtualSize = 5;
262 SetLastError(0xdeadbeef);
263 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
264 ok(ret, "WriteFile error %d\n", GetLastError());
266 /* section data */
267 SetLastError(0xdeadbeef);
268 ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
269 ok(ret, "WriteFile error %d\n", GetLastError());
272 /* Minimal PE image that Windows7+ is able to load: 268 bytes */
273 size = GetFileSize(hfile, NULL);
274 if (size < 268)
276 file_align = 268 - size;
277 SetLastError(0xdeadbeef);
278 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
279 ok(ret, "WriteFile error %d\n", GetLastError());
282 size = GetFileSize(hfile, NULL);
283 CloseHandle(hfile);
284 return size;
287 static DWORD create_test_dll_sections( const IMAGE_DOS_HEADER *dos_header, const IMAGE_NT_HEADERS *nt_header,
288 const IMAGE_SECTION_HEADER *sections, const void *section_data,
289 char dll_name[MAX_PATH] )
291 char temp_path[MAX_PATH];
292 DWORD dummy, i, size;
293 HANDLE hfile;
294 BOOL ret;
296 GetTempPathA(MAX_PATH, temp_path);
297 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
299 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
300 ok( hfile != INVALID_HANDLE_VALUE, "failed to create %s err %u\n", dll_name, GetLastError() );
301 if (hfile == INVALID_HANDLE_VALUE) return 0;
303 SetLastError(0xdeadbeef);
304 ret = WriteFile(hfile, dos_header, sizeof(*dos_header), &dummy, NULL);
305 ok(ret, "WriteFile error %d\n", GetLastError());
307 SetLastError(0xdeadbeef);
308 ret = WriteFile(hfile, nt_header, offsetof(IMAGE_NT_HEADERS, OptionalHeader) + nt_header->FileHeader.SizeOfOptionalHeader, &dummy, NULL);
309 ok(ret, "WriteFile error %d\n", GetLastError());
311 SetLastError(0xdeadbeef);
312 ret = WriteFile(hfile, sections, sizeof(*sections) * nt_header->FileHeader.NumberOfSections,
313 &dummy, NULL);
314 ok(ret, "WriteFile error %d\n", GetLastError());
316 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
318 SetFilePointer(hfile, sections[i].PointerToRawData, NULL, FILE_BEGIN);
319 SetLastError(0xdeadbeef);
320 ret = WriteFile(hfile, section_data, sections[i].SizeOfRawData, &dummy, NULL);
321 ok(ret, "WriteFile error %d\n", GetLastError());
323 size = GetFileSize(hfile, NULL);
324 CloseHandle(hfile);
325 return size;
328 static BOOL query_image_section( int id, const char *dll_name, const IMAGE_NT_HEADERS *nt_header,
329 const void *section_data )
331 static BOOL is_winxp;
332 SECTION_BASIC_INFORMATION info;
333 SECTION_IMAGE_INFORMATION image;
334 const IMAGE_COR20_HEADER *cor_header = NULL;
335 SIZE_T info_size = (SIZE_T)0xdeadbeef << 16;
336 NTSTATUS status;
337 HANDLE file, mapping;
338 ULONG file_size;
339 LARGE_INTEGER map_size;
340 SIZE_T max_stack, commit_stack;
341 void *entry_point;
343 /* truncated header is not handled correctly in windows <= w2k3 */
344 BOOL truncated;
346 file = CreateFileA( dll_name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE,
347 NULL, OPEN_EXISTING, 0, 0 );
348 ok( file != INVALID_HANDLE_VALUE, "%u: CreateFile error %d\n", id, GetLastError() );
349 file_size = GetFileSize( file, NULL );
351 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
352 NULL, NULL, PAGE_READONLY, SEC_IMAGE, file );
353 ok( !status, "%u: NtCreateSection failed err %x\n", id, status );
354 if (status)
356 CloseHandle( file );
357 return FALSE;
359 status = pNtQuerySection( mapping, SectionImageInformation, &image, sizeof(image), &info_size );
360 ok( !status, "%u: NtQuerySection failed err %x\n", id, status );
361 ok( info_size == sizeof(image), "%u: NtQuerySection wrong size %lu\n", id, info_size );
362 if (nt_header->OptionalHeader.Magic == (is_win64 ? IMAGE_NT_OPTIONAL_HDR64_MAGIC
363 : IMAGE_NT_OPTIONAL_HDR32_MAGIC))
365 max_stack = nt_header->OptionalHeader.SizeOfStackReserve;
366 commit_stack = nt_header->OptionalHeader.SizeOfStackCommit;
367 entry_point = (char *)nt_header->OptionalHeader.ImageBase + nt_header->OptionalHeader.AddressOfEntryPoint;
368 truncated = nt_header->FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER);
369 if (!truncated &&
370 nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress &&
371 nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
372 cor_header = section_data;
374 else if (nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
376 const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt_header;
377 max_stack = 0x100000;
378 commit_stack = 0x10000;
379 entry_point = (void *)0x81231234;
380 truncated = nt_header->FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER64);
381 if (!truncated &&
382 nt64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress &&
383 nt64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
384 cor_header = section_data;
386 else
388 const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt_header;
389 max_stack = nt32->OptionalHeader.SizeOfStackReserve;
390 commit_stack = nt32->OptionalHeader.SizeOfStackCommit;
391 entry_point = (char *)(ULONG_PTR)nt32->OptionalHeader.ImageBase + nt32->OptionalHeader.AddressOfEntryPoint;
392 truncated = nt_header->FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER32);
393 if (!truncated &&
394 nt32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress &&
395 nt32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
396 cor_header = section_data;
398 ok( (char *)image.TransferAddress == (char *)entry_point ||
399 (S(U(image)).ImageDynamicallyRelocated && LOWORD(image.TransferAddress) == LOWORD(entry_point)),
400 "%u: TransferAddress wrong %p / %p (%08x)\n", id,
401 image.TransferAddress, entry_point, nt_header->OptionalHeader.AddressOfEntryPoint );
402 ok( image.ZeroBits == 0, "%u: ZeroBits wrong %08x\n", id, image.ZeroBits );
403 ok( image.MaximumStackSize == max_stack || broken(truncated),
404 "%u: MaximumStackSize wrong %lx / %lx\n", id, image.MaximumStackSize, max_stack );
405 ok( image.CommittedStackSize == commit_stack || broken(truncated),
406 "%u: CommittedStackSize wrong %lx / %lx\n", id, image.CommittedStackSize, commit_stack );
407 if (truncated)
408 ok( !image.SubSystemType || broken(truncated),
409 "%u: SubSystemType wrong %08x / 00000000\n", id, image.SubSystemType );
410 else
411 ok( image.SubSystemType == nt_header->OptionalHeader.Subsystem,
412 "%u: SubSystemType wrong %08x / %08x\n", id,
413 image.SubSystemType, nt_header->OptionalHeader.Subsystem );
414 ok( image.MinorSubsystemVersion == nt_header->OptionalHeader.MinorSubsystemVersion,
415 "%u: MinorSubsystemVersion wrong %04x / %04x\n", id,
416 image.MinorSubsystemVersion, nt_header->OptionalHeader.MinorSubsystemVersion );
417 ok( image.MajorSubsystemVersion == nt_header->OptionalHeader.MajorSubsystemVersion,
418 "%u: MajorSubsystemVersion wrong %04x / %04x\n", id,
419 image.MajorSubsystemVersion, nt_header->OptionalHeader.MajorSubsystemVersion );
420 ok( image.MajorOperatingSystemVersion == nt_header->OptionalHeader.MajorOperatingSystemVersion ||
421 broken( !image.MajorOperatingSystemVersion), /* before win10 */
422 "%u: MajorOperatingSystemVersion wrong %04x / %04x\n", id,
423 image.MajorOperatingSystemVersion, nt_header->OptionalHeader.MajorOperatingSystemVersion );
424 ok( image.MinorOperatingSystemVersion == nt_header->OptionalHeader.MinorOperatingSystemVersion,
425 "%u: MinorOperatingSystemVersion wrong %04x / %04x\n", id,
426 image.MinorOperatingSystemVersion, nt_header->OptionalHeader.MinorOperatingSystemVersion );
427 ok( image.ImageCharacteristics == nt_header->FileHeader.Characteristics,
428 "%u: ImageCharacteristics wrong %04x / %04x\n", id,
429 image.ImageCharacteristics, nt_header->FileHeader.Characteristics );
430 ok( image.DllCharacteristics == nt_header->OptionalHeader.DllCharacteristics || broken(truncated),
431 "%u: DllCharacteristics wrong %04x / %04x\n", id,
432 image.DllCharacteristics, nt_header->OptionalHeader.DllCharacteristics );
433 ok( image.Machine == nt_header->FileHeader.Machine, "%u: Machine wrong %04x / %04x\n", id,
434 image.Machine, nt_header->FileHeader.Machine );
435 ok( image.LoaderFlags == (cor_header != NULL), "%u: LoaderFlags wrong %08x\n", id, image.LoaderFlags );
436 ok( image.ImageFileSize == file_size || broken(!image.ImageFileSize), /* winxpsp1 */
437 "%u: ImageFileSize wrong %08x / %08x\n", id, image.ImageFileSize, file_size );
438 ok( image.CheckSum == nt_header->OptionalHeader.CheckSum || broken(truncated),
439 "%u: CheckSum wrong %08x / %08x\n", id,
440 image.CheckSum, nt_header->OptionalHeader.CheckSum );
442 if (nt_header->OptionalHeader.SizeOfCode || nt_header->OptionalHeader.AddressOfEntryPoint)
443 ok( image.ImageContainsCode == TRUE, "%u: ImageContainsCode wrong %u\n", id,
444 image.ImageContainsCode );
445 else if ((nt_header->OptionalHeader.SectionAlignment % page_size) ||
446 (nt_header->FileHeader.NumberOfSections == 1 &&
447 (section.Characteristics & IMAGE_SCN_MEM_EXECUTE)))
448 ok( image.ImageContainsCode == TRUE || broken(!image.ImageContainsCode), /* <= win8 */
449 "%u: ImageContainsCode wrong %u\n", id, image.ImageContainsCode );
450 else
451 ok( !image.ImageContainsCode, "%u: ImageContainsCode wrong %u\n", id, image.ImageContainsCode );
453 if (cor_header &&
454 (cor_header->Flags & COMIMAGE_FLAGS_ILONLY) &&
455 (cor_header->MajorRuntimeVersion > 2 ||
456 (cor_header->MajorRuntimeVersion == 2 && cor_header->MinorRuntimeVersion >= 5)))
458 ok( S(U(image)).ComPlusILOnly || broken(is_winxp),
459 "%u: wrong ComPlusILOnly flags %02x\n", id, U(image).ImageFlags );
460 if (nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
461 !(cor_header->Flags & COMIMAGE_FLAGS_32BITREQUIRED))
462 ok( S(U(image)).ComPlusNativeReady || broken(is_winxp),
463 "%u: wrong ComPlusNativeReady flags %02x\n", id, U(image).ImageFlags );
464 else
465 ok( !S(U(image)).ComPlusNativeReady,
466 "%u: wrong ComPlusNativeReady flags %02x\n", id, U(image).ImageFlags );
467 if (nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
468 (cor_header->Flags & COMIMAGE_FLAGS_32BITPREFERRED))
469 ok( S(U(image)).ComPlusPrefer32bit ||
470 broken( !image.MajorOperatingSystemVersion ), /* before win10 */
471 "%u: wrong ComPlusPrefer32bit flags %02x\n", id, U(image).ImageFlags );
472 else
473 ok( !S(U(image)).ComPlusPrefer32bit, "%u: wrong ComPlusPrefer32bit flags %02x\n", id, U(image).ImageFlags );
475 else
477 ok( !S(U(image)).ComPlusILOnly, "%u: wrong ComPlusILOnly flags %02x\n", id, U(image).ImageFlags );
478 ok( !S(U(image)).ComPlusNativeReady, "%u: wrong ComPlusNativeReady flags %02x\n", id, U(image).ImageFlags );
479 ok( !S(U(image)).ComPlusPrefer32bit, "%u: wrong ComPlusPrefer32bit flags %02x\n", id, U(image).ImageFlags );
481 if (!(nt_header->OptionalHeader.SectionAlignment % page_size))
482 ok( !S(U(image)).ImageMappedFlat, "%u: wrong ImageMappedFlat flags %02x\n", id, U(image).ImageFlags );
483 else
485 /* winxp doesn't support any of the loader flags */
486 if (!S(U(image)).ImageMappedFlat) is_winxp = TRUE;
487 ok( S(U(image)).ImageMappedFlat || broken(is_winxp),
488 "%u: wrong ImageMappedFlat flags %02x\n", id, U(image).ImageFlags );
490 if (!(nt_header->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE))
491 ok( !S(U(image)).ImageDynamicallyRelocated || broken( S(U(image)).ComPlusILOnly ), /* <= win7 */
492 "%u: wrong ImageDynamicallyRelocated flags %02x\n", id, U(image).ImageFlags );
493 else if (image.ImageContainsCode && !cor_header)
494 ok( S(U(image)).ImageDynamicallyRelocated || broken(is_winxp),
495 "%u: wrong ImageDynamicallyRelocated flags %02x\n", id, U(image).ImageFlags );
496 else
497 ok( !S(U(image)).ImageDynamicallyRelocated || broken(TRUE), /* <= win8 */
498 "%u: wrong ImageDynamicallyRelocated flags %02x\n", id, U(image).ImageFlags );
499 ok( !S(U(image)).BaseBelow4gb, "%u: wrong BaseBelow4gb flags %02x\n", id, U(image).ImageFlags );
501 map_size.QuadPart = (nt_header->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
502 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
503 ok( !status, "NtQuerySection failed err %x\n", status );
504 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %x%08x / %x%08x\n",
505 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
506 CloseHandle( mapping );
508 map_size.QuadPart = (nt_header->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
509 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
510 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
511 ok( !status, "%u: NtCreateSection failed err %x\n", id, status );
512 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
513 ok( !status, "NtQuerySection failed err %x\n", status );
514 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %x%08x / %x%08x\n",
515 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
516 CloseHandle( mapping );
518 map_size.QuadPart++;
519 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
520 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
521 ok( status == STATUS_SECTION_TOO_BIG, "%u: NtCreateSection failed err %x\n", id, status );
523 SetFilePointerEx( file, map_size, NULL, FILE_BEGIN );
524 SetEndOfFile( file );
525 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
526 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
527 ok( status == STATUS_SECTION_TOO_BIG, "%u: NtCreateSection failed err %x\n", id, status );
529 map_size.QuadPart = 1;
530 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
531 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
532 ok( !status, "%u: NtCreateSection failed err %x\n", id, status );
533 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
534 ok( !status, "NtQuerySection failed err %x\n", status );
535 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %x%08x / %x%08x\n",
536 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
537 CloseHandle( mapping );
539 CloseHandle( file );
540 return image.ImageContainsCode && (!cor_header || !(cor_header->Flags & COMIMAGE_FLAGS_ILONLY));
543 static const WCHAR wldr_nameW[] = {'w','l','d','r','t','e','s','t','.','d','l','l',0};
544 static WCHAR load_test_name[MAX_PATH], load_fallback_name[MAX_PATH];
545 static WCHAR load_path[MAX_PATH];
547 static void init_load_path( const char *fallback_dll )
549 static const WCHAR pathW[] = {'P','A','T','H',0};
550 static const WCHAR ldrW[] = {'l','d','r',0};
551 static const WCHAR sepW[] = {';',0};
552 static const WCHAR bsW[] = {'\\',0};
553 WCHAR path[MAX_PATH];
555 GetTempPathW( MAX_PATH, path );
556 GetTempFileNameW( path, ldrW, 0, load_test_name );
557 GetTempFileNameW( path, ldrW, 0, load_fallback_name );
558 DeleteFileW( load_test_name );
559 ok( CreateDirectoryW( load_test_name, NULL ), "failed to create dir\n" );
560 DeleteFileW( load_fallback_name );
561 ok( CreateDirectoryW( load_fallback_name, NULL ), "failed to create dir\n" );
562 lstrcpyW( load_path, load_test_name );
563 lstrcatW( load_path, sepW );
564 lstrcatW( load_path, load_fallback_name );
565 lstrcatW( load_path, sepW );
566 GetEnvironmentVariableW( pathW, load_path + lstrlenW(load_path),
567 ARRAY_SIZE(load_path) - lstrlenW(load_path) );
568 lstrcatW( load_test_name, bsW );
569 lstrcatW( load_test_name, wldr_nameW );
570 lstrcatW( load_fallback_name, bsW );
571 lstrcatW( load_fallback_name, wldr_nameW );
572 MultiByteToWideChar( CP_ACP, 0, fallback_dll, -1, path, MAX_PATH );
573 MoveFileW( path, load_fallback_name );
576 static void delete_load_path(void)
578 WCHAR *p;
580 DeleteFileW( load_test_name );
581 for (p = load_test_name + lstrlenW(load_test_name) - 1; *p != '\\'; p--) ;
582 *p = 0;
583 RemoveDirectoryW( load_test_name );
584 DeleteFileW( load_fallback_name );
585 for (p = load_fallback_name + lstrlenW(load_fallback_name) - 1; *p != '\\'; p--) ;
586 *p = 0;
587 RemoveDirectoryW( load_fallback_name );
590 static UINT get_com_dir_size( const IMAGE_NT_HEADERS *nt )
592 if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
593 return ((const IMAGE_NT_HEADERS32 *)nt)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size;
594 else
595 return ((const IMAGE_NT_HEADERS64 *)nt)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size;
598 /* helper to test image section mapping */
599 static NTSTATUS map_image_section( const IMAGE_NT_HEADERS *nt_header, const IMAGE_SECTION_HEADER *sections,
600 const void *section_data, int line )
602 char dll_name[MAX_PATH];
603 WCHAR path[MAX_PATH];
604 UNICODE_STRING name;
605 LARGE_INTEGER size;
606 HANDLE file, map;
607 NTSTATUS status, expect_status, ldr_status;
608 ULONG file_size;
609 BOOL has_code = FALSE, il_only = FALSE, want_32bit = FALSE, expect_fallback = FALSE, wrong_machine = FALSE;
610 HMODULE mod = 0, ldr_mod;
612 file_size = create_test_dll_sections( &dos_header, nt_header, sections, section_data, dll_name );
614 file = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
615 ok(file != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError());
617 size.QuadPart = file_size;
618 status = pNtCreateSection(&map, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
619 NULL, &size, PAGE_READONLY, SEC_IMAGE, file );
620 expect_status = status;
622 if (get_com_dir_size( nt_header ))
624 /* invalid COR20 header seems to corrupt internal loader state on Windows */
625 if (get_com_dir_size( nt_header ) < sizeof(IMAGE_COR20_HEADER)) goto done;
626 if (!((const IMAGE_COR20_HEADER *)section_data)->Flags) goto done;
629 if (!status)
631 SECTION_BASIC_INFORMATION info;
632 SIZE_T info_size = 0xdeadbeef;
633 NTSTATUS ret = pNtQuerySection( map, SectionBasicInformation, &info, sizeof(info), &info_size );
634 ok( !ret, "NtQuerySection failed err %x\n", ret );
635 ok( info_size == sizeof(info), "NtQuerySection wrong size %lu\n", info_size );
636 ok( info.Attributes == (SEC_IMAGE | SEC_FILE), "NtQuerySection wrong attr %x\n", info.Attributes );
637 ok( info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", info.BaseAddress );
638 ok( info.Size.QuadPart == file_size, "NtQuerySection wrong size %x%08x / %08x\n",
639 info.Size.u.HighPart, info.Size.u.LowPart, file_size );
640 has_code = query_image_section( line, dll_name, nt_header, section_data );
642 if (get_com_dir_size( nt_header ))
644 const IMAGE_COR20_HEADER *cor_header = section_data;
645 il_only = (cor_header->Flags & COMIMAGE_FLAGS_ILONLY) != 0;
646 if (il_only) want_32bit = (cor_header->Flags & COMIMAGE_FLAGS_32BITREQUIRED) != 0;
649 SetLastError( 0xdeadbeef );
650 mod = LoadLibraryExA( dll_name, 0, DONT_RESOLVE_DLL_REFERENCES );
651 /* test loading dll of wrong 32/64 bitness */
652 if (nt_header->OptionalHeader.Magic == (is_win64 ? IMAGE_NT_OPTIONAL_HDR32_MAGIC
653 : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
655 if (!has_code && is_win64)
657 ok_(__FILE__,line)( mod != NULL || want_32bit || broken(il_only), /* <= win7 */
658 "loading failed err %u\n", GetLastError() );
660 else
662 ok_(__FILE__, line)( !mod, "loading succeeded\n" );
663 ok_(__FILE__, line)( GetLastError() == ERROR_BAD_EXE_FORMAT, "wrong error %u\n", GetLastError() );
666 else
668 wrong_machine = (nt_header->FileHeader.Machine == get_alt_machine( nt_header_template.FileHeader.Machine ));
670 ok( mod != NULL || broken(il_only) || /* <= win7 */
671 broken( wrong_machine ), /* win8 */
672 "%u: loading failed err %u\n", line, GetLastError() );
673 if (!mod && wrong_machine) expect_status = STATUS_INVALID_IMAGE_FORMAT;
675 if (mod) FreeLibrary( mod );
676 expect_fallback = !mod;
679 /* test fallback to another dll further in the load path */
681 MultiByteToWideChar( CP_ACP, 0, dll_name, -1, path, MAX_PATH );
682 CopyFileW( path, load_test_name, FALSE );
683 pRtlInitUnicodeString( &name, wldr_nameW );
684 ldr_status = pLdrLoadDll( load_path, 0, &name, &ldr_mod );
685 if (!ldr_status)
687 GetModuleFileNameW( ldr_mod, path, MAX_PATH );
688 if (!lstrcmpiW( path, load_test_name ))
690 if (!expect_status)
691 ok( !expect_fallback, "%u: got test dll but expected fallback\n", line );
692 else
693 ok( !expect_fallback, "%u: got test dll but expected failure %x\n", line, expect_status );
695 else if (!lstrcmpiW( path, load_fallback_name ))
697 trace( "%u: loaded fallback\n", line );
698 if (!expect_status)
699 ok( expect_fallback ||
700 /* win10 also falls back for 32-bit dll without code, even though it could be loaded */
701 (is_win64 && !has_code &&
702 nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC),
703 "%u: got fallback but expected test dll\n", line );
704 else
705 ok( broken(expect_status == STATUS_INVALID_IMAGE_FORMAT), /* <= vista */
706 "%u: got fallback but expected failure %x\n", line, expect_status );
708 else ok( 0, "%u: got unexpected path %s instead of %s\n", line, wine_dbgstr_w(path), wine_dbgstr_w(load_test_name));
709 pLdrUnloadDll( ldr_mod );
711 else if (ldr_status == STATUS_DLL_INIT_FAILED ||
712 ldr_status == STATUS_ACCESS_VIOLATION ||
713 ldr_status == STATUS_ILLEGAL_INSTRUCTION)
715 /* some dlls with invalid entry point will crash, but this means we loaded the test dll */
716 ok( !expect_fallback, "%u: got test dll but expected fallback\n", line );
718 else
720 ok( ldr_status == expect_status ||
721 broken(il_only && !expect_status && ldr_status == STATUS_INVALID_IMAGE_FORMAT),
722 "%u: wrong status %x/%x\n", line, ldr_status, expect_status );
723 ok( !expect_fallback || broken(il_only) || broken(wrong_machine),
724 "%u: failed with %x expected fallback\n", line, ldr_status );
727 done:
728 if (map) CloseHandle( map );
729 CloseHandle( file );
730 DeleteFileA( dll_name );
731 return status;
735 static void test_Loader(void)
737 static const struct test_data
739 DWORD size_of_dos_header;
740 WORD number_of_sections, size_of_optional_header;
741 DWORD section_alignment, file_alignment;
742 DWORD size_of_image, size_of_headers;
743 DWORD errors[4]; /* 0 means LoadLibrary should succeed */
744 } td[] =
746 { sizeof(dos_header),
747 1, 0, 0, 0, 0, 0,
748 { ERROR_BAD_EXE_FORMAT }
750 { sizeof(dos_header),
751 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
752 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0xe00,
753 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
754 { ERROR_BAD_EXE_FORMAT } /* XP doesn't like too small image size */
756 { sizeof(dos_header),
757 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
758 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
759 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
760 { ERROR_SUCCESS }
762 { sizeof(dos_header),
763 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
764 0x1f00,
765 0x1000,
766 { ERROR_SUCCESS }
768 { sizeof(dos_header),
769 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x200,
770 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x200,
771 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
772 { ERROR_SUCCESS, ERROR_INVALID_ADDRESS } /* vista is more strict */
774 { sizeof(dos_header),
775 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x1000,
776 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
777 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
778 { ERROR_BAD_EXE_FORMAT } /* XP doesn't like alignments */
780 { sizeof(dos_header),
781 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
782 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
783 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
784 { ERROR_SUCCESS }
786 { sizeof(dos_header),
787 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
788 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
789 0x200,
790 { ERROR_SUCCESS }
792 /* Mandatory are all fields up to SizeOfHeaders, everything else
793 * is really optional (at least that's true for XP).
795 #if 0 /* 32-bit Windows 8 crashes inside of LoadLibrary */
796 { sizeof(dos_header),
797 1, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
798 sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER) + 0x10,
799 sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER),
800 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT, ERROR_INVALID_ADDRESS,
801 ERROR_NOACCESS }
803 #endif
804 { sizeof(dos_header),
805 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
806 0xd0, /* beyond of the end of file */
807 0xc0, /* beyond of the end of file */
808 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
810 { sizeof(dos_header),
811 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
812 0x1000,
814 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
816 { sizeof(dos_header),
817 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
820 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
822 #if 0 /* not power of 2 alignments need more test cases */
823 { sizeof(dos_header),
824 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x300, 0x300,
827 { ERROR_BAD_EXE_FORMAT } /* alignment is not power of 2 */
829 #endif
830 { sizeof(dos_header),
831 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 4, 4,
834 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
836 { sizeof(dos_header),
837 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 1, 1,
840 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
842 { sizeof(dos_header),
843 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
846 { ERROR_BAD_EXE_FORMAT } /* image size == 0 -> failure */
848 /* the following data mimics the PE image which upack creates */
849 { 0x10,
850 1, 0x148, 0x1000, 0x200,
851 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
852 0x200,
853 { ERROR_SUCCESS }
855 /* Minimal PE image that XP is able to load: 92 bytes */
856 { 0x04,
857 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum),
858 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
861 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
863 /* Minimal PE image that Windows7 is able to load: 268 bytes */
864 { 0x04,
865 0, 0xf0, /* optional header size just forces 0xf0 bytes to be written,
866 0 or another number don't change the behaviour, what really
867 matters is file size regardless of values in the headers */
868 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
869 0x40, /* minimal image size that Windows7 accepts */
871 { ERROR_SUCCESS }
873 /* the following data mimics the PE image which 8k demos have */
874 { 0x04,
875 0, 0x08,
876 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
877 0x200000,
878 0x40,
879 { ERROR_SUCCESS }
882 int i;
883 DWORD file_size;
884 HANDLE h;
885 HMODULE hlib, hlib_as_data_file;
886 char dll_name[MAX_PATH];
887 SIZE_T size;
888 BOOL ret;
889 NTSTATUS status;
890 WORD orig_machine = nt_header_template.FileHeader.Machine;
891 IMAGE_NT_HEADERS nt_header;
892 IMAGE_COR20_HEADER cor_header;
894 /* prevent displaying of the "Unable to load this DLL" message box */
895 SetErrorMode(SEM_FAILCRITICALERRORS);
897 for (i = 0; i < ARRAY_SIZE(td); i++)
899 nt_header = nt_header_template;
900 nt_header.FileHeader.NumberOfSections = td[i].number_of_sections;
901 nt_header.FileHeader.SizeOfOptionalHeader = td[i].size_of_optional_header;
903 nt_header.OptionalHeader.SectionAlignment = td[i].section_alignment;
904 nt_header.OptionalHeader.FileAlignment = td[i].file_alignment;
905 nt_header.OptionalHeader.SizeOfImage = td[i].size_of_image;
906 nt_header.OptionalHeader.SizeOfHeaders = td[i].size_of_headers;
908 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
909 file_size = create_test_dll( &dos_header, td[i].size_of_dos_header, &nt_header, dll_name );
911 SetLastError(0xdeadbeef);
912 hlib = LoadLibraryA(dll_name);
913 if (hlib)
915 MEMORY_BASIC_INFORMATION info;
916 void *ptr;
918 ok( td[i].errors[0] == ERROR_SUCCESS, "%d: should have failed\n", i );
920 SetLastError(0xdeadbeef);
921 size = VirtualQuery(hlib, &info, sizeof(info));
922 ok(size == sizeof(info),
923 "%d: VirtualQuery error %d\n", i, GetLastError());
924 ok(info.BaseAddress == hlib, "%d: %p != %p\n", i, info.BaseAddress, hlib);
925 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
926 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
927 ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %lx != expected %x\n",
928 i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
929 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
930 if (nt_header.OptionalHeader.SectionAlignment < page_size)
931 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
932 else
933 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
934 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
936 SetLastError(0xdeadbeef);
937 ptr = VirtualAlloc(hlib, page_size, MEM_COMMIT, info.Protect);
938 ok(!ptr, "%d: VirtualAlloc should fail\n", i);
939 ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError());
941 SetLastError(0xdeadbeef);
942 size = VirtualQuery((char *)hlib + info.RegionSize, &info, sizeof(info));
943 ok(size == sizeof(info),
944 "%d: VirtualQuery error %d\n", i, GetLastError());
945 if (nt_header.OptionalHeader.SectionAlignment == page_size ||
946 nt_header.OptionalHeader.SectionAlignment == nt_header.OptionalHeader.FileAlignment)
948 ok(info.BaseAddress == (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %p != expected %p\n",
949 i, info.BaseAddress, (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
950 ok(info.AllocationBase == 0, "%d: %p != 0\n", i, info.AllocationBase);
951 ok(info.AllocationProtect == 0, "%d: %x != 0\n", i, info.AllocationProtect);
952 /*ok(info.RegionSize == not_practical_value, "%d: %lx != not_practical_value\n", i, info.RegionSize);*/
953 ok(info.State == MEM_FREE, "%d: %x != MEM_FREE\n", i, info.State);
954 ok(info.Type == 0, "%d: %x != 0\n", i, info.Type);
955 ok(info.Protect == PAGE_NOACCESS, "%d: %x != PAGE_NOACCESS\n", i, info.Protect);
957 else
959 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
960 ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib);
961 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
962 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
963 ok(info.RegionSize == ALIGN_SIZE(file_size, page_size), "%d: got %lx != expected %x\n",
964 i, info.RegionSize, ALIGN_SIZE(file_size, page_size));
965 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
966 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
967 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
970 /* header: check the zeroing of alignment */
971 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
973 const char *start;
975 start = (const char *)hlib + nt_header.OptionalHeader.SizeOfHeaders;
976 size = ALIGN_SIZE((ULONG_PTR)start, page_size) - (ULONG_PTR)start;
977 ok(!memcmp(start, filler, size), "%d: header alignment is not cleared\n", i);
980 if (nt_header.FileHeader.NumberOfSections)
982 SetLastError(0xdeadbeef);
983 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
984 ok(size == sizeof(info),
985 "%d: VirtualQuery error %d\n", i, GetLastError());
986 if (nt_header.OptionalHeader.SectionAlignment < page_size)
988 ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib);
989 ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %lx != expected %x\n",
990 i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
991 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
993 else
995 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
996 ok(info.RegionSize == ALIGN_SIZE(section.Misc.VirtualSize, page_size), "%d: got %lx != expected %x\n",
997 i, info.RegionSize, ALIGN_SIZE(section.Misc.VirtualSize, page_size));
998 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
1000 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
1001 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1002 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
1003 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
1005 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
1006 ok(!memcmp((const char *)hlib + section.VirtualAddress + section.PointerToRawData, &nt_header, section.SizeOfRawData), "wrong section data\n");
1007 else
1008 ok(!memcmp((const char *)hlib + section.PointerToRawData, section_data, section.SizeOfRawData), "wrong section data\n");
1010 /* check the zeroing of alignment */
1011 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
1013 const char *start;
1015 start = (const char *)hlib + section.VirtualAddress + section.PointerToRawData + section.SizeOfRawData;
1016 size = ALIGN_SIZE((ULONG_PTR)start, page_size) - (ULONG_PTR)start;
1017 ok(memcmp(start, filler, size), "%d: alignment should not be cleared\n", i);
1020 SetLastError(0xdeadbeef);
1021 ptr = VirtualAlloc((char *)hlib + section.VirtualAddress, page_size, MEM_COMMIT, info.Protect);
1022 ok(!ptr, "%d: VirtualAlloc should fail\n", i);
1023 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_INVALID_ADDRESS,
1024 "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError());
1027 SetLastError(0xdeadbeef);
1028 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
1029 ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
1030 ok(hlib_as_data_file == hlib, "hlib_as_file and hlib are different\n");
1032 SetLastError(0xdeadbeef);
1033 ret = FreeLibrary(hlib);
1034 ok(ret, "FreeLibrary error %d\n", GetLastError());
1036 SetLastError(0xdeadbeef);
1037 hlib = GetModuleHandleA(dll_name);
1038 ok(hlib != 0, "GetModuleHandle error %u\n", GetLastError());
1040 SetLastError(0xdeadbeef);
1041 ret = FreeLibrary(hlib_as_data_file);
1042 ok(ret, "FreeLibrary error %d\n", GetLastError());
1044 hlib = GetModuleHandleA(dll_name);
1045 ok(!hlib, "GetModuleHandle should fail\n");
1047 SetLastError(0xdeadbeef);
1048 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
1049 ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
1050 ok(((ULONG_PTR)hlib_as_data_file & 3) == 1, "hlib_as_data_file got %p\n", hlib_as_data_file);
1052 hlib = GetModuleHandleA(dll_name);
1053 ok(!hlib, "GetModuleHandle should fail\n");
1055 SetLastError(0xdeadbeef);
1056 h = CreateFileA( dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1057 ok( h != INVALID_HANDLE_VALUE, "open failed err %u\n", GetLastError() );
1058 CloseHandle( h );
1060 SetLastError(0xdeadbeef);
1061 ret = FreeLibrary(hlib_as_data_file);
1062 ok(ret, "FreeLibrary error %d\n", GetLastError());
1064 SetLastError(0xdeadbeef);
1065 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE);
1066 if (!((ULONG_PTR)hlib_as_data_file & 3) || /* winxp */
1067 (!hlib_as_data_file && GetLastError() == ERROR_INVALID_PARAMETER)) /* w2k3 */
1069 win_skip( "LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE not supported\n" );
1070 FreeLibrary(hlib_as_data_file);
1072 else
1074 ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
1076 SetLastError(0xdeadbeef);
1077 h = CreateFileA( dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1078 ok( h == INVALID_HANDLE_VALUE, "open succeeded\n" );
1079 ok( GetLastError() == ERROR_SHARING_VIOLATION, "wrong error %u\n", GetLastError() );
1080 CloseHandle( h );
1082 SetLastError(0xdeadbeef);
1083 h = CreateFileA( dll_name, GENERIC_READ | DELETE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1084 ok( h != INVALID_HANDLE_VALUE, "open failed err %u\n", GetLastError() );
1085 CloseHandle( h );
1087 SetLastError(0xdeadbeef);
1088 ret = FreeLibrary(hlib_as_data_file);
1089 ok(ret, "FreeLibrary error %d\n", GetLastError());
1092 SetLastError(0xdeadbeef);
1093 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE);
1094 if (!((ULONG_PTR)hlib_as_data_file & 3) || /* winxp */
1095 (!hlib_as_data_file && GetLastError() == ERROR_INVALID_PARAMETER)) /* w2k3 */
1097 win_skip( "LOAD_LIBRARY_AS_IMAGE_RESOURCE not supported\n" );
1098 FreeLibrary(hlib_as_data_file);
1100 else
1102 ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
1103 ok(((ULONG_PTR)hlib_as_data_file & 3) == 2, "hlib_as_data_file got %p\n",
1104 hlib_as_data_file);
1106 hlib = GetModuleHandleA(dll_name);
1107 ok(!hlib, "GetModuleHandle should fail\n");
1109 SetLastError(0xdeadbeef);
1110 ret = FreeLibrary(hlib_as_data_file);
1111 ok(ret, "FreeLibrary error %d\n", GetLastError());
1114 SetLastError(0xdeadbeef);
1115 ret = DeleteFileA(dll_name);
1116 ok(ret, "DeleteFile error %d\n", GetLastError());
1118 nt_header.OptionalHeader.AddressOfEntryPoint = 0x12345678;
1119 file_size = create_test_dll( &dos_header, td[i].size_of_dos_header, &nt_header, dll_name );
1120 if (!file_size)
1122 ok(0, "could not create %s\n", dll_name);
1123 break;
1126 query_image_section( i, dll_name, &nt_header, NULL );
1128 else
1130 BOOL error_match;
1131 int error_index;
1133 error_match = FALSE;
1134 for (error_index = 0;
1135 ! error_match && error_index < ARRAY_SIZE(td[i].errors);
1136 error_index++)
1138 error_match = td[i].errors[error_index] == GetLastError();
1140 ok(error_match, "%d: unexpected error %d\n", i, GetLastError());
1143 SetLastError(0xdeadbeef);
1144 ret = DeleteFileA(dll_name);
1145 ok(ret, "DeleteFile error %d\n", GetLastError());
1148 nt_header = nt_header_template;
1149 nt_header.FileHeader.NumberOfSections = 1;
1150 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1152 nt_header.OptionalHeader.SectionAlignment = page_size;
1153 nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
1154 nt_header.OptionalHeader.FileAlignment = page_size;
1155 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
1156 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
1158 section.SizeOfRawData = sizeof(section_data);
1159 section.PointerToRawData = page_size;
1160 section.VirtualAddress = page_size;
1161 section.Misc.VirtualSize = page_size;
1163 create_test_dll_sections( &dos_header, &nt_header, &section, section_data, dll_name );
1164 init_load_path( dll_name );
1166 nt_header.OptionalHeader.AddressOfEntryPoint = 0x1234;
1167 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1168 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1170 nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
1171 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1172 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1174 nt_header.OptionalHeader.SizeOfCode = 0x1000;
1175 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1176 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1177 nt_header.OptionalHeader.SizeOfCode = 0;
1178 nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
1180 dos_header.e_magic = 0;
1181 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1182 ok( status == STATUS_INVALID_IMAGE_NOT_MZ, "NtCreateSection error %08x\n", status );
1184 dos_header.e_magic = IMAGE_DOS_SIGNATURE;
1185 nt_header.Signature = IMAGE_OS2_SIGNATURE;
1186 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1187 ok( status == STATUS_INVALID_IMAGE_NE_FORMAT, "NtCreateSection error %08x\n", status );
1188 for (i = 0; i < 16; i++)
1190 ((IMAGE_OS2_HEADER *)&nt_header)->ne_exetyp = i;
1191 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1192 switch (i)
1194 case 2:
1195 ok( status == STATUS_INVALID_IMAGE_WIN_16, "NtCreateSection %u error %08x\n", i, status );
1196 break;
1197 case 5:
1198 ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection %u error %08x\n", i, status );
1199 break;
1200 default:
1201 ok( status == STATUS_INVALID_IMAGE_NE_FORMAT, "NtCreateSection %u error %08x\n", i, status );
1202 break;
1205 ((IMAGE_OS2_HEADER *)&nt_header)->ne_exetyp = ((IMAGE_OS2_HEADER *)&nt_header_template)->ne_exetyp;
1207 dos_header.e_lfanew = 0x98760000;
1208 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1209 ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection error %08x\n", status );
1211 dos_header.e_lfanew = sizeof(dos_header);
1212 nt_header.Signature = 0xdeadbeef;
1213 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1214 ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection error %08x\n", status );
1216 nt_header.Signature = IMAGE_NT_SIGNATURE;
1217 nt_header.OptionalHeader.Magic = 0xdead;
1218 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1219 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08x\n", status );
1221 nt_header.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC;
1222 nt_header.FileHeader.Machine = 0xdead;
1223 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1224 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
1225 "NtCreateSection error %08x\n", status );
1227 nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_UNKNOWN;
1228 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1229 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
1230 "NtCreateSection error %08x\n", status );
1232 nt_header.FileHeader.Machine = get_alt_machine( orig_machine );
1233 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1234 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
1235 "NtCreateSection error %08x\n", status );
1237 nt_header.FileHeader.Machine = get_alt_bitness_machine( orig_machine );
1238 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1239 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
1240 "NtCreateSection error %08x\n", status );
1242 nt_header.FileHeader.Machine = orig_machine;
1243 nt_header.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
1244 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = page_size;
1245 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = sizeof(cor_header);
1246 section.SizeOfRawData = sizeof(cor_header);
1248 memset( &cor_header, 0, sizeof(cor_header) );
1249 cor_header.cb = sizeof(cor_header);
1250 cor_header.MajorRuntimeVersion = 2;
1251 cor_header.MinorRuntimeVersion = 4;
1252 cor_header.Flags = COMIMAGE_FLAGS_ILONLY;
1253 U(cor_header).EntryPointToken = 0xbeef;
1254 status = map_image_section( &nt_header, &section, &cor_header, __LINE__ );
1255 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1257 cor_header.MinorRuntimeVersion = 5;
1258 status = map_image_section( &nt_header, &section, &cor_header, __LINE__ );
1259 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1261 cor_header.MajorRuntimeVersion = 3;
1262 cor_header.MinorRuntimeVersion = 0;
1263 status = map_image_section( &nt_header, &section, &cor_header, __LINE__ );
1264 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1266 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITREQUIRED;
1267 status = map_image_section( &nt_header, &section, &cor_header, __LINE__ );
1268 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1270 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITPREFERRED;
1271 status = map_image_section( &nt_header, &section, &cor_header, __LINE__ );
1272 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1274 cor_header.Flags = 0;
1275 status = map_image_section( &nt_header, &section, &cor_header, __LINE__ );
1276 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1278 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = 1;
1279 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = 1;
1280 status = map_image_section( &nt_header, &section, &cor_header, __LINE__ );
1281 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1283 if (nt_header.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
1285 IMAGE_NT_HEADERS64 nt64;
1287 memset( &nt64, 0, sizeof(nt64) );
1288 nt64.Signature = IMAGE_NT_SIGNATURE;
1289 nt64.FileHeader.Machine = orig_machine;
1290 nt64.FileHeader.NumberOfSections = 1;
1291 nt64.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
1292 nt64.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL;
1293 nt64.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
1294 nt64.OptionalHeader.MajorLinkerVersion = 1;
1295 nt64.OptionalHeader.SizeOfCode = 0x1000;
1296 nt64.OptionalHeader.AddressOfEntryPoint = 0x1000;
1297 nt64.OptionalHeader.ImageBase = 0x10000000;
1298 nt64.OptionalHeader.SectionAlignment = 0x1000;
1299 nt64.OptionalHeader.FileAlignment = 0x1000;
1300 nt64.OptionalHeader.MajorOperatingSystemVersion = 4;
1301 nt64.OptionalHeader.MajorImageVersion = 1;
1302 nt64.OptionalHeader.MajorSubsystemVersion = 4;
1303 nt64.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt64) + sizeof(IMAGE_SECTION_HEADER);
1304 nt64.OptionalHeader.SizeOfImage = nt64.OptionalHeader.SizeOfHeaders + 0x1000;
1305 nt64.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
1306 nt64.OptionalHeader.SizeOfStackReserve = 0x321000;
1307 nt64.OptionalHeader.SizeOfStackCommit = 0x123000;
1308 section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
1310 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, section_data, __LINE__ );
1311 ok( status == (is_wow64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_INVALID_IMAGE_WIN_64),
1312 "NtCreateSection error %08x\n", status );
1314 switch (orig_machine)
1316 case IMAGE_FILE_MACHINE_I386: nt64.FileHeader.Machine = IMAGE_FILE_MACHINE_ARM64; break;
1317 case IMAGE_FILE_MACHINE_ARMNT: nt64.FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64; break;
1319 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, section_data, __LINE__ );
1320 ok( status == (is_wow64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_INVALID_IMAGE_WIN_64),
1321 "NtCreateSection error %08x\n", status );
1323 nt64.FileHeader.Machine = get_alt_bitness_machine( orig_machine );
1324 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, section_data, __LINE__ );
1325 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1326 "NtCreateSection error %08x\n", status );
1328 nt64.OptionalHeader.SizeOfCode = 0;
1329 nt64.OptionalHeader.AddressOfEntryPoint = 0x1000;
1330 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1331 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, section_data, __LINE__ );
1332 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1333 "NtCreateSection error %08x\n", status );
1335 nt64.OptionalHeader.SizeOfCode = 0;
1336 nt64.OptionalHeader.AddressOfEntryPoint = 0;
1337 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE;
1338 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, section_data, __LINE__ );
1339 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1340 "NtCreateSection error %08x\n", status );
1342 nt64.OptionalHeader.SizeOfCode = 0x1000;
1343 nt64.OptionalHeader.AddressOfEntryPoint = 0;
1344 nt64.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
1345 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1346 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, section_data, __LINE__ );
1347 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1348 "NtCreateSection error %08x\n", status );
1350 nt64.OptionalHeader.SizeOfCode = 0;
1351 nt64.OptionalHeader.AddressOfEntryPoint = 0;
1352 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1353 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, section_data, __LINE__ );
1354 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1355 "NtCreateSection error %08x\n", status );
1357 nt64.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
1358 nt64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = page_size;
1359 nt64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = sizeof(cor_header);
1360 cor_header.MajorRuntimeVersion = 2;
1361 cor_header.MinorRuntimeVersion = 4;
1362 cor_header.Flags = COMIMAGE_FLAGS_ILONLY;
1363 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, &cor_header, __LINE__ );
1364 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1365 "NtCreateSection error %08x\n", status );
1367 nt64.OptionalHeader.SizeOfCode = 0x1000;
1368 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, &cor_header, __LINE__ );
1369 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1370 "NtCreateSection error %08x\n", status );
1372 cor_header.MinorRuntimeVersion = 5;
1373 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, &cor_header, __LINE__ );
1374 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1375 "NtCreateSection error %08x\n", status );
1377 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITREQUIRED;
1378 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, &cor_header, __LINE__ );
1379 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1380 "NtCreateSection error %08x\n", status );
1382 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITPREFERRED;
1383 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, &cor_header, __LINE__ );
1384 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1385 "NtCreateSection error %08x\n", status );
1387 cor_header.Flags = 0;
1388 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, &cor_header, __LINE__ );
1389 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1390 "NtCreateSection error %08x\n", status );
1392 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = 1;
1393 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = 1;
1394 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, &cor_header, __LINE__ );
1395 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1396 "NtCreateSection error %08x\n", status );
1398 else
1400 IMAGE_NT_HEADERS32 nt32;
1402 memset( &nt32, 0, sizeof(nt32) );
1403 nt32.Signature = IMAGE_NT_SIGNATURE;
1404 nt32.FileHeader.Machine = orig_machine;
1405 nt32.FileHeader.NumberOfSections = 1;
1406 nt32.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32);
1407 nt32.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL;
1408 nt32.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
1409 nt32.OptionalHeader.MajorLinkerVersion = 1;
1410 nt32.OptionalHeader.SizeOfCode = 0x1000;
1411 nt32.OptionalHeader.AddressOfEntryPoint = 0x1000;
1412 nt32.OptionalHeader.ImageBase = 0x10000000;
1413 nt32.OptionalHeader.SectionAlignment = 0x1000;
1414 nt32.OptionalHeader.FileAlignment = 0x1000;
1415 nt32.OptionalHeader.MajorOperatingSystemVersion = 4;
1416 nt32.OptionalHeader.MajorImageVersion = 1;
1417 nt32.OptionalHeader.MajorSubsystemVersion = 4;
1418 nt32.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt32) + sizeof(IMAGE_SECTION_HEADER);
1419 nt32.OptionalHeader.SizeOfImage = nt32.OptionalHeader.SizeOfHeaders + 0x1000;
1420 nt32.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
1421 nt32.OptionalHeader.SizeOfStackReserve = 0x321000;
1422 nt32.OptionalHeader.SizeOfStackCommit = 0x123000;
1423 section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
1425 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, section_data, __LINE__ );
1426 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08x\n", status );
1428 switch (orig_machine)
1430 case IMAGE_FILE_MACHINE_AMD64: nt32.FileHeader.Machine = IMAGE_FILE_MACHINE_ARMNT; break;
1431 case IMAGE_FILE_MACHINE_ARM64: nt32.FileHeader.Machine = IMAGE_FILE_MACHINE_I386; break;
1433 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, section_data, __LINE__ );
1434 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(!status) /* win8 */,
1435 "NtCreateSection error %08x\n", status );
1437 nt32.FileHeader.Machine = get_alt_bitness_machine( orig_machine );
1438 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, section_data, __LINE__ );
1439 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1441 nt32.OptionalHeader.SizeOfCode = 0;
1442 nt32.OptionalHeader.AddressOfEntryPoint = 0x1000;
1443 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1444 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, section_data, __LINE__ );
1445 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1447 nt32.OptionalHeader.SizeOfCode = 0;
1448 nt32.OptionalHeader.AddressOfEntryPoint = 0;
1449 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE;
1450 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, section_data, __LINE__ );
1451 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1453 nt32.OptionalHeader.SizeOfCode = 0x1000;
1454 nt32.OptionalHeader.AddressOfEntryPoint = 0;
1455 nt32.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
1456 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1457 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, section_data, __LINE__ );
1458 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1460 nt32.OptionalHeader.SizeOfCode = 0;
1461 nt32.OptionalHeader.AddressOfEntryPoint = 0;
1462 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1463 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, section_data, __LINE__ );
1464 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1466 nt32.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
1467 nt32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = page_size;
1468 nt32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = sizeof(cor_header);
1469 cor_header.MajorRuntimeVersion = 2;
1470 cor_header.MinorRuntimeVersion = 4;
1471 cor_header.Flags = COMIMAGE_FLAGS_ILONLY;
1472 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, &cor_header, __LINE__ );
1473 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1475 nt32.OptionalHeader.SizeOfCode = 0x1000;
1476 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, &cor_header, __LINE__ );
1477 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1479 cor_header.MinorRuntimeVersion = 5;
1480 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, &cor_header, __LINE__ );
1481 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1483 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITREQUIRED;
1484 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, &cor_header, __LINE__ );
1485 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1487 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITPREFERRED;
1488 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, &cor_header, __LINE__ );
1489 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1491 cor_header.Flags = 0;
1492 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, &cor_header, __LINE__ );
1493 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1495 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = 1;
1496 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = 1;
1497 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, &cor_header, __LINE__ );
1498 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1501 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
1502 delete_load_path();
1505 static void test_filenames(void)
1507 IMAGE_NT_HEADERS nt_header = nt_header_template;
1508 char dll_name[MAX_PATH], long_path[MAX_PATH], short_path[MAX_PATH], buffer[MAX_PATH];
1509 HMODULE mod, mod2;
1510 BOOL ret;
1512 nt_header.FileHeader.NumberOfSections = 1;
1513 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1515 nt_header.OptionalHeader.SectionAlignment = page_size;
1516 nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
1517 nt_header.OptionalHeader.FileAlignment = page_size;
1518 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
1519 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
1521 create_test_dll( &dos_header, sizeof(dos_header), &nt_header, dll_name );
1522 strcpy( long_path, dll_name );
1523 strcpy( strrchr( long_path, '\\' ), "\\this-is-a-long-name.dll" );
1524 ret = MoveFileA( dll_name, long_path );
1525 ok( ret, "MoveFileA failed err %u\n", GetLastError() );
1526 GetShortPathNameA( long_path, short_path, MAX_PATH );
1528 mod = LoadLibraryA( short_path );
1529 ok( mod != NULL, "loading failed err %u\n", GetLastError() );
1530 GetModuleFileNameA( mod, buffer, MAX_PATH );
1531 ok( !lstrcmpiA( buffer, short_path ), "got wrong path %s / %s\n", buffer, short_path );
1532 mod2 = GetModuleHandleA( short_path );
1533 ok( mod == mod2, "wrong module %p for %s\n", mod2, short_path );
1534 mod2 = GetModuleHandleA( long_path );
1535 ok( mod == mod2, "wrong module %p for %s\n", mod2, long_path );
1536 mod2 = LoadLibraryA( long_path );
1537 ok( mod2 != NULL, "loading failed err %u\n", GetLastError() );
1538 ok( mod == mod2, "library loaded twice\n" );
1539 GetModuleFileNameA( mod2, buffer, MAX_PATH );
1540 ok( !lstrcmpiA( buffer, short_path ), "got wrong path %s / %s\n", buffer, short_path );
1541 FreeLibrary( mod2 );
1542 FreeLibrary( mod );
1544 mod = LoadLibraryA( long_path );
1545 ok( mod != NULL, "loading failed err %u\n", GetLastError() );
1546 GetModuleFileNameA( mod, buffer, MAX_PATH );
1547 ok( !lstrcmpiA( buffer, long_path ), "got wrong path %s / %s\n", buffer, long_path );
1548 mod2 = GetModuleHandleA( short_path );
1549 ok( mod == mod2, "wrong module %p for %s\n", mod2, short_path );
1550 mod2 = GetModuleHandleA( long_path );
1551 ok( mod == mod2, "wrong module %p for %s\n", mod2, long_path );
1552 mod2 = LoadLibraryA( short_path );
1553 ok( mod2 != NULL, "loading failed err %u\n", GetLastError() );
1554 ok( mod == mod2, "library loaded twice\n" );
1555 GetModuleFileNameA( mod2, buffer, MAX_PATH );
1556 ok( !lstrcmpiA( buffer, long_path ), "got wrong path %s / %s\n", buffer, long_path );
1557 FreeLibrary( mod2 );
1558 FreeLibrary( mod );
1560 strcpy( dll_name, long_path );
1561 strcpy( strrchr( dll_name, '\\' ), "\\this-is-another-name.dll" );
1562 ret = CreateHardLinkA( dll_name, long_path, NULL );
1563 ok( ret, "CreateHardLinkA failed err %u\n", GetLastError() );
1564 if (ret)
1566 mod = LoadLibraryA( dll_name );
1567 ok( mod != NULL, "loading failed err %u\n", GetLastError() );
1568 GetModuleFileNameA( mod, buffer, MAX_PATH );
1569 ok( !lstrcmpiA( buffer, dll_name ), "got wrong path %s / %s\n", buffer, dll_name );
1570 mod2 = GetModuleHandleA( long_path );
1571 ok( mod == mod2, "wrong module %p for %s\n", mod2, long_path );
1572 mod2 = LoadLibraryA( long_path );
1573 ok( mod2 != NULL, "loading failed err %u\n", GetLastError() );
1574 ok( mod == mod2, "library loaded twice\n" );
1575 GetModuleFileNameA( mod2, buffer, MAX_PATH );
1576 ok( !lstrcmpiA( buffer, dll_name ), "got wrong path %s / %s\n", buffer, short_path );
1577 FreeLibrary( mod2 );
1578 FreeLibrary( mod );
1579 DeleteFileA( dll_name );
1581 DeleteFileA( long_path );
1584 /* Verify linking style of import descriptors */
1585 static void test_ImportDescriptors(void)
1587 HMODULE kernel32_module = NULL;
1588 PIMAGE_DOS_HEADER d_header;
1589 PIMAGE_NT_HEADERS nt_headers;
1590 DWORD import_dir_size;
1591 DWORD_PTR dir_offset;
1592 PIMAGE_IMPORT_DESCRIPTOR import_chunk;
1594 /* Load kernel32 module */
1595 kernel32_module = GetModuleHandleA("kernel32.dll");
1596 assert( kernel32_module != NULL );
1598 /* Get PE header info from module image */
1599 d_header = (PIMAGE_DOS_HEADER) kernel32_module;
1600 nt_headers = (PIMAGE_NT_HEADERS) (((char*) d_header) +
1601 d_header->e_lfanew);
1603 /* Get size of import entry directory */
1604 import_dir_size = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
1605 if (!import_dir_size)
1607 skip("Unable to continue testing due to missing import directory.\n");
1608 return;
1611 /* Get address of first import chunk */
1612 dir_offset = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
1613 import_chunk = RVAToAddr(dir_offset, kernel32_module);
1614 ok(import_chunk != 0, "Invalid import_chunk: %p\n", import_chunk);
1615 if (!import_chunk) return;
1617 /* Iterate through import descriptors and verify set name,
1618 * OriginalFirstThunk, and FirstThunk. Core Windows DLLs, such as
1619 * kernel32.dll, don't use Borland-style linking, where the table of
1620 * imported names is stored directly in FirstThunk and overwritten
1621 * by the relocation, instead of being stored in OriginalFirstThunk.
1622 * */
1623 for (; import_chunk->FirstThunk; import_chunk++)
1625 LPCSTR module_name = RVAToAddr(import_chunk->Name, kernel32_module);
1626 PIMAGE_THUNK_DATA name_table = RVAToAddr(
1627 U(*import_chunk).OriginalFirstThunk, kernel32_module);
1628 PIMAGE_THUNK_DATA iat = RVAToAddr(
1629 import_chunk->FirstThunk, kernel32_module);
1630 ok(module_name != NULL, "Imported module name should not be NULL\n");
1631 ok(name_table != NULL,
1632 "Name table for imported module %s should not be NULL\n",
1633 module_name);
1634 ok(iat != NULL, "IAT for imported module %s should not be NULL\n",
1635 module_name);
1639 static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL is_dll)
1641 HANDLE hfile, hmap;
1642 NTSTATUS status;
1643 LARGE_INTEGER offset;
1644 SIZE_T size;
1645 void *addr1, *addr2;
1646 MEMORY_BASIC_INFORMATION info;
1648 if (!pNtMapViewOfSection) return;
1650 SetLastError(0xdeadbeef);
1651 hfile = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
1652 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError());
1654 SetLastError(0xdeadbeef);
1655 hmap = CreateFileMappingW(hfile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, 0);
1656 ok(hmap != 0, "CreateFileMapping error %d\n", GetLastError());
1658 offset.u.LowPart = 0;
1659 offset.u.HighPart = 0;
1661 addr1 = NULL;
1662 size = 0;
1663 status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr1, 0, 0, &offset,
1664 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1665 ok(status == STATUS_SUCCESS, "NtMapViewOfSection error %x\n", status);
1666 ok(addr1 != 0, "mapped address should be valid\n");
1668 SetLastError(0xdeadbeef);
1669 size = VirtualQuery((char *)addr1 + section.VirtualAddress, &info, sizeof(info));
1670 ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
1671 ok(info.BaseAddress == (char *)addr1 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr1 + section.VirtualAddress);
1672 ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size);
1673 ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
1674 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1675 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1676 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
1677 ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
1679 addr2 = NULL;
1680 size = 0;
1681 status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr2, 0, 0, &offset,
1682 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1683 ok(status == STATUS_IMAGE_NOT_AT_BASE, "expected STATUS_IMAGE_NOT_AT_BASE, got %x\n", status);
1684 ok(addr2 != 0, "mapped address should be valid\n");
1685 ok(addr2 != addr1, "mapped addresses should be different\n");
1687 SetLastError(0xdeadbeef);
1688 size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info));
1689 ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
1690 ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress);
1691 ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size);
1692 ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
1693 ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2);
1694 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1695 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
1696 ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
1698 status = pNtUnmapViewOfSection(GetCurrentProcess(), addr2);
1699 ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status);
1701 addr2 = MapViewOfFile(hmap, 0, 0, 0, 0);
1702 ok(addr2 != 0, "mapped address should be valid\n");
1703 ok(addr2 != addr1, "mapped addresses should be different\n");
1705 SetLastError(0xdeadbeef);
1706 size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info));
1707 ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
1708 ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress);
1709 ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size);
1710 ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
1711 ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2);
1712 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1713 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
1714 ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
1716 UnmapViewOfFile(addr2);
1718 SetLastError(0xdeadbeef);
1719 addr2 = LoadLibraryA(dll_name);
1720 if (is_dll)
1722 ok(!addr2, "LoadLibrary should fail, is_dll %d\n", is_dll);
1723 ok(GetLastError() == ERROR_INVALID_ADDRESS, "expected ERROR_INVALID_ADDRESS, got %d\n", GetLastError());
1725 else
1727 BOOL ret;
1728 ok(addr2 != 0, "LoadLibrary error %d, is_dll %d\n", GetLastError(), is_dll);
1729 ok(addr2 != addr1, "mapped addresses should be different\n");
1731 SetLastError(0xdeadbeef);
1732 ret = FreeLibrary(addr2);
1733 ok(ret, "FreeLibrary error %d\n", GetLastError());
1736 status = pNtUnmapViewOfSection(GetCurrentProcess(), addr1);
1737 ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status);
1739 CloseHandle(hmap);
1740 CloseHandle(hfile);
1743 static BOOL is_mem_writable(DWORD prot)
1745 switch (prot & 0xff)
1747 case PAGE_READWRITE:
1748 case PAGE_WRITECOPY:
1749 case PAGE_EXECUTE_READWRITE:
1750 case PAGE_EXECUTE_WRITECOPY:
1751 return TRUE;
1753 default:
1754 return FALSE;
1758 static void test_VirtualProtect(void *base, void *section)
1760 static const struct test_data
1762 DWORD prot_set, prot_get;
1763 } td[] =
1765 { 0, 0 }, /* 0x00 */
1766 { PAGE_NOACCESS, PAGE_NOACCESS }, /* 0x01 */
1767 { PAGE_READONLY, PAGE_READONLY }, /* 0x02 */
1768 { PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x03 */
1769 { PAGE_READWRITE, PAGE_WRITECOPY }, /* 0x04 */
1770 { PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x05 */
1771 { PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x06 */
1772 { PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x07 */
1773 { PAGE_WRITECOPY, PAGE_WRITECOPY }, /* 0x08 */
1774 { PAGE_WRITECOPY | PAGE_NOACCESS, 0 }, /* 0x09 */
1775 { PAGE_WRITECOPY | PAGE_READONLY, 0 }, /* 0x0a */
1776 { PAGE_WRITECOPY | PAGE_NOACCESS | PAGE_READONLY, 0 }, /* 0x0b */
1777 { PAGE_WRITECOPY | PAGE_READWRITE, 0 }, /* 0x0c */
1778 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x0d */
1779 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x0e */
1780 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x0f */
1782 { PAGE_EXECUTE, PAGE_EXECUTE }, /* 0x10 */
1783 { PAGE_EXECUTE_READ, PAGE_EXECUTE_READ }, /* 0x20 */
1784 { PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x30 */
1785 { PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY }, /* 0x40 */
1786 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0x50 */
1787 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0x60 */
1788 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x70 */
1789 { PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_WRITECOPY }, /* 0x80 */
1790 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE, 0 }, /* 0x90 */
1791 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ, 0 }, /* 0xa0 */
1792 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0xb0 */
1793 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE, 0 }, /* 0xc0 */
1794 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0xd0 */
1795 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0xe0 */
1796 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 } /* 0xf0 */
1798 DWORD ret, orig_prot, old_prot, rw_prot, exec_prot, i, j;
1799 MEMORY_BASIC_INFORMATION info;
1801 SetLastError(0xdeadbeef);
1802 ret = VirtualProtect(section, page_size, PAGE_NOACCESS, &old_prot);
1803 ok(ret, "VirtualProtect error %d\n", GetLastError());
1805 orig_prot = old_prot;
1807 for (i = 0; i < ARRAY_SIZE(td); i++)
1809 SetLastError(0xdeadbeef);
1810 ret = VirtualQuery(section, &info, sizeof(info));
1811 ok(ret, "VirtualQuery failed %d\n", GetLastError());
1812 ok(info.BaseAddress == section, "%d: got %p != expected %p\n", i, info.BaseAddress, section);
1813 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1814 ok(info.Protect == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, info.Protect);
1815 ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
1816 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1817 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1818 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1820 old_prot = 0xdeadbeef;
1821 SetLastError(0xdeadbeef);
1822 ret = VirtualProtect(section, page_size, td[i].prot_set, &old_prot);
1823 if (td[i].prot_get)
1825 ok(ret, "%d: VirtualProtect error %d, requested prot %#x\n", i, GetLastError(), td[i].prot_set);
1826 ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
1828 SetLastError(0xdeadbeef);
1829 ret = VirtualQuery(section, &info, sizeof(info));
1830 ok(ret, "VirtualQuery failed %d\n", GetLastError());
1831 ok(info.BaseAddress == section, "%d: got %p != expected %p\n", i, info.BaseAddress, section);
1832 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1833 ok(info.Protect == td[i].prot_get, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_get);
1834 ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
1835 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1836 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1837 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1839 else
1841 ok(!ret, "%d: VirtualProtect should fail\n", i);
1842 ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
1845 old_prot = 0xdeadbeef;
1846 SetLastError(0xdeadbeef);
1847 ret = VirtualProtect(section, page_size, PAGE_NOACCESS, &old_prot);
1848 ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
1849 if (td[i].prot_get)
1850 ok(old_prot == td[i].prot_get, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_get);
1851 else
1852 ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
1855 exec_prot = 0;
1857 for (i = 0; i <= 4; i++)
1859 rw_prot = 0;
1861 for (j = 0; j <= 4; j++)
1863 DWORD prot = exec_prot | rw_prot;
1865 SetLastError(0xdeadbeef);
1866 ret = VirtualProtect(section, page_size, prot, &old_prot);
1867 if ((rw_prot && exec_prot) || (!rw_prot && !exec_prot))
1869 ok(!ret, "VirtualProtect(%02x) should fail\n", prot);
1870 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1872 else
1873 ok(ret, "VirtualProtect(%02x) error %d\n", prot, GetLastError());
1875 rw_prot = 1 << j;
1878 exec_prot = 1 << (i + 4);
1881 SetLastError(0xdeadbeef);
1882 ret = VirtualProtect(section, page_size, orig_prot, &old_prot);
1883 ok(ret, "VirtualProtect error %d\n", GetLastError());
1886 static void test_section_access(void)
1888 static const struct test_data
1890 DWORD scn_file_access, scn_page_access, scn_page_access_after_write;
1891 } td[] =
1893 { 0, PAGE_NOACCESS, 0 },
1894 { IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1895 { IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1896 { IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1897 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1898 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ },
1899 { IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1900 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1902 { IMAGE_SCN_CNT_INITIALIZED_DATA, PAGE_NOACCESS, 0 },
1903 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1904 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1905 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1906 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1907 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
1908 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1909 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1911 { IMAGE_SCN_CNT_UNINITIALIZED_DATA, PAGE_NOACCESS, 0 },
1912 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1913 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1914 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1915 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1916 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
1917 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1918 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE }
1920 char buf[256];
1921 int i;
1922 DWORD dummy, file_align;
1923 HANDLE hfile;
1924 HMODULE hlib;
1925 char temp_path[MAX_PATH];
1926 char dll_name[MAX_PATH];
1927 SIZE_T size;
1928 MEMORY_BASIC_INFORMATION info;
1929 STARTUPINFOA sti;
1930 PROCESS_INFORMATION pi;
1931 DWORD ret;
1933 /* prevent displaying of the "Unable to load this DLL" message box */
1934 SetErrorMode(SEM_FAILCRITICALERRORS);
1936 GetTempPathA(MAX_PATH, temp_path);
1938 for (i = 0; i < ARRAY_SIZE(td); i++)
1940 IMAGE_NT_HEADERS nt_header;
1942 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
1944 /*trace("creating %s\n", dll_name);*/
1945 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
1946 if (hfile == INVALID_HANDLE_VALUE)
1948 ok(0, "could not create %s\n", dll_name);
1949 return;
1952 SetLastError(0xdeadbeef);
1953 ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
1954 ok(ret, "WriteFile error %d\n", GetLastError());
1956 nt_header = nt_header_template;
1957 nt_header.FileHeader.NumberOfSections = 1;
1958 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1959 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED;
1961 nt_header.OptionalHeader.SectionAlignment = page_size;
1962 nt_header.OptionalHeader.FileAlignment = 0x200;
1963 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
1964 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
1965 SetLastError(0xdeadbeef);
1966 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
1967 ok(ret, "WriteFile error %d\n", GetLastError());
1968 SetLastError(0xdeadbeef);
1969 ret = WriteFile(hfile, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
1970 ok(ret, "WriteFile error %d\n", GetLastError());
1972 section.SizeOfRawData = sizeof(section_data);
1973 section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
1974 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
1975 section.Misc.VirtualSize = section.SizeOfRawData;
1976 section.Characteristics = td[i].scn_file_access;
1977 SetLastError(0xdeadbeef);
1978 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
1979 ok(ret, "WriteFile error %d\n", GetLastError());
1981 file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
1982 assert(file_align < sizeof(filler));
1983 SetLastError(0xdeadbeef);
1984 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
1985 ok(ret, "WriteFile error %d\n", GetLastError());
1987 /* section data */
1988 SetLastError(0xdeadbeef);
1989 ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
1990 ok(ret, "WriteFile error %d\n", GetLastError());
1992 CloseHandle(hfile);
1994 SetLastError(0xdeadbeef);
1995 hlib = LoadLibraryA(dll_name);
1996 ok(hlib != 0, "LoadLibrary error %d\n", GetLastError());
1998 SetLastError(0xdeadbeef);
1999 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
2000 ok(size == sizeof(info),
2001 "%d: VirtualQuery error %d\n", i, GetLastError());
2002 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
2003 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
2004 ok(info.Protect == td[i].scn_page_access, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access);
2005 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
2006 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
2007 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
2008 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
2009 if (info.Protect != PAGE_NOACCESS)
2010 ok(!memcmp((const char *)info.BaseAddress, section_data, section.SizeOfRawData), "wrong section data\n");
2012 test_VirtualProtect(hlib, (char *)hlib + section.VirtualAddress);
2014 /* Windows changes the WRITECOPY to WRITE protection on an image section write (for a changed page only) */
2015 if (is_mem_writable(info.Protect))
2017 char *p = info.BaseAddress;
2018 *p = 0xfe;
2019 SetLastError(0xdeadbeef);
2020 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
2021 ok(size == sizeof(info), "%d: VirtualQuery error %d\n", i, GetLastError());
2022 /* FIXME: remove the condition below once Wine is fixed */
2023 todo_wine_if (info.Protect == PAGE_WRITECOPY || info.Protect == PAGE_EXECUTE_WRITECOPY)
2024 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);
2027 SetLastError(0xdeadbeef);
2028 ret = FreeLibrary(hlib);
2029 ok(ret, "FreeLibrary error %d\n", GetLastError());
2031 test_image_mapping(dll_name, td[i].scn_page_access, TRUE);
2033 /* reset IMAGE_FILE_DLL otherwise CreateProcess fails */
2034 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_RELOCS_STRIPPED;
2035 SetLastError(0xdeadbeef);
2036 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2037 /* LoadLibrary called on an already memory-mapped file in
2038 * test_image_mapping() above leads to a file handle leak
2039 * under nt4, and inability to overwrite and delete the file
2040 * due to sharing violation error. Ignore it and skip the test,
2041 * but leave a not deletable temporary file.
2043 ok(hfile != INVALID_HANDLE_VALUE || broken(hfile == INVALID_HANDLE_VALUE) /* nt4 */,
2044 "CreateFile error %d\n", GetLastError());
2045 if (hfile == INVALID_HANDLE_VALUE) goto nt4_is_broken;
2046 SetFilePointer(hfile, sizeof(dos_header), NULL, FILE_BEGIN);
2047 SetLastError(0xdeadbeef);
2048 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
2049 ok(ret, "WriteFile error %d\n", GetLastError());
2050 CloseHandle(hfile);
2052 memset(&sti, 0, sizeof(sti));
2053 sti.cb = sizeof(sti);
2054 SetLastError(0xdeadbeef);
2055 ret = CreateProcessA(dll_name, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &sti, &pi);
2056 ok(ret, "CreateProcess() error %d\n", GetLastError());
2058 SetLastError(0xdeadbeef);
2059 size = VirtualQueryEx(pi.hProcess, (char *)hlib + section.VirtualAddress, &info, sizeof(info));
2060 ok(size == sizeof(info),
2061 "%d: VirtualQuery error %d\n", i, GetLastError());
2062 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
2063 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
2064 ok(info.Protect == td[i].scn_page_access, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access);
2065 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
2066 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
2067 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
2068 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
2069 if (info.Protect != PAGE_NOACCESS)
2071 SetLastError(0xdeadbeef);
2072 ret = ReadProcessMemory(pi.hProcess, info.BaseAddress, buf, section.SizeOfRawData, NULL);
2073 ok(ret, "ReadProcessMemory() error %d\n", GetLastError());
2074 ok(!memcmp(buf, section_data, section.SizeOfRawData), "wrong section data\n");
2077 SetLastError(0xdeadbeef);
2078 ret = TerminateProcess(pi.hProcess, 0);
2079 ok(ret, "TerminateProcess() error %d\n", GetLastError());
2080 ret = WaitForSingleObject(pi.hProcess, 3000);
2081 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
2083 CloseHandle(pi.hThread);
2084 CloseHandle(pi.hProcess);
2086 test_image_mapping(dll_name, td[i].scn_page_access, FALSE);
2088 nt4_is_broken:
2089 SetLastError(0xdeadbeef);
2090 ret = DeleteFileA(dll_name);
2091 ok(ret || broken(!ret) /* nt4 */, "DeleteFile error %d\n", GetLastError());
2095 static void test_import_resolution(void)
2097 char temp_path[MAX_PATH];
2098 char dll_name[MAX_PATH];
2099 DWORD dummy;
2100 void *expect;
2101 char *str;
2102 HANDLE hfile;
2103 HMODULE mod, mod2;
2104 struct imports
2106 IMAGE_IMPORT_DESCRIPTOR descr[2];
2107 IMAGE_THUNK_DATA original_thunks[2];
2108 IMAGE_THUNK_DATA thunks[2];
2109 char module[16];
2110 struct { WORD hint; char name[32]; } function;
2111 IMAGE_TLS_DIRECTORY tls;
2112 char tls_data[16];
2113 SHORT tls_index;
2114 } data, *ptr;
2115 IMAGE_NT_HEADERS nt;
2116 IMAGE_SECTION_HEADER section;
2117 int test;
2119 for (test = 0; test < 3; test++)
2121 #define DATA_RVA(ptr) (page_size + ((char *)(ptr) - (char *)&data))
2122 nt = nt_header_template;
2123 nt.FileHeader.NumberOfSections = 1;
2124 nt.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
2125 nt.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_RELOCS_STRIPPED;
2126 if (test != 2) nt.FileHeader.Characteristics |= IMAGE_FILE_DLL;
2127 nt.OptionalHeader.SectionAlignment = page_size;
2128 nt.OptionalHeader.FileAlignment = 0x200;
2129 nt.OptionalHeader.ImageBase = 0x12340000;
2130 nt.OptionalHeader.SizeOfImage = 2 * page_size;
2131 nt.OptionalHeader.SizeOfHeaders = nt.OptionalHeader.FileAlignment;
2132 nt.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
2133 memset( nt.OptionalHeader.DataDirectory, 0, sizeof(nt.OptionalHeader.DataDirectory) );
2134 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = sizeof(data.descr);
2135 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = DATA_RVA(data.descr);
2136 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = sizeof(data.tls);
2137 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = DATA_RVA(&data.tls);
2139 memset( &data, 0, sizeof(data) );
2140 U(data.descr[0]).OriginalFirstThunk = DATA_RVA( data.original_thunks );
2141 data.descr[0].FirstThunk = DATA_RVA( data.thunks );
2142 data.descr[0].Name = DATA_RVA( data.module );
2143 strcpy( data.module, "kernel32.dll" );
2144 strcpy( data.function.name, "CreateEventA" );
2145 data.original_thunks[0].u1.AddressOfData = DATA_RVA( &data.function );
2146 data.thunks[0].u1.AddressOfData = 0xdeadbeef;
2148 data.tls.StartAddressOfRawData = nt.OptionalHeader.ImageBase + DATA_RVA( data.tls_data );
2149 data.tls.EndAddressOfRawData = data.tls.StartAddressOfRawData + sizeof(data.tls_data);
2150 data.tls.AddressOfIndex = nt.OptionalHeader.ImageBase + DATA_RVA( &data.tls_index );
2151 strcpy( data.tls_data, "hello world" );
2152 data.tls_index = 9999;
2154 GetTempPathA(MAX_PATH, temp_path);
2155 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
2157 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
2158 ok( hfile != INVALID_HANDLE_VALUE, "creation failed\n" );
2160 memset( &section, 0, sizeof(section) );
2161 memcpy( section.Name, ".text", sizeof(".text") );
2162 section.PointerToRawData = nt.OptionalHeader.FileAlignment;
2163 section.VirtualAddress = nt.OptionalHeader.SectionAlignment;
2164 section.Misc.VirtualSize = sizeof(data);
2165 section.SizeOfRawData = sizeof(data);
2166 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
2168 WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
2169 WriteFile(hfile, &nt, sizeof(nt), &dummy, NULL);
2170 WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
2172 SetFilePointer( hfile, section.PointerToRawData, NULL, SEEK_SET );
2173 WriteFile(hfile, &data, sizeof(data), &dummy, NULL);
2175 CloseHandle( hfile );
2177 switch (test)
2179 case 0: /* normal load */
2180 mod = LoadLibraryA( dll_name );
2181 ok( mod != NULL, "failed to load err %u\n", GetLastError() );
2182 if (!mod) break;
2183 ptr = (struct imports *)((char *)mod + page_size);
2184 expect = GetProcAddress( GetModuleHandleA( data.module ), data.function.name );
2185 ok( (void *)ptr->thunks[0].u1.Function == expect, "thunk %p instead of %p for %s.%s\n",
2186 (void *)ptr->thunks[0].u1.Function, expect, data.module, data.function.name );
2187 ok( ptr->tls_index < 32 || broken(ptr->tls_index == 9999), /* before vista */
2188 "wrong tls index %d\n", ptr->tls_index );
2189 if (ptr->tls_index != 9999)
2191 str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index];
2192 ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str );
2194 FreeLibrary( mod );
2195 break;
2196 case 1: /* load with DONT_RESOLVE_DLL_REFERENCES doesn't resolve imports */
2197 mod = LoadLibraryExA( dll_name, 0, DONT_RESOLVE_DLL_REFERENCES );
2198 ok( mod != NULL, "failed to load err %u\n", GetLastError() );
2199 if (!mod) break;
2200 ptr = (struct imports *)((char *)mod + page_size);
2201 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
2202 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
2203 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
2205 mod2 = LoadLibraryA( dll_name );
2206 ok( mod2 == mod, "loaded twice %p / %p\n", mod, mod2 );
2207 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
2208 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
2209 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
2210 FreeLibrary( mod2 );
2211 FreeLibrary( mod );
2212 break;
2213 case 2: /* load without IMAGE_FILE_DLL doesn't resolve imports */
2214 mod = LoadLibraryA( dll_name );
2215 ok( mod != NULL, "failed to load err %u\n", GetLastError() );
2216 if (!mod) break;
2217 ptr = (struct imports *)((char *)mod + page_size);
2218 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
2219 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
2220 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
2221 FreeLibrary( mod );
2222 break;
2224 DeleteFileA( dll_name );
2225 #undef DATA_RVA
2229 #define MAX_COUNT 10
2230 static HANDLE attached_thread[MAX_COUNT];
2231 static DWORD attached_thread_count;
2232 static HANDLE event, mutex, semaphore;
2233 static HANDLE stop_event, loader_lock_event, peb_lock_event, heap_lock_event, cs_lock_event, ack_event;
2234 static CRITICAL_SECTION cs_lock;
2235 static int test_dll_phase, inside_loader_lock, inside_peb_lock, inside_heap_lock, inside_cs_lock;
2236 static LONG fls_callback_count;
2238 static DWORD WINAPI mutex_thread_proc(void *param)
2240 HANDLE wait_list[5];
2241 DWORD ret;
2243 ret = WaitForSingleObject(mutex, 0);
2244 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2246 SetEvent(param);
2248 wait_list[0] = stop_event;
2249 wait_list[1] = loader_lock_event;
2250 wait_list[2] = peb_lock_event;
2251 wait_list[3] = heap_lock_event;
2252 wait_list[4] = cs_lock_event;
2254 trace("%04x: mutex_thread_proc: starting\n", GetCurrentThreadId());
2255 while (1)
2257 ret = WaitForMultipleObjects(ARRAY_SIZE(wait_list), wait_list, FALSE, 50);
2258 if (ret == WAIT_OBJECT_0) break;
2259 else if (ret == WAIT_OBJECT_0 + 1)
2261 ULONG_PTR loader_lock_magic;
2262 trace("%04x: mutex_thread_proc: Entering loader lock\n", GetCurrentThreadId());
2263 ret = pLdrLockLoaderLock(0, NULL, &loader_lock_magic);
2264 ok(!ret, "LdrLockLoaderLock error %#x\n", ret);
2265 inside_loader_lock++;
2266 SetEvent(ack_event);
2268 else if (ret == WAIT_OBJECT_0 + 2)
2270 trace("%04x: mutex_thread_proc: Entering PEB lock\n", GetCurrentThreadId());
2271 pRtlAcquirePebLock();
2272 inside_peb_lock++;
2273 SetEvent(ack_event);
2275 else if (ret == WAIT_OBJECT_0 + 3)
2277 trace("%04x: mutex_thread_proc: Entering heap lock\n", GetCurrentThreadId());
2278 HeapLock(GetProcessHeap());
2279 inside_heap_lock++;
2280 SetEvent(ack_event);
2282 else if (ret == WAIT_OBJECT_0 + 4)
2284 trace("%04x: mutex_thread_proc: Entering CS lock\n", GetCurrentThreadId());
2285 EnterCriticalSection(&cs_lock);
2286 inside_cs_lock++;
2287 SetEvent(ack_event);
2291 trace("%04x: mutex_thread_proc: exiting\n", GetCurrentThreadId());
2292 return 196;
2295 static DWORD WINAPI semaphore_thread_proc(void *param)
2297 DWORD ret;
2299 ret = WaitForSingleObject(semaphore, 0);
2300 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2302 SetEvent(param);
2304 while (1)
2306 if (winetest_debug > 1)
2307 trace("%04x: semaphore_thread_proc: still alive\n", GetCurrentThreadId());
2308 if (WaitForSingleObject(stop_event, 50) != WAIT_TIMEOUT) break;
2311 trace("%04x: semaphore_thread_proc: exiting\n", GetCurrentThreadId());
2312 return 196;
2315 static DWORD WINAPI noop_thread_proc(void *param)
2317 if (param)
2319 LONG *noop_thread_started = param;
2320 InterlockedIncrement(noop_thread_started);
2323 trace("%04x: noop_thread_proc: exiting\n", GetCurrentThreadId());
2324 return 195;
2327 static VOID WINAPI fls_callback(PVOID lpFlsData)
2329 ok(lpFlsData == (void*) 0x31415, "lpFlsData is %p, expected %p\n", lpFlsData, (void*) 0x31415);
2330 InterlockedIncrement(&fls_callback_count);
2333 static LIST_ENTRY *fls_list_head;
2335 static unsigned int check_linked_list(const LIST_ENTRY *le, const LIST_ENTRY *search_entry, unsigned int *index_found)
2337 unsigned int count = 0;
2338 LIST_ENTRY *entry;
2340 *index_found = ~0;
2342 for (entry = le->Flink; entry != le; entry = entry->Flink)
2344 if (entry == search_entry)
2346 ok(*index_found == ~0, "Duplicate list entry.\n");
2347 *index_found = count;
2349 ++count;
2351 return count;
2354 static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param)
2356 static LONG noop_thread_started;
2357 static DWORD fls_index = FLS_OUT_OF_INDEXES, fls_index2 = FLS_OUT_OF_INDEXES;
2358 static int fls_count = 0;
2359 static int thread_detach_count = 0;
2360 static int thread_count;
2361 DWORD ret;
2363 ok(!inside_loader_lock, "inside_loader_lock should not be set\n");
2364 ok(!inside_peb_lock, "inside_peb_lock should not be set\n");
2366 switch (reason)
2368 case DLL_PROCESS_ATTACH:
2369 trace("dll: %p, DLL_PROCESS_ATTACH, %p\n", hinst, param);
2371 ret = pRtlDllShutdownInProgress();
2372 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2374 /* Set up the FLS slot, if FLS is available */
2375 if (pFlsGetValue)
2377 void* value;
2378 BOOL bret;
2379 ret = pFlsAlloc(&fls_callback);
2380 ok(ret != FLS_OUT_OF_INDEXES, "FlsAlloc returned %d\n", ret);
2381 fls_index = ret;
2382 SetLastError(0xdeadbeef);
2383 value = pFlsGetValue(fls_index);
2384 ok(!value, "FlsGetValue returned %p, expected NULL\n", value);
2385 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
2386 bret = pFlsSetValue(fls_index, (void*) 0x31415);
2387 ok(bret, "FlsSetValue failed\n");
2388 fls_count++;
2390 fls_index2 = pFlsAlloc(&fls_callback);
2391 ok(fls_index2 != FLS_OUT_OF_INDEXES, "FlsAlloc returned %d\n", ret);
2393 ++thread_count;
2394 break;
2395 case DLL_PROCESS_DETACH:
2397 DWORD code, expected_code, i;
2398 HANDLE handle, process;
2399 void *addr;
2400 SIZE_T size;
2401 LARGE_INTEGER offset;
2402 DEBUG_EVENT de;
2404 trace("dll: %p, DLL_PROCESS_DETACH, %p\n", hinst, param);
2406 if (test_dll_phase == 4 || test_dll_phase == 5)
2408 ok(0, "dll_entry_point(DLL_PROCESS_DETACH) should not be called\n");
2409 break;
2412 /* The process should already deadlock at this point */
2413 if (test_dll_phase == 6)
2415 /* In reality, code below never gets executed, probably some other
2416 * code tries to access process heap and deadlocks earlier, even XP
2417 * doesn't call the DLL entry point on process detach either.
2419 HeapLock(GetProcessHeap());
2420 todo_wine
2421 ok(0, "dll_entry_point: process should already deadlock\n");
2422 break;
2424 else if (test_dll_phase == 7)
2426 EnterCriticalSection(&cs_lock);
2429 if (test_dll_phase == 0 || test_dll_phase == 1 || test_dll_phase == 3 || test_dll_phase == 7)
2430 ok(param != NULL, "dll: param %p\n", param);
2431 else
2432 ok(!param, "dll: param %p\n", param);
2434 if (test_dll_phase == 0 || test_dll_phase == 1) expected_code = 195;
2435 else if (test_dll_phase == 3) expected_code = 196;
2436 else if (test_dll_phase == 7) expected_code = 199;
2437 else expected_code = STILL_ACTIVE;
2439 if (test_dll_phase == 3)
2441 ret = pRtlDllShutdownInProgress();
2442 ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
2444 else
2446 ret = pRtlDllShutdownInProgress();
2448 /* FIXME: remove once Wine is fixed */
2449 todo_wine_if (!(expected_code == STILL_ACTIVE || expected_code == 196))
2450 ok(!ret || broken(ret) /* before Vista */, "RtlDllShutdownInProgress returned %d\n", ret);
2453 /* In the case that the process is terminating, FLS slots should still be accessible, but
2454 * the callback should be already run for this thread and the contents already NULL.
2455 * Note that this is broken for Win2k3, which runs the callbacks *after* the DLL entry
2456 * point has already run.
2458 if (param && pFlsGetValue)
2460 void* value;
2461 SetLastError(0xdeadbeef);
2462 value = pFlsGetValue(fls_index);
2463 ok(broken(value == (void*) 0x31415) || /* Win2k3 */
2464 value == NULL, "FlsGetValue returned %p, expected NULL\n", value);
2465 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
2466 ok(broken(fls_callback_count == thread_detach_count) || /* Win2k3 */
2467 fls_callback_count == thread_detach_count + 1,
2468 "wrong FLS callback count %d, expected %d\n", fls_callback_count, thread_detach_count + 1);
2470 if (pFlsFree)
2472 BOOL ret;
2473 /* Call FlsFree now and run the remaining callbacks from uncleanly terminated threads */
2474 ret = pFlsFree(fls_index);
2475 ok(ret, "FlsFree failed with error %u\n", GetLastError());
2476 fls_index = FLS_OUT_OF_INDEXES;
2477 ok(fls_callback_count == fls_count,
2478 "wrong FLS callback count %d, expected %d\n", fls_callback_count, fls_count);
2481 ok(attached_thread_count >= 2, "attached thread count should be >= 2\n");
2483 for (i = 0; i < attached_thread_count; i++)
2485 /* Calling GetExitCodeThread() without waiting for thread termination
2486 * leads to different results due to a race condition.
2488 if (expected_code != STILL_ACTIVE)
2490 ret = WaitForSingleObject(attached_thread[i], 1000);
2491 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2493 ret = GetExitCodeThread(attached_thread[i], &code);
2494 trace("dll: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
2495 ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
2496 ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code);
2499 ret = WaitForSingleObject(event, 0);
2500 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2502 ret = WaitForSingleObject(mutex, 0);
2503 if (expected_code == STILL_ACTIVE)
2504 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2505 else
2506 ok(ret == WAIT_ABANDONED, "expected WAIT_ABANDONED, got %#x\n", ret);
2508 /* semaphore is not abandoned on thread termination */
2509 ret = WaitForSingleObject(semaphore, 0);
2510 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2512 if (expected_code == STILL_ACTIVE)
2514 ret = WaitForSingleObject(attached_thread[0], 0);
2515 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2516 ret = WaitForSingleObject(attached_thread[1], 0);
2517 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2519 else
2521 ret = WaitForSingleObject(attached_thread[0], 0);
2522 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2523 ret = WaitForSingleObject(attached_thread[1], 0);
2524 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2527 /* win7 doesn't allow creating a thread during process shutdown but
2528 * earlier Windows versions allow it.
2530 noop_thread_started = 0;
2531 SetLastError(0xdeadbeef);
2532 handle = CreateThread(NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
2533 if (param)
2535 ok(!handle || broken(handle != 0) /* before win7 */, "CreateThread should fail\n");
2536 if (!handle)
2537 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2538 else
2540 ret = WaitForSingleObject(handle, 1000);
2541 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2542 CloseHandle(handle);
2545 else
2547 ok(handle != 0, "CreateThread error %d\n", GetLastError());
2548 ret = WaitForSingleObject(handle, 1000);
2549 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2550 ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n");
2551 CloseHandle(handle);
2554 SetLastError(0xdeadbeef);
2555 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, GetCurrentProcessId());
2556 ok(process != NULL, "OpenProcess error %d\n", GetLastError());
2558 noop_thread_started = 0;
2559 SetLastError(0xdeadbeef);
2560 handle = CreateRemoteThread(process, NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
2561 if (param)
2563 ok(!handle || broken(handle != 0) /* before win7 */, "CreateRemoteThread should fail\n");
2564 if (!handle)
2565 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2566 else
2568 ret = WaitForSingleObject(handle, 1000);
2569 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2570 CloseHandle(handle);
2573 else
2575 ok(handle != 0, "CreateRemoteThread error %d\n", GetLastError());
2576 ret = WaitForSingleObject(handle, 1000);
2577 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2578 ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n");
2579 CloseHandle(handle);
2582 SetLastError(0xdeadbeef);
2583 handle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
2584 ok(handle != 0, "CreateFileMapping error %d\n", GetLastError());
2586 offset.u.LowPart = 0;
2587 offset.u.HighPart = 0;
2588 addr = NULL;
2589 size = 0;
2590 ret = pNtMapViewOfSection(handle, process, &addr, 0, 0, &offset,
2591 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
2592 ok(ret == STATUS_SUCCESS, "NtMapViewOfSection error %#x\n", ret);
2593 ret = pNtUnmapViewOfSection(process, addr);
2594 ok(ret == STATUS_SUCCESS, "NtUnmapViewOfSection error %#x\n", ret);
2596 CloseHandle(handle);
2597 CloseHandle(process);
2599 handle = GetModuleHandleA("winver.exe");
2600 ok(!handle, "winver.exe shouldn't be loaded yet\n");
2601 SetLastError(0xdeadbeef);
2602 handle = LoadLibraryA("winver.exe");
2603 ok(handle != 0, "LoadLibrary error %d\n", GetLastError());
2604 SetLastError(0xdeadbeef);
2605 ret = FreeLibrary(handle);
2606 ok(ret, "FreeLibrary error %d\n", GetLastError());
2607 handle = GetModuleHandleA("winver.exe");
2608 if (param)
2609 ok(handle != 0, "winver.exe should not be unloaded\n");
2610 else
2611 todo_wine
2612 ok(!handle || broken(handle != 0) /* before win7 */, "winver.exe should be unloaded\n");
2614 SetLastError(0xdeadbeef);
2615 ret = WaitForDebugEvent(&de, 0);
2616 ok(!ret, "WaitForDebugEvent should fail\n");
2617 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
2619 SetLastError(0xdeadbeef);
2620 ret = DebugActiveProcess(GetCurrentProcessId());
2621 ok(!ret, "DebugActiveProcess should fail\n");
2622 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2624 SetLastError(0xdeadbeef);
2625 ret = WaitForDebugEvent(&de, 0);
2626 ok(!ret, "WaitForDebugEvent should fail\n");
2627 ok(GetLastError() == ERROR_SEM_TIMEOUT, "expected ERROR_SEM_TIMEOUT, got %d\n", GetLastError());
2629 if (test_dll_phase == 2)
2631 trace("dll: call ExitProcess()\n");
2632 *child_failures = winetest_get_failures();
2633 ExitProcess(197);
2635 trace("dll: %p, DLL_PROCESS_DETACH, %p => DONE\n", hinst, param);
2636 break;
2638 case DLL_THREAD_ATTACH:
2639 trace("dll: %p, DLL_THREAD_ATTACH, %p\n", hinst, param);
2641 ++thread_count;
2643 ret = pRtlDllShutdownInProgress();
2644 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2646 if (attached_thread_count < MAX_COUNT)
2648 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &attached_thread[attached_thread_count],
2649 0, TRUE, DUPLICATE_SAME_ACCESS);
2650 attached_thread_count++;
2653 /* Make sure the FLS slot is empty, if FLS is available */
2654 if (pFlsGetValue)
2656 void* value;
2657 BOOL ret;
2658 SetLastError(0xdeadbeef);
2659 value = pFlsGetValue(fls_index);
2660 ok(!value, "FlsGetValue returned %p, expected NULL\n", value);
2661 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
2662 ret = pFlsSetValue(fls_index, (void*) 0x31415);
2663 ok(ret, "FlsSetValue failed\n");
2664 fls_count++;
2667 break;
2668 case DLL_THREAD_DETACH:
2669 trace("dll: %p, DLL_THREAD_DETACH, %p\n", hinst, param);
2670 --thread_count;
2671 thread_detach_count++;
2673 ret = pRtlDllShutdownInProgress();
2674 /* win7 doesn't allow creating a thread during process shutdown but
2675 * earlier Windows versions allow it. In that case DLL_THREAD_DETACH is
2676 * sent on thread exit, but DLL_THREAD_ATTACH is never received.
2678 if (noop_thread_started)
2679 ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
2680 else
2681 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2683 /* FLS data should already be destroyed, if FLS is available.
2684 * Note that this is broken for Win2k3, which runs the callbacks *after* the DLL entry
2685 * point has already run.
2687 if (pFlsGetValue && fls_index != FLS_OUT_OF_INDEXES)
2689 unsigned int index, count;
2690 void* value;
2691 BOOL bret;
2693 SetLastError(0xdeadbeef);
2694 value = pFlsGetValue(fls_index);
2695 ok(broken(value == (void*) 0x31415) || /* Win2k3 */
2696 !value, "FlsGetValue returned %p, expected NULL\n", value);
2697 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
2699 bret = pFlsSetValue(fls_index2, (void*) 0x31415);
2700 ok(bret, "FlsSetValue failed\n");
2702 if (fls_list_head)
2704 count = check_linked_list(fls_list_head, &NtCurrentTeb()->FlsSlots->fls_list_entry, &index);
2705 ok(count <= thread_count, "Got unexpected count %u, thread_count %u.\n", count, thread_count);
2706 ok(index == ~0, "Got unexpected index %u.\n", index);
2710 break;
2711 default:
2712 trace("dll: %p, %d, %p\n", hinst, reason, param);
2713 break;
2716 *child_failures = winetest_get_failures();
2718 return TRUE;
2721 static void child_process(const char *dll_name, DWORD target_offset)
2723 void *target;
2724 DWORD ret, dummy, i, code, expected_code;
2725 HANDLE file, thread, process;
2726 HMODULE hmod;
2727 struct PROCESS_BASIC_INFORMATION_PRIVATE pbi;
2728 DWORD_PTR affinity;
2730 trace("phase %d: writing %p at %#x\n", test_dll_phase, dll_entry_point, target_offset);
2732 if (pFlsAlloc)
2734 fls_list_head = NtCurrentTeb()->Peb->FlsListHead.Flink ? &NtCurrentTeb()->Peb->FlsListHead
2735 : NtCurrentTeb()->FlsSlots->fls_list_entry.Flink;
2738 SetLastError(0xdeadbeef);
2739 mutex = CreateMutexW(NULL, FALSE, NULL);
2740 ok(mutex != 0, "CreateMutex error %d\n", GetLastError());
2742 SetLastError(0xdeadbeef);
2743 semaphore = CreateSemaphoreW(NULL, 1, 1, NULL);
2744 ok(semaphore != 0, "CreateSemaphore error %d\n", GetLastError());
2746 SetLastError(0xdeadbeef);
2747 event = CreateEventW(NULL, TRUE, FALSE, NULL);
2748 ok(event != 0, "CreateEvent error %d\n", GetLastError());
2750 SetLastError(0xdeadbeef);
2751 loader_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2752 ok(loader_lock_event != 0, "CreateEvent error %d\n", GetLastError());
2754 SetLastError(0xdeadbeef);
2755 peb_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2756 ok(peb_lock_event != 0, "CreateEvent error %d\n", GetLastError());
2758 SetLastError(0xdeadbeef);
2759 heap_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2760 ok(heap_lock_event != 0, "CreateEvent error %d\n", GetLastError());
2762 InitializeCriticalSection(&cs_lock);
2763 SetLastError(0xdeadbeef);
2764 cs_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2765 ok(cs_lock_event != 0, "CreateEvent error %d\n", GetLastError());
2767 SetLastError(0xdeadbeef);
2768 ack_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2769 ok(ack_event != 0, "CreateEvent error %d\n", GetLastError());
2771 file = CreateFileA(dll_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2772 if (file == INVALID_HANDLE_VALUE)
2774 ok(0, "could not open %s\n", dll_name);
2775 return;
2777 SetFilePointer(file, target_offset, NULL, FILE_BEGIN);
2778 SetLastError(0xdeadbeef);
2779 target = dll_entry_point;
2780 ret = WriteFile(file, &target, sizeof(target), &dummy, NULL);
2781 ok(ret, "WriteFile error %d\n", GetLastError());
2782 CloseHandle(file);
2784 SetLastError(0xdeadbeef);
2785 hmod = LoadLibraryA(dll_name);
2786 ok(hmod != 0, "LoadLibrary error %d\n", GetLastError());
2788 SetLastError(0xdeadbeef);
2789 stop_event = CreateEventW(NULL, TRUE, FALSE, NULL);
2790 ok(stop_event != 0, "CreateEvent error %d\n", GetLastError());
2792 SetLastError(0xdeadbeef);
2793 thread = CreateThread(NULL, 0, mutex_thread_proc, event, 0, &dummy);
2794 ok(thread != 0, "CreateThread error %d\n", GetLastError());
2795 WaitForSingleObject(event, 3000);
2796 CloseHandle(thread);
2798 ResetEvent(event);
2800 SetLastError(0xdeadbeef);
2801 thread = CreateThread(NULL, 0, semaphore_thread_proc, event, 0, &dummy);
2802 ok(thread != 0, "CreateThread error %d\n", GetLastError());
2803 WaitForSingleObject(event, 3000);
2804 CloseHandle(thread);
2806 ResetEvent(event);
2807 Sleep(100);
2809 ok(attached_thread_count == 2, "attached thread count should be 2\n");
2810 for (i = 0; i < attached_thread_count; i++)
2812 ret = GetExitCodeThread(attached_thread[i], &code);
2813 trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
2814 ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
2815 ok(code == STILL_ACTIVE, "expected thread exit code STILL_ACTIVE, got %u\n", code);
2818 ret = WaitForSingleObject(attached_thread[0], 0);
2819 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2820 ret = WaitForSingleObject(attached_thread[1], 0);
2821 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2823 ret = WaitForSingleObject(event, 0);
2824 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2825 ret = WaitForSingleObject(mutex, 0);
2826 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2827 ret = WaitForSingleObject(semaphore, 0);
2828 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2830 ret = pRtlDllShutdownInProgress();
2831 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2833 SetLastError(0xdeadbeef);
2834 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, GetCurrentProcessId());
2835 ok(process != NULL, "OpenProcess error %d\n", GetLastError());
2837 SetLastError(0xdeadbeef);
2838 ret = TerminateProcess(0, 195);
2839 ok(!ret, "TerminateProcess(0) should fail\n");
2840 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
2842 Sleep(100);
2844 affinity = 1;
2845 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
2846 ok(!ret, "NtSetInformationProcess error %#x\n", ret);
2848 switch (test_dll_phase)
2850 case 0:
2851 ret = pRtlDllShutdownInProgress();
2852 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2854 trace("call NtTerminateProcess(0, 195)\n");
2855 ret = pNtTerminateProcess(0, 195);
2856 ok(!ret, "NtTerminateProcess error %#x\n", ret);
2858 memset(&pbi, 0, sizeof(pbi));
2859 ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
2860 ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
2861 ok(pbi.ExitStatus == STILL_ACTIVE || pbi.ExitStatus == 195,
2862 "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus);
2863 affinity = 1;
2864 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
2865 ok(!ret, "NtSetInformationProcess error %#x\n", ret);
2867 ret = pRtlDllShutdownInProgress();
2868 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2870 hmod = GetModuleHandleA(dll_name);
2871 ok(hmod != 0, "DLL should not be unloaded\n");
2873 SetLastError(0xdeadbeef);
2874 thread = CreateThread(NULL, 0, noop_thread_proc, &dummy, 0, &ret);
2875 ok(!thread || broken(thread != 0) /* before win7 */, "CreateThread should fail\n");
2876 if (!thread)
2877 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2878 else
2880 ret = WaitForSingleObject(thread, 1000);
2881 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2882 CloseHandle(thread);
2885 trace("call LdrShutdownProcess()\n");
2886 pLdrShutdownProcess();
2888 ret = pRtlDllShutdownInProgress();
2889 ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
2891 hmod = GetModuleHandleA(dll_name);
2892 ok(hmod != 0, "DLL should not be unloaded\n");
2894 memset(&pbi, 0, sizeof(pbi));
2895 ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
2896 ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
2897 ok(pbi.ExitStatus == STILL_ACTIVE || pbi.ExitStatus == 195,
2898 "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus);
2899 affinity = 1;
2900 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
2901 ok(!ret, "NtSetInformationProcess error %#x\n", ret);
2902 break;
2904 case 1: /* normal ExitProcess */
2905 ret = pRtlDllShutdownInProgress();
2906 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2907 break;
2909 case 2: /* ExitProcess will be called by the PROCESS_DETACH handler */
2910 ret = pRtlDllShutdownInProgress();
2911 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2913 trace("call FreeLibrary(%p)\n", hmod);
2914 SetLastError(0xdeadbeef);
2915 ret = FreeLibrary(hmod);
2916 ok(ret, "FreeLibrary error %d\n", GetLastError());
2917 hmod = GetModuleHandleA(dll_name);
2918 ok(!hmod, "DLL should be unloaded\n");
2920 if (test_dll_phase == 2)
2921 ok(0, "FreeLibrary+ExitProcess should never return\n");
2923 ret = pRtlDllShutdownInProgress();
2924 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2926 break;
2928 case 3:
2929 trace("signalling thread exit\n");
2930 SetEvent(stop_event);
2931 break;
2933 case 4:
2934 trace("setting loader_lock_event\n");
2935 SetEvent(loader_lock_event);
2936 WaitForSingleObject(ack_event, 1000);
2937 ok(inside_loader_lock != 0, "inside_loader_lock is not set\n");
2939 /* calling NtTerminateProcess should not cause a deadlock */
2940 trace("call NtTerminateProcess(0, 198)\n");
2941 ret = pNtTerminateProcess(0, 198);
2942 ok(!ret, "NtTerminateProcess error %#x\n", ret);
2944 *child_failures = winetest_get_failures();
2946 /* Windows fails to release loader lock acquired from another thread,
2947 * so the LdrUnlockLoaderLock call fails here and ExitProcess deadlocks
2948 * later on, so NtTerminateProcess is used instead.
2950 trace("call NtTerminateProcess(GetCurrentProcess(), 198)\n");
2951 pNtTerminateProcess(GetCurrentProcess(), 198);
2952 ok(0, "NtTerminateProcess should not return\n");
2953 break;
2955 case 5:
2956 trace("setting peb_lock_event\n");
2957 SetEvent(peb_lock_event);
2958 WaitForSingleObject(ack_event, 1000);
2959 ok(inside_peb_lock != 0, "inside_peb_lock is not set\n");
2961 *child_failures = winetest_get_failures();
2963 /* calling ExitProcess should cause a deadlock */
2964 trace("call ExitProcess(198)\n");
2965 ExitProcess(198);
2966 ok(0, "ExitProcess should not return\n");
2967 break;
2969 case 6:
2970 trace("setting heap_lock_event\n");
2971 SetEvent(heap_lock_event);
2972 WaitForSingleObject(ack_event, 1000);
2973 ok(inside_heap_lock != 0, "inside_heap_lock is not set\n");
2975 *child_failures = winetest_get_failures();
2977 /* calling ExitProcess should cause a deadlock */
2978 trace("call ExitProcess(1)\n");
2979 ExitProcess(1);
2980 ok(0, "ExitProcess should not return\n");
2981 break;
2983 case 7:
2984 trace("setting cs_lock_event\n");
2985 SetEvent(cs_lock_event);
2986 WaitForSingleObject(ack_event, 1000);
2987 ok(inside_cs_lock != 0, "inside_cs_lock is not set\n");
2989 *child_failures = winetest_get_failures();
2991 /* calling ExitProcess should not cause a deadlock */
2992 trace("call ExitProcess(199)\n");
2993 ExitProcess(199);
2994 ok(0, "ExitProcess should not return\n");
2995 break;
2997 default:
2998 assert(0);
2999 break;
3002 if (test_dll_phase == 0) expected_code = 195;
3003 else if (test_dll_phase == 3) expected_code = 196;
3004 else if (test_dll_phase == 4) expected_code = 198;
3005 else expected_code = STILL_ACTIVE;
3007 if (expected_code == STILL_ACTIVE)
3009 ret = WaitForSingleObject(attached_thread[0], 100);
3010 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
3011 ret = WaitForSingleObject(attached_thread[1], 100);
3012 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
3014 else
3016 ret = WaitForSingleObject(attached_thread[0], 2000);
3017 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
3018 ret = WaitForSingleObject(attached_thread[1], 2000);
3019 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
3022 for (i = 0; i < attached_thread_count; i++)
3024 ret = GetExitCodeThread(attached_thread[i], &code);
3025 trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
3026 ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
3027 ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code);
3030 *child_failures = winetest_get_failures();
3032 trace("call ExitProcess(195)\n");
3033 ExitProcess(195);
3036 static void test_ExitProcess(void)
3038 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
3039 #include "pshpack1.h"
3040 #ifdef __x86_64__
3041 static struct section_data
3043 BYTE mov_rax[2];
3044 void *target;
3045 BYTE jmp_rax[2];
3046 } section_data = { { 0x48,0xb8 }, dll_entry_point, { 0xff,0xe0 } };
3047 #elif defined(__i386__)
3048 static struct section_data
3050 BYTE mov_eax;
3051 void *target;
3052 BYTE jmp_eax[2];
3053 } section_data = { 0xb8, dll_entry_point, { 0xff,0xe0 } };
3054 #elif defined(__aarch64__)
3055 static struct section_data
3057 DWORD ldr; /* ldr x0,target */
3058 DWORD br; /* br x0 */
3059 void *target;
3060 } section_data = { 0x58000040, 0xd61f0000, dll_entry_point };
3061 #endif
3062 #include "poppack.h"
3063 DWORD dummy, file_align;
3064 HANDLE file, thread, process, hmap, hmap_dup;
3065 char temp_path[MAX_PATH], dll_name[MAX_PATH], cmdline[MAX_PATH * 2];
3066 DWORD ret, target_offset, old_prot;
3067 char **argv, buf[256];
3068 PROCESS_INFORMATION pi;
3069 STARTUPINFOA si = { sizeof(si) };
3070 CONTEXT ctx;
3071 struct PROCESS_BASIC_INFORMATION_PRIVATE pbi;
3072 MEMORY_BASIC_INFORMATION mbi;
3073 DWORD_PTR affinity;
3074 void *addr;
3075 LARGE_INTEGER offset;
3076 SIZE_T size;
3077 IMAGE_NT_HEADERS nt_header;
3079 if (!pRtlDllShutdownInProgress)
3081 win_skip("RtlDllShutdownInProgress is not available on this platform (XP+)\n");
3082 return;
3084 if (!pNtQueryInformationProcess || !pNtSetInformationProcess)
3086 win_skip("NtQueryInformationProcess/NtSetInformationProcess are not available on this platform\n");
3087 return;
3089 if (!pNtAllocateVirtualMemory || !pNtFreeVirtualMemory)
3091 win_skip("NtAllocateVirtualMemory/NtFreeVirtualMemory are not available on this platform\n");
3092 return;
3095 /* prevent displaying of the "Unable to load this DLL" message box */
3096 SetErrorMode(SEM_FAILCRITICALERRORS);
3098 GetTempPathA(MAX_PATH, temp_path);
3099 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
3101 /*trace("creating %s\n", dll_name);*/
3102 file = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
3103 if (file == INVALID_HANDLE_VALUE)
3105 ok(0, "could not create %s\n", dll_name);
3106 return;
3109 SetLastError(0xdeadbeef);
3110 ret = WriteFile(file, &dos_header, sizeof(dos_header), &dummy, NULL);
3111 ok(ret, "WriteFile error %d\n", GetLastError());
3113 nt_header = nt_header_template;
3114 nt_header.FileHeader.NumberOfSections = 1;
3115 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
3116 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED;
3118 nt_header.OptionalHeader.AddressOfEntryPoint = 0x1000;
3119 nt_header.OptionalHeader.SectionAlignment = 0x1000;
3120 nt_header.OptionalHeader.FileAlignment = 0x200;
3121 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000;
3122 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
3123 SetLastError(0xdeadbeef);
3124 ret = WriteFile(file, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
3125 ok(ret, "WriteFile error %d\n", GetLastError());
3126 SetLastError(0xdeadbeef);
3127 ret = WriteFile(file, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
3128 ok(ret, "WriteFile error %d\n", GetLastError());
3130 section.SizeOfRawData = sizeof(section_data);
3131 section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
3132 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
3133 section.Misc.VirtualSize = sizeof(section_data);
3134 section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
3135 SetLastError(0xdeadbeef);
3136 ret = WriteFile(file, &section, sizeof(section), &dummy, NULL);
3137 ok(ret, "WriteFile error %d\n", GetLastError());
3139 file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
3140 assert(file_align < sizeof(filler));
3141 SetLastError(0xdeadbeef);
3142 ret = WriteFile(file, filler, file_align, &dummy, NULL);
3143 ok(ret, "WriteFile error %d\n", GetLastError());
3145 target_offset = SetFilePointer(file, 0, NULL, FILE_CURRENT) + FIELD_OFFSET(struct section_data, target);
3147 /* section data */
3148 SetLastError(0xdeadbeef);
3149 ret = WriteFile(file, &section_data, sizeof(section_data), &dummy, NULL);
3150 ok(ret, "WriteFile error %d\n", GetLastError());
3152 CloseHandle(file);
3154 winetest_get_mainargs(&argv);
3156 /* phase 0 */
3157 *child_failures = -1;
3158 sprintf(cmdline, "\"%s\" loader %s %u 0", argv[0], dll_name, target_offset);
3159 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3160 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
3161 ret = WaitForSingleObject(pi.hProcess, 10000);
3162 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3163 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
3164 GetExitCodeProcess(pi.hProcess, &ret);
3165 ok(ret == 195, "expected exit code 195, got %u\n", ret);
3166 if (*child_failures)
3168 trace("%d failures in child process\n", *child_failures);
3169 winetest_add_failures(*child_failures);
3171 CloseHandle(pi.hThread);
3172 CloseHandle(pi.hProcess);
3174 /* phase 1 */
3175 *child_failures = -1;
3176 sprintf(cmdline, "\"%s\" loader %s %u 1", argv[0], dll_name, target_offset);
3177 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3178 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
3179 ret = WaitForSingleObject(pi.hProcess, 10000);
3180 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3181 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
3182 GetExitCodeProcess(pi.hProcess, &ret);
3183 ok(ret == 195, "expected exit code 195, got %u\n", ret);
3184 if (*child_failures)
3186 trace("%d failures in child process\n", *child_failures);
3187 winetest_add_failures(*child_failures);
3189 CloseHandle(pi.hThread);
3190 CloseHandle(pi.hProcess);
3192 /* phase 2 */
3193 *child_failures = -1;
3194 sprintf(cmdline, "\"%s\" loader %s %u 2", argv[0], dll_name, target_offset);
3195 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3196 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
3197 ret = WaitForSingleObject(pi.hProcess, 10000);
3198 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3199 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
3200 GetExitCodeProcess(pi.hProcess, &ret);
3201 ok(ret == 197, "expected exit code 197, got %u\n", ret);
3202 if (*child_failures)
3204 trace("%d failures in child process\n", *child_failures);
3205 winetest_add_failures(*child_failures);
3207 CloseHandle(pi.hThread);
3208 CloseHandle(pi.hProcess);
3210 /* phase 3 */
3211 *child_failures = -1;
3212 sprintf(cmdline, "\"%s\" loader %s %u 3", argv[0], dll_name, target_offset);
3213 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3214 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
3215 ret = WaitForSingleObject(pi.hProcess, 10000);
3216 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3217 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
3218 GetExitCodeProcess(pi.hProcess, &ret);
3219 ok(ret == 195, "expected exit code 195, got %u\n", ret);
3220 if (*child_failures)
3222 trace("%d failures in child process\n", *child_failures);
3223 winetest_add_failures(*child_failures);
3225 CloseHandle(pi.hThread);
3226 CloseHandle(pi.hProcess);
3228 /* phase 4 */
3229 if (pLdrLockLoaderLock && pLdrUnlockLoaderLock)
3231 *child_failures = -1;
3232 sprintf(cmdline, "\"%s\" loader %s %u 4", argv[0], dll_name, target_offset);
3233 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3234 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
3235 ret = WaitForSingleObject(pi.hProcess, 10000);
3236 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3237 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
3238 GetExitCodeProcess(pi.hProcess, &ret);
3239 ok(ret == 198, "expected exit code 198, got %u\n", ret);
3240 if (*child_failures)
3242 trace("%d failures in child process\n", *child_failures);
3243 winetest_add_failures(*child_failures);
3245 CloseHandle(pi.hThread);
3246 CloseHandle(pi.hProcess);
3248 else
3249 win_skip("LdrLockLoaderLock/LdrUnlockLoaderLock are not available on this platform\n");
3251 /* phase 5 */
3252 if (pRtlAcquirePebLock && pRtlReleasePebLock)
3254 *child_failures = -1;
3255 sprintf(cmdline, "\"%s\" loader %s %u 5", argv[0], dll_name, target_offset);
3256 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3257 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
3258 ret = WaitForSingleObject(pi.hProcess, 5000);
3259 ok(ret == WAIT_TIMEOUT, "child process should fail to terminate\n");
3260 if (ret != WAIT_OBJECT_0)
3262 trace("terminating child process\n");
3263 TerminateProcess(pi.hProcess, 199);
3265 ret = WaitForSingleObject(pi.hProcess, 1000);
3266 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3267 GetExitCodeProcess(pi.hProcess, &ret);
3268 ok(ret == 199, "expected exit code 199, got %u\n", ret);
3269 if (*child_failures)
3271 trace("%d failures in child process\n", *child_failures);
3272 winetest_add_failures(*child_failures);
3274 CloseHandle(pi.hThread);
3275 CloseHandle(pi.hProcess);
3277 else
3278 win_skip("RtlAcquirePebLock/RtlReleasePebLock are not available on this platform\n");
3280 /* phase 6 */
3281 *child_failures = -1;
3282 sprintf(cmdline, "\"%s\" loader %s %u 6", argv[0], dll_name, target_offset);
3283 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3284 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
3285 ret = WaitForSingleObject(pi.hProcess, 5000);
3286 todo_wine
3287 ok(ret == WAIT_TIMEOUT || broken(ret == WAIT_OBJECT_0) /* XP */, "child process should fail to terminate\n");
3288 if (ret != WAIT_OBJECT_0)
3290 trace("terminating child process\n");
3291 TerminateProcess(pi.hProcess, 201);
3293 ret = WaitForSingleObject(pi.hProcess, 1000);
3294 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3295 GetExitCodeProcess(pi.hProcess, &ret);
3296 todo_wine
3297 ok(ret == 201 || broken(ret == 1) /* XP */, "expected exit code 201, got %u\n", ret);
3298 if (*child_failures)
3300 trace("%d failures in child process\n", *child_failures);
3301 winetest_add_failures(*child_failures);
3303 CloseHandle(pi.hThread);
3304 CloseHandle(pi.hProcess);
3306 /* phase 7 */
3307 *child_failures = -1;
3308 sprintf(cmdline, "\"%s\" loader %s %u 7", argv[0], dll_name, target_offset);
3309 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3310 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
3311 ret = WaitForSingleObject(pi.hProcess, 5000);
3312 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3313 if (ret != WAIT_OBJECT_0)
3315 trace("terminating child process\n");
3316 TerminateProcess(pi.hProcess, 199);
3318 ret = WaitForSingleObject(pi.hProcess, 1000);
3319 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3320 GetExitCodeProcess(pi.hProcess, &ret);
3321 ok(ret == 199, "expected exit code 199, got %u\n", ret);
3322 if (*child_failures)
3324 trace("%d failures in child process\n", *child_failures);
3325 winetest_add_failures(*child_failures);
3327 CloseHandle(pi.hThread);
3328 CloseHandle(pi.hProcess);
3330 /* test remote process termination */
3331 SetLastError(0xdeadbeef);
3332 ret = CreateProcessA(argv[0], NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
3333 ok(ret, "CreateProcess(%s) error %d\n", argv[0], GetLastError());
3335 SetLastError(0xdeadbeef);
3336 addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
3337 ok(addr != NULL, "VirtualAllocEx error %d\n", GetLastError());
3338 SetLastError(0xdeadbeef);
3339 ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READONLY, &old_prot);
3340 ok(ret, "VirtualProtectEx error %d\n", GetLastError());
3341 ok(old_prot == PAGE_READWRITE, "expected PAGE_READWRITE, got %#x\n", old_prot);
3342 SetLastError(0xdeadbeef);
3343 size = VirtualQueryEx(pi.hProcess, NULL, &mbi, sizeof(mbi));
3344 ok(size == sizeof(mbi), "VirtualQueryEx error %d\n", GetLastError());
3346 SetLastError(0xdeadbeef);
3347 ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size);
3348 ok(ret, "ReadProcessMemory error %d\n", GetLastError());
3349 ok(size == 4, "expected 4, got %lu\n", size);
3351 SetLastError(0xdeadbeef);
3352 hmap = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
3353 ok(hmap != 0, "CreateFileMapping error %d\n", GetLastError());
3355 SetLastError(0xdeadbeef);
3356 ret = DuplicateHandle(GetCurrentProcess(), hmap, pi.hProcess, &hmap_dup,
3357 0, FALSE, DUPLICATE_SAME_ACCESS);
3358 ok(ret, "DuplicateHandle error %d\n", GetLastError());
3360 offset.u.LowPart = 0;
3361 offset.u.HighPart = 0;
3362 addr = NULL;
3363 size = 0;
3364 ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset,
3365 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
3366 ok(!ret, "NtMapViewOfSection error %#x\n", ret);
3367 ret = pNtUnmapViewOfSection(pi.hProcess, addr);
3368 ok(!ret, "NtUnmapViewOfSection error %#x\n", ret);
3370 SetLastError(0xdeadbeef);
3371 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
3372 ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError());
3373 SetLastError(0xdeadbeef);
3374 ctx.ContextFlags = CONTEXT_INTEGER;
3375 ret = GetThreadContext(thread, &ctx);
3376 ok(ret, "GetThreadContext error %d\n", GetLastError());
3377 SetLastError(0xdeadbeef);
3378 ctx.ContextFlags = CONTEXT_INTEGER;
3379 ret = SetThreadContext(thread, &ctx);
3380 ok(ret, "SetThreadContext error %d\n", GetLastError());
3381 SetLastError(0xdeadbeef);
3382 ret = SetThreadPriority(thread, 0);
3383 ok(ret, "SetThreadPriority error %d\n", GetLastError());
3385 SetLastError(0xdeadbeef);
3386 ret = TerminateThread(thread, 199);
3387 ok(ret, "TerminateThread error %d\n", GetLastError());
3388 /* Calling GetExitCodeThread() without waiting for thread termination
3389 * leads to different results due to a race condition.
3391 ret = WaitForSingleObject(thread, 1000);
3392 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
3393 GetExitCodeThread(thread, &ret);
3394 ok(ret == 199, "expected exit code 199, got %u\n", ret);
3396 SetLastError(0xdeadbeef);
3397 ret = TerminateProcess(pi.hProcess, 198);
3398 ok(ret, "TerminateProcess error %d\n", GetLastError());
3399 /* Checking process state without waiting for process termination
3400 * leads to different results due to a race condition.
3402 ret = WaitForSingleObject(pi.hProcess, 1000);
3403 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
3405 SetLastError(0xdeadbeef);
3406 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pi.dwProcessId);
3407 ok(process != NULL, "OpenProcess error %d\n", GetLastError());
3408 CloseHandle(process);
3410 memset(&pbi, 0, sizeof(pbi));
3411 ret = pNtQueryInformationProcess(pi.hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
3412 ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
3413 ok(pbi.ExitStatus == 198, "expected 198, got %lu\n", pbi.ExitStatus);
3414 affinity = 1;
3415 ret = pNtSetInformationProcess(pi.hProcess, ProcessAffinityMask, &affinity, sizeof(affinity));
3416 ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#x\n", ret);
3418 SetLastError(0xdeadbeef);
3419 ctx.ContextFlags = CONTEXT_INTEGER;
3420 ret = GetThreadContext(thread, &ctx);
3421 ok(!ret || broken(ret) /* XP 64-bit */, "GetThreadContext should fail\n");
3422 if (!ret)
3423 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
3424 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
3425 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */ ||
3426 GetLastError() == ERROR_ACCESS_DENIED /* Win10 32-bit */,
3427 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3428 SetLastError(0xdeadbeef);
3429 ctx.ContextFlags = CONTEXT_INTEGER;
3430 ret = SetThreadContext(thread, &ctx);
3431 ok(!ret || broken(ret) /* XP 64-bit */, "SetThreadContext should fail\n");
3432 if (!ret)
3433 ok(GetLastError() == ERROR_ACCESS_DENIED ||
3434 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
3435 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
3436 "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
3437 SetLastError(0xdeadbeef);
3438 ret = SetThreadPriority(thread, 0);
3439 ok(ret, "SetThreadPriority error %d\n", GetLastError());
3440 CloseHandle(thread);
3442 SetLastError(0xdeadbeef);
3443 ctx.ContextFlags = CONTEXT_INTEGER;
3444 ret = GetThreadContext(pi.hThread, &ctx);
3445 ok(!ret || broken(ret) /* XP 64-bit */, "GetThreadContext should fail\n");
3446 if (!ret)
3447 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
3448 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
3449 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */ ||
3450 GetLastError() == ERROR_ACCESS_DENIED /* Win10 32-bit */,
3451 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3452 SetLastError(0xdeadbeef);
3453 ctx.ContextFlags = CONTEXT_INTEGER;
3454 ret = SetThreadContext(pi.hThread, &ctx);
3455 ok(!ret || broken(ret) /* XP 64-bit */, "SetThreadContext should fail\n");
3456 if (!ret)
3457 ok(GetLastError() == ERROR_ACCESS_DENIED ||
3458 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
3459 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
3460 "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
3461 SetLastError(0xdeadbeef);
3462 ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READWRITE, &old_prot);
3463 ok(!ret, "VirtualProtectEx should fail\n");
3464 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
3465 SetLastError(0xdeadbeef);
3466 size = 0;
3467 ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size);
3468 ok(!ret, "ReadProcessMemory should fail\n");
3469 ok(GetLastError() == ERROR_PARTIAL_COPY || GetLastError() == ERROR_ACCESS_DENIED,
3470 "expected ERROR_PARTIAL_COPY, got %d\n", GetLastError());
3471 ok(!size, "expected 0, got %lu\n", size);
3472 SetLastError(0xdeadbeef);
3473 ret = VirtualFreeEx(pi.hProcess, addr, 0, MEM_RELEASE);
3474 ok(!ret, "VirtualFreeEx should fail\n");
3475 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
3476 SetLastError(0xdeadbeef);
3477 addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
3478 ok(!addr, "VirtualAllocEx should fail\n");
3479 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
3480 SetLastError(0xdeadbeef);
3481 size = VirtualQueryEx(pi.hProcess, NULL, &mbi, sizeof(mbi));
3482 ok(!size, "VirtualQueryEx should fail\n");
3483 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
3485 /* CloseHandle() call below leads to premature process termination
3486 * under some Windows versions.
3488 if (0)
3490 SetLastError(0xdeadbeef);
3491 ret = CloseHandle(hmap_dup);
3492 ok(ret, "CloseHandle should not fail\n");
3495 SetLastError(0xdeadbeef);
3496 ret = DuplicateHandle(GetCurrentProcess(), hmap, pi.hProcess, &hmap_dup,
3497 0, FALSE, DUPLICATE_SAME_ACCESS);
3498 ok(!ret, "DuplicateHandle should fail\n");
3499 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
3501 offset.u.LowPart = 0;
3502 offset.u.HighPart = 0;
3503 addr = NULL;
3504 size = 0;
3505 ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset,
3506 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
3507 ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#x\n", ret);
3509 SetLastError(0xdeadbeef);
3510 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
3511 ok(!thread, "CreateRemoteThread should fail\n");
3512 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
3514 SetLastError(0xdeadbeef);
3515 ret = DebugActiveProcess(pi.dwProcessId);
3516 ok(!ret, "DebugActiveProcess should fail\n");
3517 ok(GetLastError() == ERROR_ACCESS_DENIED /* 64-bit */ || GetLastError() == ERROR_NOT_SUPPORTED /* 32-bit */,
3518 "ERROR_ACCESS_DENIED, got %d\n", GetLastError());
3520 GetExitCodeProcess(pi.hProcess, &ret);
3521 ok(ret == 198 || broken(ret != 198) /* some 32-bit XP version in a VM returns random exit code */,
3522 "expected exit code 198, got %u\n", ret);
3523 CloseHandle(pi.hThread);
3524 CloseHandle(pi.hProcess);
3526 ret = DeleteFileA(dll_name);
3527 ok(ret, "DeleteFile error %d\n", GetLastError());
3528 #else
3529 skip("x86 specific ExitProcess test\n");
3530 #endif
3533 static PVOID WINAPI failuredllhook(ULONG ul, DELAYLOAD_INFO* pd)
3535 ok(ul == 4, "expected 4, got %u\n", ul);
3536 ok(!!pd, "no delayload info supplied\n");
3537 if (pd)
3539 ok(pd->Size == sizeof(*pd), "got %u\n", pd->Size);
3540 ok(!!pd->DelayloadDescriptor, "no DelayloadDescriptor supplied\n");
3541 if (pd->DelayloadDescriptor)
3543 ok(pd->DelayloadDescriptor->Attributes.AllAttributes == 1,
3544 "expected 1, got %u\n", pd->DelayloadDescriptor->Attributes.AllAttributes);
3545 ok(pd->DelayloadDescriptor->DllNameRVA == 0x2000,
3546 "expected 0x2000, got %x\n", pd->DelayloadDescriptor->DllNameRVA);
3547 ok(pd->DelayloadDescriptor->ModuleHandleRVA == 0x201a,
3548 "expected 0x201a, got %x\n", pd->DelayloadDescriptor->ModuleHandleRVA);
3549 ok(pd->DelayloadDescriptor->ImportAddressTableRVA > pd->DelayloadDescriptor->ModuleHandleRVA,
3550 "expected %x > %x\n", pd->DelayloadDescriptor->ImportAddressTableRVA,
3551 pd->DelayloadDescriptor->ModuleHandleRVA);
3552 ok(pd->DelayloadDescriptor->ImportNameTableRVA > pd->DelayloadDescriptor->ImportAddressTableRVA,
3553 "expected %x > %x\n", pd->DelayloadDescriptor->ImportNameTableRVA,
3554 pd->DelayloadDescriptor->ImportAddressTableRVA);
3555 ok(pd->DelayloadDescriptor->BoundImportAddressTableRVA == 0,
3556 "expected 0, got %x\n", pd->DelayloadDescriptor->BoundImportAddressTableRVA);
3557 ok(pd->DelayloadDescriptor->UnloadInformationTableRVA == 0,
3558 "expected 0, got %x\n", pd->DelayloadDescriptor->UnloadInformationTableRVA);
3559 ok(pd->DelayloadDescriptor->TimeDateStamp == 0,
3560 "expected 0, got %x\n", pd->DelayloadDescriptor->TimeDateStamp);
3563 ok(!!pd->ThunkAddress, "no ThunkAddress supplied\n");
3564 if (pd->ThunkAddress)
3565 ok(pd->ThunkAddress->u1.Ordinal, "no ThunkAddress value supplied\n");
3567 ok(!!pd->TargetDllName, "no TargetDllName supplied\n");
3568 if (pd->TargetDllName)
3569 ok(!strcmp(pd->TargetDllName, "secur32.dll"),
3570 "expected \"secur32.dll\", got \"%s\"\n", pd->TargetDllName);
3572 ok(pd->TargetApiDescriptor.ImportDescribedByName == 0,
3573 "expected 0, got %x\n", pd->TargetApiDescriptor.ImportDescribedByName);
3574 ok(pd->TargetApiDescriptor.Description.Ordinal == 0 ||
3575 pd->TargetApiDescriptor.Description.Ordinal == 999,
3576 "expected 0, got %x\n", pd->TargetApiDescriptor.Description.Ordinal);
3578 ok(!!pd->TargetModuleBase, "no TargetModuleBase supplied\n");
3579 ok(pd->Unused == NULL, "expected NULL, got %p\n", pd->Unused);
3580 ok(pd->LastError, "no LastError supplied\n");
3582 cb_count++;
3583 return (void*)0xdeadbeef;
3586 static PVOID WINAPI failuresyshook(const char *dll, const char *function)
3588 ok(!strcmp(dll, "secur32.dll"), "wrong dll: %s\n", dll);
3589 ok(!((ULONG_PTR)function >> 16), "expected ordinal, got %p\n", function);
3590 cb_count_sys++;
3591 return (void*)0x12345678;
3594 static void test_ResolveDelayLoadedAPI(void)
3596 static const char test_dll[] = "secur32.dll";
3597 static const char test_func[] = "SealMessage";
3598 char temp_path[MAX_PATH];
3599 char dll_name[MAX_PATH];
3600 IMAGE_DELAYLOAD_DESCRIPTOR idd, *delaydir;
3601 IMAGE_THUNK_DATA itd32;
3602 HANDLE hfile;
3603 HMODULE hlib;
3604 DWORD dummy, file_size, i;
3605 WORD hint = 0;
3606 BOOL ret;
3607 IMAGE_NT_HEADERS nt_header;
3609 static const struct test_data
3611 BOOL func;
3612 UINT_PTR ordinal;
3613 BOOL succeeds;
3614 } td[] =
3617 TRUE, 0, TRUE
3620 FALSE, IMAGE_ORDINAL_FLAG | 2, TRUE
3623 FALSE, IMAGE_ORDINAL_FLAG | 5, TRUE
3626 FALSE, IMAGE_ORDINAL_FLAG | 0, FALSE
3629 FALSE, IMAGE_ORDINAL_FLAG | 999, FALSE
3633 if (!pResolveDelayLoadedAPI)
3635 win_skip("ResolveDelayLoadedAPI is not available\n");
3636 return;
3639 if (0) /* crashes on native */
3641 SetLastError(0xdeadbeef);
3642 ok(!pResolveDelayLoadedAPI(NULL, NULL, NULL, NULL, NULL, 0),
3643 "ResolveDelayLoadedAPI succeeded\n");
3644 ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %x\n", GetLastError());
3646 cb_count = 0;
3647 SetLastError(0xdeadbeef);
3648 ok(!pResolveDelayLoadedAPI(NULL, NULL, failuredllhook, NULL, NULL, 0),
3649 "ResolveDelayLoadedAPI succeeded\n");
3650 ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %x\n", GetLastError());
3651 ok(cb_count == 1, "Wrong callback count: %d\n", cb_count);
3654 GetTempPathA(MAX_PATH, temp_path);
3655 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
3656 trace("creating %s\n", dll_name);
3657 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
3658 if (hfile == INVALID_HANDLE_VALUE)
3660 ok(0, "could not create %s\n", dll_name);
3661 return;
3664 SetLastError(0xdeadbeef);
3665 ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
3666 ok(ret, "WriteFile error %d\n", GetLastError());
3668 nt_header = nt_header_template;
3669 nt_header.FileHeader.NumberOfSections = 2;
3670 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
3672 nt_header.OptionalHeader.SectionAlignment = 0x1000;
3673 nt_header.OptionalHeader.FileAlignment = 0x1000;
3674 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x2200;
3675 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + 2 * sizeof(IMAGE_SECTION_HEADER);
3676 nt_header.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
3677 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress = 0x1000;
3678 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size = 0x100;
3680 SetLastError(0xdeadbeef);
3681 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
3682 ok(ret, "WriteFile error %d\n", GetLastError());
3684 SetLastError(0xdeadbeef);
3685 ret = WriteFile(hfile, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
3686 ok(ret, "WriteFile error %d\n", GetLastError());
3688 /* sections */
3689 section.PointerToRawData = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
3690 section.VirtualAddress = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
3691 section.Misc.VirtualSize = 2 * sizeof(idd);
3692 section.SizeOfRawData = section.Misc.VirtualSize;
3693 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
3694 SetLastError(0xdeadbeef);
3695 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
3696 ok(ret, "WriteFile error %d\n", GetLastError());
3698 section.PointerToRawData = 0x2000;
3699 section.VirtualAddress = 0x2000;
3700 i = ARRAY_SIZE(td);
3701 section.Misc.VirtualSize = sizeof(test_dll) + sizeof(hint) + sizeof(test_func) + sizeof(HMODULE) +
3702 2 * (i + 1) * sizeof(IMAGE_THUNK_DATA);
3703 ok(section.Misc.VirtualSize <= 0x1000, "Too much tests, add a new section!\n");
3704 section.SizeOfRawData = section.Misc.VirtualSize;
3705 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
3706 SetLastError(0xdeadbeef);
3707 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
3708 ok(ret, "WriteFile error %d\n", GetLastError());
3710 /* fill up to delay data */
3711 SetFilePointer( hfile, nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress, NULL, SEEK_SET );
3713 /* delay data */
3714 idd.Attributes.AllAttributes = 1;
3715 idd.DllNameRVA = 0x2000;
3716 idd.ModuleHandleRVA = idd.DllNameRVA + sizeof(test_dll) + sizeof(hint) + sizeof(test_func);
3717 idd.ImportAddressTableRVA = idd.ModuleHandleRVA + sizeof(HMODULE);
3718 idd.ImportNameTableRVA = idd.ImportAddressTableRVA + (i + 1) * sizeof(IMAGE_THUNK_DATA);
3719 idd.BoundImportAddressTableRVA = 0;
3720 idd.UnloadInformationTableRVA = 0;
3721 idd.TimeDateStamp = 0;
3723 SetLastError(0xdeadbeef);
3724 ret = WriteFile(hfile, &idd, sizeof(idd), &dummy, NULL);
3725 ok(ret, "WriteFile error %d\n", GetLastError());
3727 SetLastError(0xdeadbeef);
3728 ret = WriteFile(hfile, filler, sizeof(idd), &dummy, NULL);
3729 ok(ret, "WriteFile error %d\n", GetLastError());
3731 /* fill up to extended delay data */
3732 SetFilePointer( hfile, idd.DllNameRVA, NULL, SEEK_SET );
3734 /* extended delay data */
3735 SetLastError(0xdeadbeef);
3736 ret = WriteFile(hfile, test_dll, sizeof(test_dll), &dummy, NULL);
3737 ok(ret, "WriteFile error %d\n", GetLastError());
3739 SetLastError(0xdeadbeef);
3740 ret = WriteFile(hfile, &hint, sizeof(hint), &dummy, NULL);
3741 ok(ret, "WriteFile error %d\n", GetLastError());
3743 SetLastError(0xdeadbeef);
3744 ret = WriteFile(hfile, test_func, sizeof(test_func), &dummy, NULL);
3745 ok(ret, "WriteFile error %d\n", GetLastError());
3747 SetFilePointer( hfile, idd.ImportAddressTableRVA, NULL, SEEK_SET );
3749 for (i = 0; i < ARRAY_SIZE(td); i++)
3751 /* 0x1a00 is an empty space between delay data and extended delay data, real thunks are not necessary */
3752 itd32.u1.Function = nt_header.OptionalHeader.ImageBase + 0x1a00 + i * 0x20;
3753 SetLastError(0xdeadbeef);
3754 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
3755 ok(ret, "WriteFile error %d\n", GetLastError());
3758 itd32.u1.Function = 0;
3759 SetLastError(0xdeadbeef);
3760 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
3761 ok(ret, "WriteFile error %d\n", GetLastError());
3763 for (i = 0; i < ARRAY_SIZE(td); i++)
3765 if (td[i].func)
3766 itd32.u1.AddressOfData = idd.DllNameRVA + sizeof(test_dll);
3767 else
3768 itd32.u1.Ordinal = td[i].ordinal;
3769 SetLastError(0xdeadbeef);
3770 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
3771 ok(ret, "WriteFile error %d\n", GetLastError());
3774 itd32.u1.Ordinal = 0;
3775 SetLastError(0xdeadbeef);
3776 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
3777 ok(ret, "WriteFile error %d\n", GetLastError());
3779 /* fill up to eof */
3780 SetFilePointer( hfile, section.VirtualAddress + section.Misc.VirtualSize, NULL, SEEK_SET );
3781 SetEndOfFile( hfile );
3782 CloseHandle(hfile);
3784 SetLastError(0xdeadbeef);
3785 hlib = LoadLibraryA(dll_name);
3786 ok(hlib != NULL, "LoadLibrary error %u\n", GetLastError());
3787 if (!hlib)
3789 skip("couldn't load %s.\n", dll_name);
3790 DeleteFileA(dll_name);
3791 return;
3794 delaydir = pRtlImageDirectoryEntryToData(hlib, TRUE, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, &file_size);
3795 if (!delaydir)
3797 skip("haven't found section for delay import directory.\n");
3798 FreeLibrary(hlib);
3799 DeleteFileA(dll_name);
3800 return;
3803 for (;;)
3805 IMAGE_THUNK_DATA *itdn, *itda;
3806 HMODULE htarget;
3808 if (!delaydir->DllNameRVA ||
3809 !delaydir->ImportAddressTableRVA ||
3810 !delaydir->ImportNameTableRVA) break;
3812 itdn = RVAToAddr(delaydir->ImportNameTableRVA, hlib);
3813 itda = RVAToAddr(delaydir->ImportAddressTableRVA, hlib);
3814 htarget = LoadLibraryA(RVAToAddr(delaydir->DllNameRVA, hlib));
3816 for (i = 0; i < ARRAY_SIZE(td); i++)
3818 void *ret, *load;
3820 if (IMAGE_SNAP_BY_ORDINAL(itdn[i].u1.Ordinal))
3821 load = (void *)GetProcAddress(htarget, (LPSTR)IMAGE_ORDINAL(itdn[i].u1.Ordinal));
3822 else
3824 const IMAGE_IMPORT_BY_NAME* iibn = RVAToAddr(itdn[i].u1.AddressOfData, hlib);
3825 load = (void *)GetProcAddress(htarget, (char*)iibn->Name);
3828 /* test without failure dll callback */
3829 cb_count = cb_count_sys = 0;
3830 ret = pResolveDelayLoadedAPI(hlib, delaydir, NULL, failuresyshook, &itda[i], 0);
3831 if (td[i].succeeds)
3833 ok(ret != NULL, "Test %u: ResolveDelayLoadedAPI failed\n", i);
3834 ok(ret == load, "Test %u: expected %p, got %p\n", i, load, ret);
3835 ok(ret == (void*)itda[i].u1.AddressOfData, "Test %u: expected %p, got %p\n",
3836 i, ret, (void*)itda[i].u1.AddressOfData);
3837 ok(!cb_count, "Test %u: Wrong callback count: %d\n", i, cb_count);
3838 ok(!cb_count_sys, "Test %u: Wrong sys callback count: %d\n", i, cb_count_sys);
3840 else
3842 ok(ret == (void*)0x12345678, "Test %u: ResolveDelayLoadedAPI succeeded with %p\n", i, ret);
3843 ok(!cb_count, "Test %u: Wrong callback count: %d\n", i, cb_count);
3844 ok(cb_count_sys == 1, "Test %u: Wrong sys callback count: %d\n", i, cb_count_sys);
3847 /* test with failure dll callback */
3848 cb_count = cb_count_sys = 0;
3849 ret = pResolveDelayLoadedAPI(hlib, delaydir, failuredllhook, failuresyshook, &itda[i], 0);
3850 if (td[i].succeeds)
3852 ok(ret != NULL, "Test %u: ResolveDelayLoadedAPI failed\n", i);
3853 ok(ret == load, "Test %u: expected %p, got %p\n", i, load, ret);
3854 ok(ret == (void*)itda[i].u1.AddressOfData, "Test %u: expected %p, got %p\n",
3855 i, ret, (void*)itda[i].u1.AddressOfData);
3856 ok(!cb_count, "Test %u: Wrong callback count: %d\n", i, cb_count);
3857 ok(!cb_count_sys, "Test %u: Wrong sys callback count: %d\n", i, cb_count_sys);
3859 else
3861 if (ret == (void*)0x12345678)
3863 /* Win10+ sometimes buffers the address of the stub function */
3864 ok(!cb_count, "Test %u: Wrong callback count: %d\n", i, cb_count);
3865 ok(!cb_count_sys, "Test %u: Wrong sys callback count: %d\n", i, cb_count_sys);
3867 else if (ret == (void*)0xdeadbeef)
3869 ok(cb_count == 1, "Test %u: Wrong callback count: %d\n", i, cb_count);
3870 ok(!cb_count_sys, "Test %u: Wrong sys callback count: %d\n", i, cb_count_sys);
3872 else
3873 ok(0, "Test %u: ResolveDelayLoadedAPI succeeded with %p\n", i, ret);
3876 delaydir++;
3879 FreeLibrary(hlib);
3880 trace("deleting %s\n", dll_name);
3881 DeleteFileA(dll_name);
3884 static void test_InMemoryOrderModuleList(void)
3886 PEB_LDR_DATA *ldr = NtCurrentTeb()->Peb->LdrData;
3887 LIST_ENTRY *entry1, *mark1 = &ldr->InLoadOrderModuleList;
3888 LIST_ENTRY *entry2, *mark2 = &ldr->InMemoryOrderModuleList;
3889 LDR_DATA_TABLE_ENTRY *module1, *module2;
3891 ok(ldr->Initialized == TRUE, "expected TRUE, got %u\n", ldr->Initialized);
3893 for (entry1 = mark1->Flink, entry2 = mark2->Flink;
3894 entry1 != mark1 && entry2 != mark2;
3895 entry1 = entry1->Flink, entry2 = entry2->Flink)
3897 module1 = CONTAINING_RECORD(entry1, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3898 module2 = CONTAINING_RECORD(entry2, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
3899 ok(module1 == module2, "expected module1 == module2, got %p and %p\n", module1, module2);
3901 ok(entry1 == mark1, "expected entry1 == mark1, got %p and %p\n", entry1, mark1);
3902 ok(entry2 == mark2, "expected entry2 == mark2, got %p and %p\n", entry2, mark2);
3905 static void test_wow64_redirection_for_dll(const char *libname)
3907 HMODULE lib;
3908 char buf[256];
3910 if (!GetModuleHandleA(libname))
3912 lib = LoadLibraryExA(libname, NULL, 0);
3913 ok (broken(lib == NULL) /* Vista/2008 */ ||
3914 lib != NULL, "Loading %s should succeed with WOW64 redirection disabled\n", libname);
3915 if (lib)
3917 /* Win 7/2008R2 return the un-redirected path (i.e. c:\windows\system32\dwrite.dll), test loading it. */
3918 GetModuleFileNameA(lib, buf, sizeof(buf));
3919 FreeLibrary(lib);
3920 lib = LoadLibraryExA(buf, NULL, 0);
3921 ok(lib != NULL, "Loading %s from full path should succeed with WOW64 redirection disabled\n", libname);
3922 if (lib)
3923 FreeLibrary(lib);
3926 else
3928 skip("%s was already loaded in the process\n", libname);
3932 static void test_wow64_redirection(void)
3934 void *OldValue;
3936 if (!is_wow64)
3937 return;
3939 /* Disable FS redirection, then test loading system libraries (pick ones that shouldn't
3940 * already be loaded in this process).
3942 ok(pWow64DisableWow64FsRedirection(&OldValue), "Disabling FS redirection failed\n");
3943 test_wow64_redirection_for_dll("wlanapi.dll");
3944 test_wow64_redirection_for_dll("dxgi.dll");
3945 test_wow64_redirection_for_dll("dwrite.dll");
3946 ok(pWow64RevertWow64FsRedirection(OldValue), "Re-enabling FS redirection failed\n");
3949 static void test_dll_file( const char *name )
3951 HMODULE module = GetModuleHandleA( name );
3952 IMAGE_NT_HEADERS *nt, *nt_file;
3953 IMAGE_SECTION_HEADER *sec, *sec_file;
3954 char path[MAX_PATH];
3955 HANDLE file, mapping;
3956 int i = 0;
3957 void *ptr;
3959 GetModuleFileNameA( module, path, MAX_PATH );
3960 file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
3961 ok( file != INVALID_HANDLE_VALUE, "can't open '%s': %u\n", path, GetLastError() );
3963 mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 0, NULL );
3964 ok( mapping != NULL, "%s: CreateFileMappingW failed err %u\n", name, GetLastError() );
3965 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
3966 ok( ptr != NULL, "%s: MapViewOfFile failed err %u\n", name, GetLastError() );
3967 CloseHandle( mapping );
3968 CloseHandle( file );
3970 nt = pRtlImageNtHeader( module );
3971 nt_file = pRtlImageNtHeader( ptr );
3972 ok( nt_file != NULL, "%s: invalid header\n", path );
3973 #define OK_FIELD(x) ok( nt->x == nt_file->x, "%s:%u: wrong " #x " %x / %x\n", name, i, nt->x, nt_file->x )
3974 OK_FIELD( FileHeader.NumberOfSections );
3975 OK_FIELD( OptionalHeader.AddressOfEntryPoint );
3976 OK_FIELD( OptionalHeader.NumberOfRvaAndSizes );
3977 for (i = 0; i < nt->OptionalHeader.NumberOfRvaAndSizes; i++)
3979 OK_FIELD( OptionalHeader.DataDirectory[i].VirtualAddress );
3980 OK_FIELD( OptionalHeader.DataDirectory[i].Size );
3982 sec = (IMAGE_SECTION_HEADER *)((char *)&nt->OptionalHeader + nt->FileHeader.SizeOfOptionalHeader);
3983 sec_file = (IMAGE_SECTION_HEADER *)((char *)&nt_file->OptionalHeader + nt_file->FileHeader.SizeOfOptionalHeader);
3984 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
3985 ok( !memcmp( sec + i, sec_file + i, sizeof(*sec) ), "%s: wrong section %d\n", name, i );
3986 UnmapViewOfFile( ptr );
3987 #undef OK_FIELD
3990 static void test_LoadPackagedLibrary(void)
3992 HMODULE h;
3994 if (!pLoadPackagedLibrary)
3996 win_skip("LoadPackagedLibrary is not available.\n");
3997 return;
4000 SetLastError( 0xdeadbeef );
4001 h = pLoadPackagedLibrary(L"kernel32.dll", 0);
4002 ok(!h && GetLastError() == APPMODEL_ERROR_NO_PACKAGE, "Got unexpected handle %p, GetLastError() %u.\n",
4003 h, GetLastError());
4006 START_TEST(loader)
4008 int argc;
4009 char **argv;
4010 HANDLE ntdll, mapping, kernel32;
4011 SYSTEM_INFO si;
4013 ntdll = GetModuleHandleA("ntdll.dll");
4014 kernel32 = GetModuleHandleA("kernel32.dll");
4015 pNtCreateSection = (void *)GetProcAddress(ntdll, "NtCreateSection");
4016 pNtQuerySection = (void *)GetProcAddress(ntdll, "NtQuerySection");
4017 pNtMapViewOfSection = (void *)GetProcAddress(ntdll, "NtMapViewOfSection");
4018 pNtUnmapViewOfSection = (void *)GetProcAddress(ntdll, "NtUnmapViewOfSection");
4019 pNtTerminateProcess = (void *)GetProcAddress(ntdll, "NtTerminateProcess");
4020 pNtQueryInformationProcess = (void *)GetProcAddress(ntdll, "NtQueryInformationProcess");
4021 pNtSetInformationProcess = (void *)GetProcAddress(ntdll, "NtSetInformationProcess");
4022 pLdrShutdownProcess = (void *)GetProcAddress(ntdll, "LdrShutdownProcess");
4023 pRtlDllShutdownInProgress = (void *)GetProcAddress(ntdll, "RtlDllShutdownInProgress");
4024 pNtAllocateVirtualMemory = (void *)GetProcAddress(ntdll, "NtAllocateVirtualMemory");
4025 pNtFreeVirtualMemory = (void *)GetProcAddress(ntdll, "NtFreeVirtualMemory");
4026 pLdrLockLoaderLock = (void *)GetProcAddress(ntdll, "LdrLockLoaderLock");
4027 pLdrUnlockLoaderLock = (void *)GetProcAddress(ntdll, "LdrUnlockLoaderLock");
4028 pLdrLoadDll = (void *)GetProcAddress(ntdll, "LdrLoadDll");
4029 pLdrUnloadDll = (void *)GetProcAddress(ntdll, "LdrUnloadDll");
4030 pRtlInitUnicodeString = (void *)GetProcAddress(ntdll, "RtlInitUnicodeString");
4031 pRtlAcquirePebLock = (void *)GetProcAddress(ntdll, "RtlAcquirePebLock");
4032 pRtlReleasePebLock = (void *)GetProcAddress(ntdll, "RtlReleasePebLock");
4033 pRtlImageDirectoryEntryToData = (void *)GetProcAddress(ntdll, "RtlImageDirectoryEntryToData");
4034 pRtlImageNtHeader = (void *)GetProcAddress(ntdll, "RtlImageNtHeader");
4035 pFlsAlloc = (void *)GetProcAddress(kernel32, "FlsAlloc");
4036 pFlsSetValue = (void *)GetProcAddress(kernel32, "FlsSetValue");
4037 pFlsGetValue = (void *)GetProcAddress(kernel32, "FlsGetValue");
4038 pFlsFree = (void *)GetProcAddress(kernel32, "FlsFree");
4039 pIsWow64Process = (void *)GetProcAddress(kernel32, "IsWow64Process");
4040 pWow64DisableWow64FsRedirection = (void *)GetProcAddress(kernel32, "Wow64DisableWow64FsRedirection");
4041 pWow64RevertWow64FsRedirection = (void *)GetProcAddress(kernel32, "Wow64RevertWow64FsRedirection");
4042 pResolveDelayLoadedAPI = (void *)GetProcAddress(kernel32, "ResolveDelayLoadedAPI");
4043 pLoadPackagedLibrary = (void *)GetProcAddress(kernel32, "LoadPackagedLibrary");
4045 if (pIsWow64Process) pIsWow64Process( GetCurrentProcess(), &is_wow64 );
4046 GetSystemInfo( &si );
4047 page_size = si.dwPageSize;
4048 dos_header.e_magic = IMAGE_DOS_SIGNATURE;
4049 dos_header.e_lfanew = sizeof(dos_header);
4051 mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_loader");
4052 ok(mapping != 0, "CreateFileMapping failed\n");
4053 child_failures = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 4096);
4054 if (*child_failures == -1)
4056 *child_failures = 0;
4058 else
4059 *child_failures = -1;
4061 argc = winetest_get_mainargs(&argv);
4062 if (argc > 4)
4064 test_dll_phase = atoi(argv[4]);
4065 child_process(argv[2], atol(argv[3]));
4066 return;
4069 test_filenames();
4070 test_ResolveDelayLoadedAPI();
4071 test_ImportDescriptors();
4072 test_section_access();
4073 test_import_resolution();
4074 test_ExitProcess();
4075 test_InMemoryOrderModuleList();
4076 test_LoadPackagedLibrary();
4077 test_wow64_redirection();
4078 test_dll_file( "ntdll.dll" );
4079 test_dll_file( "kernel32.dll" );
4080 test_dll_file( "advapi32.dll" );
4081 test_dll_file( "user32.dll" );
4082 /* loader test must be last, it can corrupt the internal loader state on Windows */
4083 test_Loader();