cmd: Use CRT's popen instead of rewriting it.
[wine.git] / dlls / kernel32 / tests / loader.c
blob8b332e479e67d7e203c2b312821326993ab50f76
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 #include <stdarg.h>
22 #include <stdio.h>
23 #include <assert.h>
25 #include "ntstatus.h"
26 #define WIN32_NO_STATUS
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winternl.h"
30 #include "winnls.h"
31 #include "wine/test.h"
32 #include "delayloadhandler.h"
34 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
35 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
37 #define ALIGN_SIZE(size, alignment) (((size) + ((ULONG_PTR)(alignment) - 1)) & ~(((ULONG_PTR)(alignment) - 1)))
39 struct PROCESS_BASIC_INFORMATION_PRIVATE
41 NTSTATUS ExitStatus;
42 PPEB PebBaseAddress;
43 DWORD_PTR AffinityMask;
44 DWORD_PTR BasePriority;
45 ULONG_PTR UniqueProcessId;
46 ULONG_PTR InheritedFromUniqueProcessId;
49 static LONG *child_failures;
50 static WORD cb_count, cb_count_sys;
51 static DWORD page_size;
52 static BOOL is_win64 = sizeof(void *) > sizeof(int);
53 static BOOL is_wow64;
54 static char system_dir[MAX_PATH];
55 static char syswow_dir[MAX_PATH]; /* only available if 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 0x10000000, /* ImageBase */
133 #else
134 0x123450000, /* ImageBase */
135 #endif
136 0, /* SectionAlignment */
137 0, /* FileAlignment */
138 4, /* MajorOperatingSystemVersion */
139 0, /* MinorOperatingSystemVersion */
140 1, /* MajorImageVersion */
141 0, /* MinorImageVersion */
142 4, /* MajorSubsystemVersion */
143 0, /* MinorSubsystemVersion */
144 0, /* Win32VersionValue */
145 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000, /* SizeOfImage */
146 sizeof(dos_header) + sizeof(nt_header_template), /* SizeOfHeaders */
147 0, /* CheckSum */
148 IMAGE_SUBSYSTEM_WINDOWS_CUI, /* Subsystem */
149 IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT, /* DllCharacteristics */
150 0x100000, /* SizeOfStackReserve */
151 0x1000, /* SizeOfStackCommit */
152 0x100000, /* SizeOfHeapReserve */
153 0x1000, /* SizeOfHeapCommit */
154 0, /* LoaderFlags */
155 IMAGE_NUMBEROF_DIRECTORY_ENTRIES, /* NumberOfRvaAndSizes */
156 { { 0 } } /* DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] */
160 static IMAGE_SECTION_HEADER section =
162 ".rodata", /* Name */
163 { 0 }, /* Misc */
164 0, /* VirtualAddress */
165 0, /* SizeOfRawData */
166 0, /* PointerToRawData */
167 0, /* PointerToRelocations */
168 0, /* PointerToLinenumbers */
169 0, /* NumberOfRelocations */
170 0, /* NumberOfLinenumbers */
171 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, /* Characteristics */
175 static const char filler[0x1000];
176 static const char section_data[0x10] = "section data";
178 /* return an alternate machine of the same 32/64 bitness */
179 static WORD get_alt_machine( WORD orig_machine )
181 switch (orig_machine)
183 case IMAGE_FILE_MACHINE_I386: return IMAGE_FILE_MACHINE_ARMNT;
184 case IMAGE_FILE_MACHINE_AMD64: return IMAGE_FILE_MACHINE_ARM64;
185 case IMAGE_FILE_MACHINE_ARMNT: return IMAGE_FILE_MACHINE_I386;
186 case IMAGE_FILE_MACHINE_ARM64: return IMAGE_FILE_MACHINE_AMD64;
188 return 0;
191 /* return the machine of the alternate 32/64 bitness */
192 static WORD get_alt_bitness_machine( WORD orig_machine )
194 switch (orig_machine)
196 case IMAGE_FILE_MACHINE_I386: return IMAGE_FILE_MACHINE_AMD64;
197 case IMAGE_FILE_MACHINE_AMD64: return IMAGE_FILE_MACHINE_I386;
198 case IMAGE_FILE_MACHINE_ARMNT: return IMAGE_FILE_MACHINE_ARM64;
199 case IMAGE_FILE_MACHINE_ARM64: return IMAGE_FILE_MACHINE_ARMNT;
201 return 0;
204 static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size,
205 const IMAGE_NT_HEADERS *nt_header, char dll_name[MAX_PATH] )
207 char temp_path[MAX_PATH];
208 DWORD dummy, size, file_align;
209 HANDLE hfile;
210 BOOL ret;
212 GetTempPathA(MAX_PATH, temp_path);
213 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
215 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
216 ok( hfile != INVALID_HANDLE_VALUE, "failed to create %s err %lu\n", dll_name, GetLastError() );
217 if (hfile == INVALID_HANDLE_VALUE) return 0;
219 SetLastError(0xdeadbeef);
220 ret = WriteFile(hfile, dos_header, dos_size, &dummy, NULL);
221 ok(ret, "WriteFile error %ld\n", GetLastError());
223 SetLastError(0xdeadbeef);
224 ret = WriteFile(hfile, nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
225 ok(ret, "WriteFile error %ld\n", GetLastError());
227 if (nt_header->FileHeader.SizeOfOptionalHeader)
229 SetLastError(0xdeadbeef);
230 ret = WriteFile(hfile, &nt_header->OptionalHeader,
231 sizeof(IMAGE_OPTIONAL_HEADER),
232 &dummy, NULL);
233 ok(ret, "WriteFile error %ld\n", GetLastError());
234 if (nt_header->FileHeader.SizeOfOptionalHeader > sizeof(IMAGE_OPTIONAL_HEADER))
236 file_align = nt_header->FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER);
237 assert(file_align < sizeof(filler));
238 SetLastError(0xdeadbeef);
239 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
240 ok(ret, "WriteFile error %ld\n", GetLastError());
244 assert(nt_header->FileHeader.NumberOfSections <= 1);
245 if (nt_header->FileHeader.NumberOfSections)
247 SetFilePointer(hfile, dos_size + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + nt_header->FileHeader.SizeOfOptionalHeader, NULL, FILE_BEGIN);
249 section.SizeOfRawData = 10;
251 if (nt_header->OptionalHeader.SectionAlignment >= page_size)
253 section.PointerToRawData = dos_size;
254 section.VirtualAddress = nt_header->OptionalHeader.SectionAlignment;
255 section.Misc.VirtualSize = section.SizeOfRawData * 10;
257 else
259 section.PointerToRawData = nt_header->OptionalHeader.SizeOfHeaders;
260 section.VirtualAddress = nt_header->OptionalHeader.SizeOfHeaders;
261 section.Misc.VirtualSize = 5;
264 SetLastError(0xdeadbeef);
265 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
266 ok(ret, "WriteFile error %ld\n", GetLastError());
268 /* section data */
269 SetLastError(0xdeadbeef);
270 ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
271 ok(ret, "WriteFile error %ld\n", GetLastError());
274 /* Minimal PE image that Windows7+ is able to load: 268 bytes */
275 size = GetFileSize(hfile, NULL);
276 if (size < 268)
278 file_align = 268 - size;
279 SetLastError(0xdeadbeef);
280 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
281 ok(ret, "WriteFile error %ld\n", GetLastError());
284 size = GetFileSize(hfile, NULL);
285 CloseHandle(hfile);
286 return size;
289 static DWORD create_test_dll_sections( const IMAGE_DOS_HEADER *dos_header, const IMAGE_NT_HEADERS *nt_header,
290 const IMAGE_SECTION_HEADER *sections, const void *section_data,
291 char dll_name[MAX_PATH] )
293 char temp_path[MAX_PATH];
294 DWORD dummy, i, size;
295 HANDLE hfile;
296 BOOL ret;
298 GetTempPathA(MAX_PATH, temp_path);
299 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
301 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
302 ok( hfile != INVALID_HANDLE_VALUE, "failed to create %s err %lu\n", dll_name, GetLastError() );
303 if (hfile == INVALID_HANDLE_VALUE) return 0;
305 SetLastError(0xdeadbeef);
306 ret = WriteFile(hfile, dos_header, sizeof(*dos_header), &dummy, NULL);
307 ok(ret, "WriteFile error %ld\n", GetLastError());
309 SetLastError(0xdeadbeef);
310 ret = WriteFile(hfile, nt_header, offsetof(IMAGE_NT_HEADERS, OptionalHeader) + nt_header->FileHeader.SizeOfOptionalHeader, &dummy, NULL);
311 ok(ret, "WriteFile error %ld\n", GetLastError());
313 SetLastError(0xdeadbeef);
314 ret = WriteFile(hfile, sections, sizeof(*sections) * nt_header->FileHeader.NumberOfSections,
315 &dummy, NULL);
316 ok(ret, "WriteFile error %ld\n", GetLastError());
318 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
320 SetFilePointer(hfile, sections[i].PointerToRawData, NULL, FILE_BEGIN);
321 SetLastError(0xdeadbeef);
322 ret = WriteFile(hfile, section_data, sections[i].SizeOfRawData, &dummy, NULL);
323 ok(ret, "WriteFile error %ld\n", GetLastError());
325 size = GetFileSize(hfile, NULL);
326 CloseHandle(hfile);
327 return size;
330 static BOOL query_image_section( int id, const char *dll_name, const IMAGE_NT_HEADERS *nt_header,
331 const void *section_data )
333 SECTION_BASIC_INFORMATION info;
334 SECTION_IMAGE_INFORMATION image;
335 const IMAGE_COR20_HEADER *cor_header = NULL;
336 SIZE_T info_size = (SIZE_T)0xdeadbeef << 16;
337 NTSTATUS status;
338 HANDLE file, mapping;
339 ULONG file_size;
340 LARGE_INTEGER map_size;
341 SIZE_T max_stack, commit_stack;
342 void *entry_point;
343 BOOL truncated;
345 file = CreateFileA( dll_name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE,
346 NULL, OPEN_EXISTING, 0, 0 );
347 ok( file != INVALID_HANDLE_VALUE, "%u: CreateFile error %ld\n", id, GetLastError() );
348 file_size = GetFileSize( file, NULL );
350 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
351 NULL, NULL, PAGE_READONLY, SEC_IMAGE, file );
352 ok( !status, "%u: NtCreateSection failed err %lx\n", id, status );
353 if (status)
355 CloseHandle( file );
356 return FALSE;
358 status = pNtQuerySection( mapping, SectionImageInformation, &image, sizeof(image), &info_size );
359 ok( !status, "%u: NtQuerySection failed err %lx\n", id, status );
360 ok( info_size == sizeof(image), "%u: NtQuerySection wrong size %Iu\n", id, info_size );
361 if (nt_header->OptionalHeader.Magic == (is_win64 ? IMAGE_NT_OPTIONAL_HDR64_MAGIC
362 : IMAGE_NT_OPTIONAL_HDR32_MAGIC))
364 max_stack = nt_header->OptionalHeader.SizeOfStackReserve;
365 commit_stack = nt_header->OptionalHeader.SizeOfStackCommit;
366 entry_point = (char *)nt_header->OptionalHeader.ImageBase + nt_header->OptionalHeader.AddressOfEntryPoint;
367 truncated = nt_header->FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER);
368 if (!truncated &&
369 nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress &&
370 nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
371 cor_header = section_data;
373 else if (nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
375 const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt_header;
376 max_stack = 0x100000;
377 commit_stack = 0x10000;
378 entry_point = (void *)0x81231234;
379 truncated = nt_header->FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER64);
380 if (!truncated &&
381 nt64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress &&
382 nt64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
383 cor_header = section_data;
385 else
387 const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt_header;
388 max_stack = nt32->OptionalHeader.SizeOfStackReserve;
389 commit_stack = nt32->OptionalHeader.SizeOfStackCommit;
390 entry_point = (char *)(ULONG_PTR)nt32->OptionalHeader.ImageBase + nt32->OptionalHeader.AddressOfEntryPoint;
391 truncated = nt_header->FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER32);
392 if (!truncated &&
393 nt32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress &&
394 nt32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
395 cor_header = section_data;
397 ok( (char *)image.TransferAddress == (char *)entry_point ||
398 (image.ImageDynamicallyRelocated && LOWORD(image.TransferAddress) == LOWORD(entry_point)),
399 "%u: TransferAddress wrong %p / %p (%08lx)\n", id,
400 image.TransferAddress, entry_point, nt_header->OptionalHeader.AddressOfEntryPoint );
401 ok( image.ZeroBits == 0, "%u: ZeroBits wrong %08lx\n", id, image.ZeroBits );
402 ok( image.MaximumStackSize == max_stack,
403 "%u: MaximumStackSize wrong %Ix / %Ix\n", id, image.MaximumStackSize, max_stack );
404 ok( image.CommittedStackSize == commit_stack,
405 "%u: CommittedStackSize wrong %Ix / %Ix\n", id, image.CommittedStackSize, commit_stack );
406 ok( image.SubSystemType == nt_header->OptionalHeader.Subsystem,
407 "%u: SubSystemType wrong %08lx / %08x\n", id,
408 image.SubSystemType, nt_header->OptionalHeader.Subsystem );
409 ok( image.MinorSubsystemVersion == nt_header->OptionalHeader.MinorSubsystemVersion,
410 "%u: MinorSubsystemVersion wrong %04x / %04x\n", id,
411 image.MinorSubsystemVersion, nt_header->OptionalHeader.MinorSubsystemVersion );
412 ok( image.MajorSubsystemVersion == nt_header->OptionalHeader.MajorSubsystemVersion,
413 "%u: MajorSubsystemVersion wrong %04x / %04x\n", id,
414 image.MajorSubsystemVersion, nt_header->OptionalHeader.MajorSubsystemVersion );
415 ok( image.MajorOperatingSystemVersion == nt_header->OptionalHeader.MajorOperatingSystemVersion ||
416 broken( !image.MajorOperatingSystemVersion), /* before win10 */
417 "%u: MajorOperatingSystemVersion wrong %04x / %04x\n", id,
418 image.MajorOperatingSystemVersion, nt_header->OptionalHeader.MajorOperatingSystemVersion );
419 ok( image.MinorOperatingSystemVersion == nt_header->OptionalHeader.MinorOperatingSystemVersion,
420 "%u: MinorOperatingSystemVersion wrong %04x / %04x\n", id,
421 image.MinorOperatingSystemVersion, nt_header->OptionalHeader.MinorOperatingSystemVersion );
422 ok( image.ImageCharacteristics == nt_header->FileHeader.Characteristics,
423 "%u: ImageCharacteristics wrong %04x / %04x\n", id,
424 image.ImageCharacteristics, nt_header->FileHeader.Characteristics );
425 ok( image.DllCharacteristics == nt_header->OptionalHeader.DllCharacteristics,
426 "%u: DllCharacteristics wrong %04x / %04x\n", id,
427 image.DllCharacteristics, nt_header->OptionalHeader.DllCharacteristics );
428 ok( image.Machine == nt_header->FileHeader.Machine, "%u: Machine wrong %04x / %04x\n", id,
429 image.Machine, nt_header->FileHeader.Machine );
430 ok( image.LoaderFlags == (cor_header != NULL), "%u: LoaderFlags wrong %08lx\n", id, image.LoaderFlags );
431 ok( image.ImageFileSize == file_size,
432 "%u: ImageFileSize wrong %08lx / %08lx\n", id, image.ImageFileSize, file_size );
433 ok( image.CheckSum == nt_header->OptionalHeader.CheckSum,
434 "%u: CheckSum wrong %08lx / %08lx\n", id,
435 image.CheckSum, nt_header->OptionalHeader.CheckSum );
437 if (nt_header->OptionalHeader.SizeOfCode || nt_header->OptionalHeader.AddressOfEntryPoint)
438 ok( image.ImageContainsCode == TRUE, "%u: ImageContainsCode wrong %u\n", id,
439 image.ImageContainsCode );
440 else if ((nt_header->OptionalHeader.SectionAlignment % page_size) ||
441 (nt_header->FileHeader.NumberOfSections == 1 &&
442 (section.Characteristics & IMAGE_SCN_MEM_EXECUTE)))
443 ok( image.ImageContainsCode == TRUE || broken(!image.ImageContainsCode), /* <= win8 */
444 "%u: ImageContainsCode wrong %u\n", id, image.ImageContainsCode );
445 else
446 ok( !image.ImageContainsCode, "%u: ImageContainsCode wrong %u\n", id, image.ImageContainsCode );
448 if (cor_header &&
449 (cor_header->Flags & COMIMAGE_FLAGS_ILONLY) &&
450 (cor_header->MajorRuntimeVersion > 2 ||
451 (cor_header->MajorRuntimeVersion == 2 && cor_header->MinorRuntimeVersion >= 5)))
453 ok( image.ComPlusILOnly,
454 "%u: wrong ComPlusILOnly flags %02x\n", id, image.ImageFlags );
455 if (nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
456 !(cor_header->Flags & COMIMAGE_FLAGS_32BITREQUIRED))
457 ok( image.ComPlusNativeReady,
458 "%u: wrong ComPlusNativeReady flags %02x\n", id, image.ImageFlags );
459 else
460 ok( !image.ComPlusNativeReady,
461 "%u: wrong ComPlusNativeReady flags %02x\n", id, image.ImageFlags );
462 if (nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
463 (cor_header->Flags & COMIMAGE_FLAGS_32BITPREFERRED))
464 ok( image.ComPlusPrefer32bit ||
465 broken( !image.MajorOperatingSystemVersion ), /* before win10 */
466 "%u: wrong ComPlusPrefer32bit flags %02x\n", id, image.ImageFlags );
467 else
468 ok( !image.ComPlusPrefer32bit, "%u: wrong ComPlusPrefer32bit flags %02x\n", id, image.ImageFlags );
470 else
472 ok( !image.ComPlusILOnly, "%u: wrong ComPlusILOnly flags %02x\n", id, image.ImageFlags );
473 ok( !image.ComPlusNativeReady, "%u: wrong ComPlusNativeReady flags %02x\n", id, image.ImageFlags );
474 ok( !image.ComPlusPrefer32bit, "%u: wrong ComPlusPrefer32bit flags %02x\n", id, image.ImageFlags );
476 if (!(nt_header->OptionalHeader.SectionAlignment % page_size))
477 ok( !image.ImageMappedFlat, "%u: wrong ImageMappedFlat flags %02x\n", id, image.ImageFlags );
478 else
479 ok( image.ImageMappedFlat,
480 "%u: wrong ImageMappedFlat flags %02x\n", id, image.ImageFlags );
482 if (!(nt_header->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE))
483 ok( !image.ImageDynamicallyRelocated || broken( image.ComPlusILOnly ), /* <= win7 */
484 "%u: wrong ImageDynamicallyRelocated flags %02x\n", id, image.ImageFlags );
485 else if (image.ImageContainsCode && !image.ImageMappedFlat && !cor_header)
486 ok( image.ImageDynamicallyRelocated,
487 "%u: wrong ImageDynamicallyRelocated flags %02x\n", id, image.ImageFlags );
488 else
489 ok( !image.ImageDynamicallyRelocated || broken(TRUE), /* <= win8 */
490 "%u: wrong ImageDynamicallyRelocated flags %02x\n", id, image.ImageFlags );
491 ok( !image.BaseBelow4gb, "%u: wrong BaseBelow4gb flags %02x\n", id, image.ImageFlags );
493 map_size.QuadPart = (nt_header->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
494 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
495 ok( !status, "NtQuerySection failed err %lx\n", status );
496 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %lx%08lx / %lx%08lx\n",
497 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
498 CloseHandle( mapping );
500 map_size.QuadPart = (nt_header->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
501 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
502 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
503 ok( !status, "%u: NtCreateSection failed err %lx\n", id, status );
504 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
505 ok( !status, "NtQuerySection failed err %lx\n", status );
506 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %lx%08lx / %lx%08lx\n",
507 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
508 CloseHandle( mapping );
510 map_size.QuadPart++;
511 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
512 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
513 ok( status == STATUS_SECTION_TOO_BIG, "%u: NtCreateSection failed err %lx\n", id, status );
515 SetFilePointerEx( file, map_size, NULL, FILE_BEGIN );
516 SetEndOfFile( file );
517 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
518 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
519 ok( status == STATUS_SECTION_TOO_BIG, "%u: NtCreateSection failed err %lx\n", id, status );
521 map_size.QuadPart = 1;
522 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
523 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
524 ok( !status, "%u: NtCreateSection failed err %lx\n", id, status );
525 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
526 ok( !status, "NtQuerySection failed err %lx\n", status );
527 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %lx%08lx / %lx%08lx\n",
528 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
529 CloseHandle( mapping );
531 CloseHandle( file );
532 return image.ImageContainsCode && (!cor_header || !(cor_header->Flags & COMIMAGE_FLAGS_ILONLY));
535 static const WCHAR wldr_nameW[] = {'w','l','d','r','t','e','s','t','.','d','l','l',0};
536 static WCHAR load_test_name[MAX_PATH], load_fallback_name[MAX_PATH];
537 static WCHAR load_path[MAX_PATH];
539 static void init_load_path( const char *fallback_dll )
541 static const WCHAR pathW[] = {'P','A','T','H',0};
542 static const WCHAR ldrW[] = {'l','d','r',0};
543 static const WCHAR sepW[] = {';',0};
544 static const WCHAR bsW[] = {'\\',0};
545 WCHAR path[MAX_PATH];
547 GetTempPathW( MAX_PATH, path );
548 GetTempFileNameW( path, ldrW, 0, load_test_name );
549 GetTempFileNameW( path, ldrW, 0, load_fallback_name );
550 DeleteFileW( load_test_name );
551 ok( CreateDirectoryW( load_test_name, NULL ), "failed to create dir\n" );
552 DeleteFileW( load_fallback_name );
553 ok( CreateDirectoryW( load_fallback_name, NULL ), "failed to create dir\n" );
554 lstrcpyW( load_path, load_test_name );
555 lstrcatW( load_path, sepW );
556 lstrcatW( load_path, load_fallback_name );
557 lstrcatW( load_path, sepW );
558 GetEnvironmentVariableW( pathW, load_path + lstrlenW(load_path),
559 ARRAY_SIZE(load_path) - lstrlenW(load_path) );
560 lstrcatW( load_test_name, bsW );
561 lstrcatW( load_test_name, wldr_nameW );
562 lstrcatW( load_fallback_name, bsW );
563 lstrcatW( load_fallback_name, wldr_nameW );
564 MultiByteToWideChar( CP_ACP, 0, fallback_dll, -1, path, MAX_PATH );
565 MoveFileW( path, load_fallback_name );
568 static void delete_load_path(void)
570 WCHAR *p;
572 DeleteFileW( load_test_name );
573 for (p = load_test_name + lstrlenW(load_test_name) - 1; *p != '\\'; p--) ;
574 *p = 0;
575 RemoveDirectoryW( load_test_name );
576 DeleteFileW( load_fallback_name );
577 for (p = load_fallback_name + lstrlenW(load_fallback_name) - 1; *p != '\\'; p--) ;
578 *p = 0;
579 RemoveDirectoryW( load_fallback_name );
582 static UINT get_com_dir_size( const IMAGE_NT_HEADERS *nt )
584 if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
585 return ((const IMAGE_NT_HEADERS32 *)nt)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size;
586 else
587 return ((const IMAGE_NT_HEADERS64 *)nt)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size;
590 /* helper to test image section mapping */
591 static NTSTATUS map_image_section( const IMAGE_NT_HEADERS *nt_header, const IMAGE_SECTION_HEADER *sections,
592 const void *section_data, int line )
594 char dll_name[MAX_PATH];
595 WCHAR path[MAX_PATH];
596 UNICODE_STRING name;
597 LARGE_INTEGER size;
598 HANDLE file, map;
599 NTSTATUS status, expect_status, ldr_status;
600 ULONG file_size;
601 BOOL has_code = FALSE, il_only = FALSE, want_32bit = FALSE, expect_fallback = FALSE, wrong_machine = FALSE;
602 HMODULE mod = 0, ldr_mod;
604 file_size = create_test_dll_sections( &dos_header, nt_header, sections, section_data, dll_name );
606 file = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
607 ok(file != INVALID_HANDLE_VALUE, "CreateFile error %ld\n", GetLastError());
609 size.QuadPart = file_size;
610 status = pNtCreateSection(&map, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
611 NULL, &size, PAGE_READONLY, SEC_IMAGE, file );
612 expect_status = status;
614 if (get_com_dir_size( nt_header ))
616 /* invalid COR20 header seems to corrupt internal loader state on Windows */
617 if (get_com_dir_size( nt_header ) < sizeof(IMAGE_COR20_HEADER)) goto done;
618 if (!((const IMAGE_COR20_HEADER *)section_data)->Flags) goto done;
621 if (!status)
623 SECTION_BASIC_INFORMATION info;
624 SIZE_T info_size = 0xdeadbeef;
625 NTSTATUS ret = pNtQuerySection( map, SectionBasicInformation, &info, sizeof(info), &info_size );
626 ok( !ret, "NtQuerySection failed err %lx\n", ret );
627 ok( info_size == sizeof(info), "NtQuerySection wrong size %Iu\n", info_size );
628 ok( info.Attributes == (SEC_IMAGE | SEC_FILE), "NtQuerySection wrong attr %lx\n", info.Attributes );
629 ok( info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", info.BaseAddress );
630 ok( info.Size.QuadPart == file_size, "NtQuerySection wrong size %lx%08lx / %08lx\n",
631 info.Size.u.HighPart, info.Size.u.LowPart, file_size );
632 has_code = query_image_section( line, dll_name, nt_header, section_data );
634 if (get_com_dir_size( nt_header ))
636 const IMAGE_COR20_HEADER *cor_header = section_data;
637 il_only = (cor_header->Flags & COMIMAGE_FLAGS_ILONLY) != 0;
638 if (il_only) want_32bit = (cor_header->Flags & COMIMAGE_FLAGS_32BITREQUIRED) != 0;
641 SetLastError( 0xdeadbeef );
642 mod = LoadLibraryExA( dll_name, 0, DONT_RESOLVE_DLL_REFERENCES );
643 /* test loading dll of wrong 32/64 bitness */
644 if (nt_header->OptionalHeader.Magic == (is_win64 ? IMAGE_NT_OPTIONAL_HDR32_MAGIC
645 : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
647 if (!has_code && is_win64)
649 ok_(__FILE__,line)( mod != NULL || want_32bit || broken(il_only), /* <= win7 */
650 "loading failed err %lu\n", GetLastError() );
652 else
654 ok_(__FILE__, line)( !mod, "loading succeeded\n" );
655 ok_(__FILE__, line)( GetLastError() == ERROR_BAD_EXE_FORMAT, "wrong error %lu\n", GetLastError() );
656 if (nt_header_template.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64)
658 wrong_machine = TRUE;
659 expect_status = STATUS_INVALID_IMAGE_FORMAT;
663 else
665 wrong_machine = (nt_header->FileHeader.Machine == get_alt_machine( nt_header_template.FileHeader.Machine ));
667 ok( mod != NULL || broken(il_only) || /* <= win7 */
668 broken( wrong_machine ), /* win8 */
669 "%u: loading failed err %lu\n", line, GetLastError() );
671 if (mod) FreeLibrary( mod );
672 expect_fallback = !mod;
675 /* test fallback to another dll further in the load path */
677 MultiByteToWideChar( CP_ACP, 0, dll_name, -1, path, MAX_PATH );
678 CopyFileW( path, load_test_name, FALSE );
679 pRtlInitUnicodeString( &name, wldr_nameW );
680 ldr_status = pLdrLoadDll( load_path, 0, &name, &ldr_mod );
681 if (!ldr_status)
683 GetModuleFileNameW( ldr_mod, path, MAX_PATH );
684 if (!lstrcmpiW( path, load_test_name ))
686 if (!expect_status)
687 ok( !expect_fallback, "%u: got test dll but expected fallback\n", line );
688 else
689 ok( !expect_fallback, "%u: got test dll but expected failure %lx\n", line, expect_status );
691 else if (!lstrcmpiW( path, load_fallback_name ))
693 trace( "%u: loaded fallback\n", line );
694 ok( !expect_status, "%u: got fallback but expected failure %lx\n", line, expect_status );
695 ok( expect_fallback ||
696 /* win10 also falls back for 32-bit dll without code, even though it could be loaded */
697 (is_win64 && !has_code &&
698 nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC),
699 "%u: got fallback but expected test dll\n", line );
701 else ok( 0, "%u: got unexpected path %s instead of %s\n", line, wine_dbgstr_w(path), wine_dbgstr_w(load_test_name));
702 pLdrUnloadDll( ldr_mod );
704 else if (ldr_status == STATUS_DLL_INIT_FAILED ||
705 ldr_status == STATUS_ACCESS_VIOLATION ||
706 ldr_status == STATUS_ILLEGAL_INSTRUCTION)
708 /* some dlls with invalid entry point will crash, but this means we loaded the test dll */
709 ok( !expect_fallback, "%u: got test dll but expected fallback\n", line );
711 else
713 ok( ldr_status == expect_status ||
714 (wrong_machine && !expect_status && ldr_status == STATUS_INVALID_IMAGE_FORMAT) ||
715 broken(il_only && !expect_status && ldr_status == STATUS_INVALID_IMAGE_FORMAT) ||
716 broken(nt_header->Signature == IMAGE_OS2_SIGNATURE && ldr_status == STATUS_INVALID_IMAGE_NE_FORMAT),
717 "%u: wrong status %lx/%lx\n", line, ldr_status, expect_status );
718 ok( !expect_fallback || wrong_machine || broken(il_only),
719 "%u: failed with %lx expected fallback\n", line, ldr_status );
722 done:
723 if (map) CloseHandle( map );
724 CloseHandle( file );
725 DeleteFileA( dll_name );
726 return status;
730 static void test_Loader(void)
732 static const struct test_data
734 DWORD size_of_dos_header;
735 WORD number_of_sections, size_of_optional_header;
736 DWORD section_alignment, file_alignment;
737 DWORD size_of_image, size_of_headers;
738 DWORD errors[4]; /* 0 means LoadLibrary should succeed */
739 } td[] =
741 { sizeof(dos_header),
742 1, 0, 0, 0, 0, 0,
743 { ERROR_BAD_EXE_FORMAT }
745 { sizeof(dos_header),
746 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
747 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0xe00,
748 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
749 { ERROR_BAD_EXE_FORMAT } /* XP doesn't like too small image size */
751 { sizeof(dos_header),
752 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
753 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
754 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
755 { ERROR_SUCCESS }
757 { sizeof(dos_header),
758 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
759 0x1f00,
760 0x1000,
761 { ERROR_SUCCESS }
763 { sizeof(dos_header),
764 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x200,
765 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x200,
766 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
767 { ERROR_SUCCESS, ERROR_INVALID_ADDRESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
769 { sizeof(dos_header),
770 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x1000,
771 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
772 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
773 { ERROR_BAD_EXE_FORMAT } /* XP doesn't like alignments */
775 { sizeof(dos_header),
776 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
777 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
778 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
779 { ERROR_SUCCESS }
781 { sizeof(dos_header),
782 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
783 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
784 0x200,
785 { ERROR_SUCCESS }
787 /* Mandatory are all fields up to SizeOfHeaders, everything else
788 * is really optional (at least that's true for XP).
790 #if 0 /* 32-bit Windows 8 crashes inside of LoadLibrary */
791 { sizeof(dos_header),
792 1, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
793 sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER) + 0x10,
794 sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER),
795 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT, ERROR_INVALID_ADDRESS,
796 ERROR_NOACCESS }
798 #endif
799 { sizeof(dos_header),
800 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
801 0xd0, /* beyond of the end of file */
802 0xc0, /* beyond of the end of file */
803 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
805 { sizeof(dos_header),
806 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
807 0x1000,
809 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
811 { sizeof(dos_header),
812 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
815 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
817 #if 0 /* not power of 2 alignments need more test cases */
818 { sizeof(dos_header),
819 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x300, 0x300,
822 { ERROR_BAD_EXE_FORMAT } /* alignment is not power of 2 */
824 #endif
825 { sizeof(dos_header),
826 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 4, 4,
829 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
831 { sizeof(dos_header),
832 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 1, 1,
835 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
837 { sizeof(dos_header),
838 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
841 { ERROR_BAD_EXE_FORMAT } /* image size == 0 -> failure */
843 /* the following data mimics the PE image which upack creates */
844 { 0x10,
845 1, 0x148, 0x1000, 0x200,
846 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
847 0x200,
848 { ERROR_SUCCESS }
850 /* Minimal PE image that XP is able to load: 92 bytes */
851 { 0x04,
852 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum),
853 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
856 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
858 /* Minimal PE image initially created for Windows 7 and accepted from
859 * Vista up to Windows 10 1709 with some unexplained exceptions:
860 * 268 bytes
862 { 0x04,
863 0, 0xf0, /* optional header size just forces 0xf0 bytes to be written,
864 0 or another number don't change the behaviour, what really
865 matters is file size regardless of values in the headers */
866 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
867 0x40, /* minimal image size that Windows7 accepts */
869 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* rejected by win10 1809+ */
871 /* the following data mimics the PE image which 8k demos have */
872 { 0x04,
873 0, 0x08,
874 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
875 0x2000,
876 0x40,
877 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT }
880 int i;
881 DWORD file_size;
882 HANDLE h;
883 HMODULE hlib, hlib_as_data_file;
884 char dll_name[MAX_PATH];
885 SIZE_T size;
886 BOOL ret;
887 NTSTATUS status;
888 WORD orig_machine = nt_header_template.FileHeader.Machine;
889 IMAGE_NT_HEADERS nt_header;
890 IMAGE_COR20_HEADER cor_header;
892 /* prevent displaying of the "Unable to load this DLL" message box */
893 SetErrorMode(SEM_FAILCRITICALERRORS);
895 for (i = 0; i < ARRAY_SIZE(td); i++)
897 winetest_push_context("%d", i);
898 nt_header = nt_header_template;
899 nt_header.FileHeader.NumberOfSections = td[i].number_of_sections;
900 nt_header.FileHeader.SizeOfOptionalHeader = td[i].size_of_optional_header;
902 nt_header.OptionalHeader.SectionAlignment = td[i].section_alignment;
903 nt_header.OptionalHeader.FileAlignment = td[i].file_alignment;
904 nt_header.OptionalHeader.SizeOfImage = td[i].size_of_image;
905 nt_header.OptionalHeader.SizeOfHeaders = td[i].size_of_headers;
907 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
908 file_size = create_test_dll( &dos_header, td[i].size_of_dos_header, &nt_header, dll_name );
910 SetLastError(0xdeadbeef);
911 hlib = LoadLibraryA(dll_name);
912 if (hlib)
914 MEMORY_BASIC_INFORMATION info;
915 void *ptr;
917 ok( td[i].errors[0] == ERROR_SUCCESS, "should have failed\n" );
919 SetLastError(0xdeadbeef);
920 size = VirtualQuery(hlib, &info, sizeof(info));
921 ok(size == sizeof(info),
922 "%d: VirtualQuery error %ld\n", i, GetLastError());
923 ok(info.BaseAddress == hlib, "%p != %p\n", info.BaseAddress, hlib);
924 ok(info.AllocationBase == hlib, "%p != %p\n", info.AllocationBase, hlib);
925 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
926 ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "got %Ix != expected %x\n",
927 info.RegionSize, (UINT)ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
928 ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State);
929 if (nt_header.OptionalHeader.SectionAlignment < page_size)
930 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.Protect);
931 else
932 ok(info.Protect == PAGE_READONLY, "%lx != PAGE_READONLY\n", info.Protect);
933 ok(info.Type == SEC_IMAGE, "%lx != SEC_IMAGE\n", info.Type);
935 SetLastError(0xdeadbeef);
936 ptr = VirtualAlloc(hlib, page_size, MEM_COMMIT, info.Protect);
937 ok(!ptr, "VirtualAlloc should fail\n");
938 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
940 SetLastError(0xdeadbeef);
941 size = VirtualQuery((char *)hlib + info.RegionSize, &info, sizeof(info));
942 ok(size == sizeof(info), "VirtualQuery error %ld\n", GetLastError());
943 if (nt_header.OptionalHeader.SectionAlignment == page_size ||
944 nt_header.OptionalHeader.SectionAlignment == nt_header.OptionalHeader.FileAlignment)
946 ok(info.BaseAddress == (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "got %p != expected %p\n",
947 info.BaseAddress, (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
948 ok(info.AllocationBase == 0, "%p != 0\n", info.AllocationBase);
949 ok(info.AllocationProtect == 0, "%lx != 0\n", info.AllocationProtect);
950 /*ok(info.RegionSize == not_practical_value, "%d: %lx != not_practical_value\n", i, info.RegionSize);*/
951 ok(info.State == MEM_FREE, "%lx != MEM_FREE\n", info.State);
952 ok(info.Type == 0, "%lx != 0\n", info.Type);
953 ok(info.Protect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.Protect);
955 else
957 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.Protect);
958 ok(info.BaseAddress == hlib, "got %p != expected %p\n", info.BaseAddress, hlib);
959 ok(info.AllocationBase == hlib, "%p != %p\n", info.AllocationBase, hlib);
960 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
961 ok(info.RegionSize == ALIGN_SIZE(file_size, page_size), "got %Ix != expected %x\n",
962 info.RegionSize, (UINT)ALIGN_SIZE(file_size, page_size));
963 ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State);
964 ok(info.Protect == PAGE_READONLY, "%lx != PAGE_READONLY\n", info.Protect);
965 ok(info.Type == SEC_IMAGE, "%lx != SEC_IMAGE\n", info.Type);
968 /* header: check the zeroing of alignment */
969 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
971 const char *start;
973 start = (const char *)hlib + nt_header.OptionalHeader.SizeOfHeaders;
974 size = ALIGN_SIZE((ULONG_PTR)start, page_size) - (ULONG_PTR)start;
975 ok(!memcmp(start, filler, size), "header alignment is not cleared\n");
978 if (nt_header.FileHeader.NumberOfSections)
980 SetLastError(0xdeadbeef);
981 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
982 ok(size == sizeof(info),
983 "VirtualQuery error %ld\n", GetLastError());
984 if (nt_header.OptionalHeader.SectionAlignment < page_size)
986 ok(info.BaseAddress == hlib, "got %p != expected %p\n", info.BaseAddress, hlib);
987 ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "got %Ix != expected %x\n",
988 info.RegionSize, (UINT)ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
989 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.Protect);
991 else
993 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)hlib + section.VirtualAddress);
994 ok(info.RegionSize == ALIGN_SIZE(section.Misc.VirtualSize, page_size), "got %Ix != expected %x\n",
995 info.RegionSize, (UINT)ALIGN_SIZE(section.Misc.VirtualSize, page_size));
996 ok(info.Protect == PAGE_READONLY, "%lx != PAGE_READONLY\n", info.Protect);
998 ok(info.AllocationBase == hlib, "%p != %p\n", info.AllocationBase, hlib);
999 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1000 ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State);
1001 ok(info.Type == SEC_IMAGE, "%lx != SEC_IMAGE\n", info.Type);
1003 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
1004 ok(!memcmp((const char *)hlib + section.VirtualAddress + section.PointerToRawData, &nt_header, section.SizeOfRawData), "wrong section data\n");
1005 else
1006 ok(!memcmp((const char *)hlib + section.PointerToRawData, section_data, section.SizeOfRawData), "wrong section data\n");
1008 /* check the zeroing of alignment */
1009 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
1011 const char *start;
1013 start = (const char *)hlib + section.VirtualAddress + section.PointerToRawData + section.SizeOfRawData;
1014 size = ALIGN_SIZE((ULONG_PTR)start, page_size) - (ULONG_PTR)start;
1015 ok(memcmp(start, filler, size), "alignment should not be cleared\n");
1018 SetLastError(0xdeadbeef);
1019 ptr = VirtualAlloc((char *)hlib + section.VirtualAddress, page_size, MEM_COMMIT, info.Protect);
1020 ok(!ptr, "VirtualAlloc should fail\n");
1021 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_INVALID_ADDRESS,
1022 "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
1025 SetLastError(0xdeadbeef);
1026 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
1027 ok(hlib_as_data_file != 0, "LoadLibraryEx error %lu\n", GetLastError());
1028 ok(hlib_as_data_file == hlib, "hlib_as_file and hlib are different\n");
1030 SetLastError(0xdeadbeef);
1031 ret = FreeLibrary(hlib);
1032 ok(ret, "FreeLibrary error %ld\n", GetLastError());
1034 SetLastError(0xdeadbeef);
1035 hlib = GetModuleHandleA(dll_name);
1036 ok(hlib != 0, "GetModuleHandle error %lu\n", GetLastError());
1038 SetLastError(0xdeadbeef);
1039 ret = FreeLibrary(hlib_as_data_file);
1040 ok(ret, "FreeLibrary error %ld\n", GetLastError());
1042 hlib = GetModuleHandleA(dll_name);
1043 ok(!hlib, "GetModuleHandle should fail\n");
1045 SetLastError(0xdeadbeef);
1046 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
1047 ok(hlib_as_data_file != 0, "LoadLibraryEx error %lu\n", GetLastError());
1048 ok(((ULONG_PTR)hlib_as_data_file & 3) == 1, "hlib_as_data_file got %p\n", hlib_as_data_file);
1050 hlib = GetModuleHandleA(dll_name);
1051 ok(!hlib, "GetModuleHandle should fail\n");
1053 SetLastError(0xdeadbeef);
1054 h = CreateFileA( dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1055 ok( h != INVALID_HANDLE_VALUE, "open failed err %lu\n", GetLastError() );
1056 CloseHandle( h );
1058 SetLastError(0xdeadbeef);
1059 ret = FreeLibrary(hlib_as_data_file);
1060 ok(ret, "FreeLibrary error %ld\n", GetLastError());
1062 SetLastError(0xdeadbeef);
1063 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE);
1064 ok(hlib_as_data_file != 0, "LoadLibraryEx error %lu\n", GetLastError());
1066 SetLastError(0xdeadbeef);
1067 h = CreateFileA( dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1068 ok( h == INVALID_HANDLE_VALUE, "open succeeded\n" );
1069 ok( GetLastError() == ERROR_SHARING_VIOLATION, "wrong error %lu\n", GetLastError() );
1070 CloseHandle( h );
1072 SetLastError(0xdeadbeef);
1073 h = CreateFileA( dll_name, GENERIC_READ | DELETE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1074 ok( h != INVALID_HANDLE_VALUE, "open failed err %lu\n", GetLastError() );
1075 CloseHandle( h );
1077 SetLastError(0xdeadbeef);
1078 ret = FreeLibrary(hlib_as_data_file);
1079 ok(ret, "FreeLibrary error %ld\n", GetLastError());
1081 SetLastError(0xdeadbeef);
1082 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE);
1083 ok(hlib_as_data_file != 0, "LoadLibraryEx error %lu\n", GetLastError());
1084 ok(((ULONG_PTR)hlib_as_data_file & 3) == 2, "hlib_as_data_file got %p\n",
1085 hlib_as_data_file);
1087 hlib = GetModuleHandleA(dll_name);
1088 ok(!hlib, "GetModuleHandle should fail\n");
1090 SetLastError(0xdeadbeef);
1091 ret = FreeLibrary(hlib_as_data_file);
1092 ok(ret, "FreeLibrary error %ld\n", GetLastError());
1094 SetLastError(0xdeadbeef);
1095 ret = DeleteFileA(dll_name);
1096 ok(ret, "DeleteFile error %ld\n", GetLastError());
1098 nt_header.OptionalHeader.AddressOfEntryPoint = 0x12345678;
1099 file_size = create_test_dll( &dos_header, td[i].size_of_dos_header, &nt_header, dll_name );
1100 if (!file_size)
1102 ok(0, "could not create %s\n", dll_name);
1103 winetest_pop_context();
1104 break;
1107 query_image_section( i, dll_name, &nt_header, NULL );
1109 else
1111 BOOL error_match;
1112 int error_index;
1114 error_match = FALSE;
1115 for (error_index = 0;
1116 ! error_match && error_index < ARRAY_SIZE(td[i].errors);
1117 error_index++)
1119 error_match = td[i].errors[error_index] == GetLastError();
1121 ok(error_match, "unexpected error %ld\n", GetLastError());
1124 SetLastError(0xdeadbeef);
1125 ret = DeleteFileA(dll_name);
1126 ok(ret, "DeleteFile error %ld\n", GetLastError());
1127 winetest_pop_context();
1130 nt_header = nt_header_template;
1131 nt_header.FileHeader.NumberOfSections = 1;
1132 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1134 nt_header.OptionalHeader.SectionAlignment = page_size;
1135 nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
1136 nt_header.OptionalHeader.FileAlignment = page_size;
1137 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
1138 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
1140 section.SizeOfRawData = sizeof(section_data);
1141 section.PointerToRawData = page_size;
1142 section.VirtualAddress = page_size;
1143 section.Misc.VirtualSize = page_size;
1145 create_test_dll_sections( &dos_header, &nt_header, &section, section_data, dll_name );
1146 init_load_path( dll_name );
1148 nt_header.OptionalHeader.AddressOfEntryPoint = 0x1234;
1149 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1150 ok( status == (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_SUCCESS),
1151 "NtCreateSection error %08lx\n", status );
1153 nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
1154 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1155 ok( status == (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_SUCCESS),
1156 "NtCreateSection error %08lx\n", status );
1158 nt_header.OptionalHeader.SizeOfCode = 0x1000;
1159 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1160 ok( status == (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_SUCCESS),
1161 "NtCreateSection error %08lx\n", status );
1163 nt_header.OptionalHeader.SizeOfCode = 0;
1164 nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
1166 dos_header.e_magic = 0;
1167 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1168 ok( status == STATUS_INVALID_IMAGE_NOT_MZ, "NtCreateSection error %08lx\n", status );
1170 dos_header.e_magic = IMAGE_DOS_SIGNATURE;
1171 nt_header.Signature = IMAGE_OS2_SIGNATURE;
1172 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1173 ok( status == STATUS_INVALID_IMAGE_NE_FORMAT, "NtCreateSection error %08lx\n", status );
1174 for (i = 0; i < 16; i++)
1176 ((IMAGE_OS2_HEADER *)&nt_header)->ne_exetyp = i;
1177 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1178 switch (i)
1180 case 2:
1181 ok( status == STATUS_INVALID_IMAGE_WIN_16, "NtCreateSection %u error %08lx\n", i, status );
1182 break;
1183 case 5:
1184 ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection %u error %08lx\n", i, status );
1185 break;
1186 default:
1187 ok( status == STATUS_INVALID_IMAGE_NE_FORMAT, "NtCreateSection %u error %08lx\n", i, status );
1188 break;
1191 ((IMAGE_OS2_HEADER *)&nt_header)->ne_exetyp = ((IMAGE_OS2_HEADER *)&nt_header_template)->ne_exetyp;
1193 dos_header.e_lfanew = 0x98760000;
1194 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1195 ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection error %08lx\n", status );
1197 dos_header.e_lfanew = sizeof(dos_header);
1198 nt_header.Signature = 0xdeadbeef;
1199 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1200 ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection error %08lx\n", status );
1202 nt_header.Signature = IMAGE_NT_SIGNATURE;
1203 nt_header.OptionalHeader.Magic = 0xdead;
1204 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1205 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08lx\n", status );
1207 nt_header.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC;
1208 nt_header.FileHeader.Machine = 0xdead;
1209 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1210 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08lx\n", status );
1212 nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_UNKNOWN;
1213 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1214 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08lx\n", status );
1216 nt_header.FileHeader.Machine = get_alt_bitness_machine( orig_machine );
1217 status = map_image_section( &nt_header, &section, section_data, __LINE__ );
1218 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08lx\n", status );
1220 nt_header.FileHeader.Machine = orig_machine;
1221 nt_header.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
1222 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = page_size;
1223 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = sizeof(cor_header);
1224 section.SizeOfRawData = sizeof(cor_header);
1226 memset( &cor_header, 0, sizeof(cor_header) );
1227 cor_header.cb = sizeof(cor_header);
1228 cor_header.MajorRuntimeVersion = 2;
1229 cor_header.MinorRuntimeVersion = 4;
1230 cor_header.Flags = COMIMAGE_FLAGS_ILONLY;
1231 cor_header.EntryPointToken = 0xbeef;
1232 status = map_image_section( &nt_header, &section, &cor_header, __LINE__ );
1233 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1235 cor_header.MinorRuntimeVersion = 5;
1236 status = map_image_section( &nt_header, &section, &cor_header, __LINE__ );
1237 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1239 cor_header.MajorRuntimeVersion = 3;
1240 cor_header.MinorRuntimeVersion = 0;
1241 status = map_image_section( &nt_header, &section, &cor_header, __LINE__ );
1242 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1244 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITREQUIRED;
1245 status = map_image_section( &nt_header, &section, &cor_header, __LINE__ );
1246 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1248 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITPREFERRED;
1249 status = map_image_section( &nt_header, &section, &cor_header, __LINE__ );
1250 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1252 cor_header.Flags = 0;
1253 status = map_image_section( &nt_header, &section, &cor_header, __LINE__ );
1254 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1256 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = 1;
1257 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = 1;
1258 status = map_image_section( &nt_header, &section, &cor_header, __LINE__ );
1259 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1261 if (nt_header.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
1263 IMAGE_NT_HEADERS64 nt64;
1265 memset( &nt64, 0, sizeof(nt64) );
1266 nt64.Signature = IMAGE_NT_SIGNATURE;
1267 nt64.FileHeader.Machine = orig_machine;
1268 nt64.FileHeader.NumberOfSections = 1;
1269 nt64.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
1270 nt64.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL;
1271 nt64.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
1272 nt64.OptionalHeader.MajorLinkerVersion = 1;
1273 nt64.OptionalHeader.SizeOfCode = 0x1000;
1274 nt64.OptionalHeader.AddressOfEntryPoint = 0x1000;
1275 nt64.OptionalHeader.ImageBase = 0x10000000;
1276 nt64.OptionalHeader.SectionAlignment = 0x1000;
1277 nt64.OptionalHeader.FileAlignment = 0x1000;
1278 nt64.OptionalHeader.MajorOperatingSystemVersion = 4;
1279 nt64.OptionalHeader.MajorImageVersion = 1;
1280 nt64.OptionalHeader.MajorSubsystemVersion = 4;
1281 nt64.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt64) + sizeof(IMAGE_SECTION_HEADER);
1282 nt64.OptionalHeader.SizeOfImage = nt64.OptionalHeader.SizeOfHeaders + 0x1000;
1283 nt64.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
1284 nt64.OptionalHeader.SizeOfStackReserve = 0x321000;
1285 nt64.OptionalHeader.SizeOfStackCommit = 0x123000;
1286 section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
1288 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, section_data, __LINE__ );
1289 ok( status == (is_wow64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_INVALID_IMAGE_WIN_64),
1290 "NtCreateSection error %08lx\n", status );
1292 switch (orig_machine)
1294 case IMAGE_FILE_MACHINE_I386: nt64.FileHeader.Machine = IMAGE_FILE_MACHINE_ARM64; break;
1295 case IMAGE_FILE_MACHINE_ARMNT: nt64.FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64; break;
1297 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, section_data, __LINE__ );
1298 ok( status == (is_wow64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_INVALID_IMAGE_WIN_64),
1299 "NtCreateSection error %08lx\n", status );
1301 nt64.FileHeader.Machine = get_alt_bitness_machine( orig_machine );
1302 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, section_data, __LINE__ );
1303 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1304 "NtCreateSection error %08lx\n", status );
1306 nt64.OptionalHeader.SizeOfCode = 0;
1307 nt64.OptionalHeader.AddressOfEntryPoint = 0x1000;
1308 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1309 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, section_data, __LINE__ );
1310 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1311 "NtCreateSection error %08lx\n", status );
1313 nt64.OptionalHeader.SizeOfCode = 0;
1314 nt64.OptionalHeader.AddressOfEntryPoint = 0;
1315 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE;
1316 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, section_data, __LINE__ );
1317 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1318 "NtCreateSection error %08lx\n", status );
1320 nt64.OptionalHeader.SizeOfCode = 0x1000;
1321 nt64.OptionalHeader.AddressOfEntryPoint = 0;
1322 nt64.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
1323 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
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 %08lx\n", status );
1328 nt64.OptionalHeader.SizeOfCode = 0;
1329 nt64.OptionalHeader.AddressOfEntryPoint = 0;
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 %08lx\n", status );
1335 nt64.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
1336 nt64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = page_size;
1337 nt64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = sizeof(cor_header);
1338 cor_header.MajorRuntimeVersion = 2;
1339 cor_header.MinorRuntimeVersion = 4;
1340 cor_header.Flags = COMIMAGE_FLAGS_ILONLY;
1341 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, &cor_header, __LINE__ );
1342 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1343 "NtCreateSection error %08lx\n", status );
1345 nt64.OptionalHeader.SizeOfCode = 0x1000;
1346 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, &cor_header, __LINE__ );
1347 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1348 "NtCreateSection error %08lx\n", status );
1350 cor_header.MinorRuntimeVersion = 5;
1351 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, &cor_header, __LINE__ );
1352 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1353 "NtCreateSection error %08lx\n", status );
1355 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITREQUIRED;
1356 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, &cor_header, __LINE__ );
1357 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1358 "NtCreateSection error %08lx\n", status );
1360 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITPREFERRED;
1361 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, &cor_header, __LINE__ );
1362 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1363 "NtCreateSection error %08lx\n", status );
1365 cor_header.Flags = 0;
1366 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, &cor_header, __LINE__ );
1367 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1368 "NtCreateSection error %08lx\n", status );
1370 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = 1;
1371 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = 1;
1372 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, &section, &cor_header, __LINE__ );
1373 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1374 "NtCreateSection error %08lx\n", status );
1376 else
1378 IMAGE_NT_HEADERS32 nt32;
1380 memset( &nt32, 0, sizeof(nt32) );
1381 nt32.Signature = IMAGE_NT_SIGNATURE;
1382 nt32.FileHeader.Machine = orig_machine;
1383 nt32.FileHeader.NumberOfSections = 1;
1384 nt32.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32);
1385 nt32.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL;
1386 nt32.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
1387 nt32.OptionalHeader.MajorLinkerVersion = 1;
1388 nt32.OptionalHeader.SizeOfCode = 0x1000;
1389 nt32.OptionalHeader.AddressOfEntryPoint = 0x1000;
1390 nt32.OptionalHeader.ImageBase = 0x10000000;
1391 nt32.OptionalHeader.SectionAlignment = 0x1000;
1392 nt32.OptionalHeader.FileAlignment = 0x1000;
1393 nt32.OptionalHeader.MajorOperatingSystemVersion = 4;
1394 nt32.OptionalHeader.MajorImageVersion = 1;
1395 nt32.OptionalHeader.MajorSubsystemVersion = 4;
1396 nt32.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt32) + sizeof(IMAGE_SECTION_HEADER);
1397 nt32.OptionalHeader.SizeOfImage = nt32.OptionalHeader.SizeOfHeaders + 0x1000;
1398 nt32.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
1399 nt32.OptionalHeader.SizeOfStackReserve = 0x321000;
1400 nt32.OptionalHeader.SizeOfStackCommit = 0x123000;
1401 section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
1403 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, section_data, __LINE__ );
1404 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08lx\n", status );
1406 if (orig_machine == IMAGE_FILE_MACHINE_AMD64)
1408 nt32.FileHeader.Machine = IMAGE_FILE_MACHINE_ARMNT;
1409 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, section_data, __LINE__ );
1410 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(!status) /* win8 */,
1411 "NtCreateSection error %08lx\n", status );
1414 nt32.FileHeader.Machine = IMAGE_FILE_MACHINE_I386;
1415 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, section_data, __LINE__ );
1416 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1418 nt32.OptionalHeader.SizeOfCode = 0;
1419 nt32.OptionalHeader.AddressOfEntryPoint = 0x1000;
1420 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1421 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, section_data, __LINE__ );
1422 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1424 nt32.OptionalHeader.SizeOfCode = 0;
1425 nt32.OptionalHeader.AddressOfEntryPoint = 0;
1426 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE;
1427 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, section_data, __LINE__ );
1428 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1430 nt32.OptionalHeader.SizeOfCode = 0x1000;
1431 nt32.OptionalHeader.AddressOfEntryPoint = 0;
1432 nt32.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
1433 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1434 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, section_data, __LINE__ );
1435 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1437 nt32.OptionalHeader.SizeOfCode = 0;
1438 nt32.OptionalHeader.AddressOfEntryPoint = 0;
1439 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1440 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, section_data, __LINE__ );
1441 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1443 nt32.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
1444 nt32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = page_size;
1445 nt32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = sizeof(cor_header);
1446 cor_header.MajorRuntimeVersion = 2;
1447 cor_header.MinorRuntimeVersion = 4;
1448 cor_header.Flags = COMIMAGE_FLAGS_ILONLY;
1449 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, &cor_header, __LINE__ );
1450 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1452 nt32.OptionalHeader.SizeOfCode = 0x1000;
1453 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, &cor_header, __LINE__ );
1454 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1456 cor_header.MinorRuntimeVersion = 5;
1457 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, &cor_header, __LINE__ );
1458 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1460 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITREQUIRED;
1461 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, &cor_header, __LINE__ );
1462 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1464 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITPREFERRED;
1465 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, &cor_header, __LINE__ );
1466 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1468 cor_header.Flags = 0;
1469 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, &cor_header, __LINE__ );
1470 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1472 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = 1;
1473 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = 1;
1474 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, &section, &cor_header, __LINE__ );
1475 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1478 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
1479 delete_load_path();
1482 static void test_filenames(void)
1484 IMAGE_NT_HEADERS nt_header = nt_header_template;
1485 char dll_name[MAX_PATH], long_path[MAX_PATH], short_path[MAX_PATH], buffer[MAX_PATH];
1486 HMODULE mod, mod2;
1487 BOOL ret;
1489 nt_header.FileHeader.NumberOfSections = 1;
1490 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1492 nt_header.OptionalHeader.SectionAlignment = page_size;
1493 nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
1494 nt_header.OptionalHeader.FileAlignment = page_size;
1495 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
1496 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
1498 create_test_dll( &dos_header, sizeof(dos_header), &nt_header, dll_name );
1499 strcpy( long_path, dll_name );
1500 strcpy( strrchr( long_path, '\\' ), "\\this-is-a-long-name.dll" );
1501 ret = MoveFileA( dll_name, long_path );
1502 ok( ret, "MoveFileA failed err %lu\n", GetLastError() );
1503 GetShortPathNameA( long_path, short_path, MAX_PATH );
1505 mod = LoadLibraryA( short_path );
1506 ok( mod != NULL, "loading failed err %lu\n", GetLastError() );
1507 GetModuleFileNameA( mod, buffer, MAX_PATH );
1508 ok( !lstrcmpiA( buffer, short_path ), "got wrong path %s / %s\n", buffer, short_path );
1509 mod2 = GetModuleHandleA( short_path );
1510 ok( mod == mod2, "wrong module %p for %s\n", mod2, short_path );
1511 mod2 = GetModuleHandleA( long_path );
1512 ok( mod == mod2, "wrong module %p for %s\n", mod2, long_path );
1513 mod2 = LoadLibraryA( long_path );
1514 ok( mod2 != NULL, "loading failed err %lu\n", GetLastError() );
1515 ok( mod == mod2, "library loaded twice\n" );
1516 GetModuleFileNameA( mod2, buffer, MAX_PATH );
1517 ok( !lstrcmpiA( buffer, short_path ), "got wrong path %s / %s\n", buffer, short_path );
1518 FreeLibrary( mod2 );
1519 FreeLibrary( mod );
1521 mod = LoadLibraryA( long_path );
1522 ok( mod != NULL, "loading failed err %lu\n", GetLastError() );
1523 GetModuleFileNameA( mod, buffer, MAX_PATH );
1524 ok( !lstrcmpiA( buffer, long_path ), "got wrong path %s / %s\n", buffer, long_path );
1525 mod2 = GetModuleHandleA( short_path );
1526 ok( mod == mod2, "wrong module %p for %s\n", mod2, short_path );
1527 mod2 = GetModuleHandleA( long_path );
1528 ok( mod == mod2, "wrong module %p for %s\n", mod2, long_path );
1529 mod2 = LoadLibraryA( short_path );
1530 ok( mod2 != NULL, "loading failed err %lu\n", GetLastError() );
1531 ok( mod == mod2, "library loaded twice\n" );
1532 GetModuleFileNameA( mod2, buffer, MAX_PATH );
1533 ok( !lstrcmpiA( buffer, long_path ), "got wrong path %s / %s\n", buffer, long_path );
1534 FreeLibrary( mod2 );
1535 FreeLibrary( mod );
1537 strcpy( dll_name, long_path );
1538 strcpy( strrchr( dll_name, '\\' ), "\\this-is-another-name.dll" );
1539 ret = CreateHardLinkA( dll_name, long_path, NULL );
1540 ok( ret, "CreateHardLinkA failed err %lu\n", GetLastError() );
1541 if (ret)
1543 mod = LoadLibraryA( dll_name );
1544 ok( mod != NULL, "loading failed err %lu\n", GetLastError() );
1545 GetModuleFileNameA( mod, buffer, MAX_PATH );
1546 ok( !lstrcmpiA( buffer, dll_name ), "got wrong path %s / %s\n", buffer, dll_name );
1547 mod2 = GetModuleHandleA( long_path );
1548 ok( mod == mod2, "wrong module %p for %s\n", mod2, long_path );
1549 mod2 = LoadLibraryA( long_path );
1550 ok( mod2 != NULL, "loading failed err %lu\n", GetLastError() );
1551 ok( mod == mod2, "library loaded twice\n" );
1552 GetModuleFileNameA( mod2, buffer, MAX_PATH );
1553 ok( !lstrcmpiA( buffer, dll_name ), "got wrong path %s / %s\n", buffer, short_path );
1554 FreeLibrary( mod2 );
1555 FreeLibrary( mod );
1556 DeleteFileA( dll_name );
1558 DeleteFileA( long_path );
1561 /* Verify linking style of import descriptors */
1562 static void test_ImportDescriptors(void)
1564 HMODULE kernel32_module = NULL;
1565 PIMAGE_DOS_HEADER d_header;
1566 PIMAGE_NT_HEADERS nt_headers;
1567 DWORD import_dir_size;
1568 DWORD_PTR dir_offset;
1569 PIMAGE_IMPORT_DESCRIPTOR import_chunk;
1571 /* Load kernel32 module */
1572 kernel32_module = GetModuleHandleA("kernel32.dll");
1573 assert( kernel32_module != NULL );
1575 /* Get PE header info from module image */
1576 d_header = (PIMAGE_DOS_HEADER) kernel32_module;
1577 nt_headers = (PIMAGE_NT_HEADERS) (((char*) d_header) +
1578 d_header->e_lfanew);
1580 /* Get size of import entry directory */
1581 import_dir_size = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
1582 if (!import_dir_size)
1584 skip("Unable to continue testing due to missing import directory.\n");
1585 return;
1588 /* Get address of first import chunk */
1589 dir_offset = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
1590 import_chunk = RVAToAddr(dir_offset, kernel32_module);
1591 ok(import_chunk != 0, "Invalid import_chunk: %p\n", import_chunk);
1592 if (!import_chunk) return;
1594 /* Iterate through import descriptors and verify set name,
1595 * OriginalFirstThunk, and FirstThunk. Core Windows DLLs, such as
1596 * kernel32.dll, don't use Borland-style linking, where the table of
1597 * imported names is stored directly in FirstThunk and overwritten
1598 * by the relocation, instead of being stored in OriginalFirstThunk.
1599 * */
1600 for (; import_chunk->FirstThunk; import_chunk++)
1602 LPCSTR module_name = RVAToAddr(import_chunk->Name, kernel32_module);
1603 PIMAGE_THUNK_DATA name_table = RVAToAddr(
1604 import_chunk->OriginalFirstThunk, kernel32_module);
1605 PIMAGE_THUNK_DATA iat = RVAToAddr(
1606 import_chunk->FirstThunk, kernel32_module);
1607 ok(module_name != NULL, "Imported module name should not be NULL\n");
1608 ok(name_table != NULL,
1609 "Name table for imported module %s should not be NULL\n",
1610 module_name);
1611 ok(iat != NULL, "IAT for imported module %s should not be NULL\n",
1612 module_name);
1616 static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL is_dll)
1618 HANDLE hfile, hmap;
1619 NTSTATUS status;
1620 LARGE_INTEGER offset;
1621 SIZE_T size;
1622 void *addr1, *addr2;
1623 MEMORY_BASIC_INFORMATION info;
1625 if (!pNtMapViewOfSection) return;
1627 SetLastError(0xdeadbeef);
1628 hfile = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
1629 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile error %ld\n", GetLastError());
1631 SetLastError(0xdeadbeef);
1632 hmap = CreateFileMappingW(hfile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, 0);
1633 ok(hmap != 0, "CreateFileMapping error %ld\n", GetLastError());
1635 offset.u.LowPart = 0;
1636 offset.u.HighPart = 0;
1638 addr1 = NULL;
1639 size = 0;
1640 status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr1, 0, 0, &offset,
1641 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1642 ok(NT_SUCCESS(status), "NtMapViewOfSection error %lx\n", status);
1643 ok(addr1 != 0, "mapped address should be valid\n");
1645 SetLastError(0xdeadbeef);
1646 size = VirtualQuery((char *)addr1 + section.VirtualAddress, &info, sizeof(info));
1647 ok(size == sizeof(info), "VirtualQuery error %ld\n", GetLastError());
1648 ok(info.BaseAddress == (char *)addr1 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr1 + section.VirtualAddress);
1649 ok(info.RegionSize == page_size, "got %#Ix != expected %#lx\n", info.RegionSize, page_size);
1650 ok(info.Protect == scn_page_access, "got %#lx != expected %#lx\n", info.Protect, scn_page_access);
1651 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1652 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1653 ok(info.State == MEM_COMMIT, "%#lx != MEM_COMMIT\n", info.State);
1654 ok(info.Type == SEC_IMAGE, "%#lx != SEC_IMAGE\n", info.Type);
1656 addr2 = NULL;
1657 size = 0;
1658 status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr2, 0, 0, &offset,
1659 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1660 ok(status == STATUS_IMAGE_NOT_AT_BASE, "expected STATUS_IMAGE_NOT_AT_BASE, got %lx\n", status);
1661 ok(addr2 != 0, "mapped address should be valid\n");
1662 ok(addr2 != addr1, "mapped addresses should be different\n");
1664 SetLastError(0xdeadbeef);
1665 size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info));
1666 ok(size == sizeof(info), "VirtualQuery error %ld\n", GetLastError());
1667 ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress);
1668 ok(info.RegionSize == page_size, "got %#Ix != expected %#lx\n", info.RegionSize, page_size);
1669 ok(info.Protect == scn_page_access, "got %#lx != expected %#lx\n", info.Protect, scn_page_access);
1670 ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2);
1671 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1672 ok(info.State == MEM_COMMIT, "%#lx != MEM_COMMIT\n", info.State);
1673 ok(info.Type == SEC_IMAGE, "%#lx != SEC_IMAGE\n", info.Type);
1675 status = pNtUnmapViewOfSection(GetCurrentProcess(), addr2);
1676 ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %lx\n", status);
1678 addr2 = MapViewOfFile(hmap, 0, 0, 0, 0);
1679 ok(addr2 != 0, "mapped address should be valid\n");
1680 ok(addr2 != addr1, "mapped addresses should be different\n");
1682 SetLastError(0xdeadbeef);
1683 size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info));
1684 ok(size == sizeof(info), "VirtualQuery error %ld\n", GetLastError());
1685 ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress);
1686 ok(info.RegionSize == page_size, "got %#Ix != expected %#lx\n", info.RegionSize, page_size);
1687 ok(info.Protect == scn_page_access, "got %#lx != expected %#lx\n", info.Protect, scn_page_access);
1688 ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2);
1689 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1690 ok(info.State == MEM_COMMIT, "%#lx != MEM_COMMIT\n", info.State);
1691 ok(info.Type == SEC_IMAGE, "%#lx != SEC_IMAGE\n", info.Type);
1693 UnmapViewOfFile(addr2);
1695 SetLastError(0xdeadbeef);
1696 addr2 = LoadLibraryA(dll_name);
1697 if (!addr2)
1699 ok(is_dll, "LoadLibrary should fail, is_dll %d\n", is_dll);
1700 ok(GetLastError() == ERROR_INVALID_ADDRESS, "expected ERROR_INVALID_ADDRESS, got %ld\n", GetLastError());
1702 else
1704 BOOL ret;
1705 ok(addr2 != 0, "LoadLibrary error %ld, is_dll %d\n", GetLastError(), is_dll);
1706 ok(addr2 != addr1, "mapped addresses should be different\n");
1708 SetLastError(0xdeadbeef);
1709 ret = FreeLibrary(addr2);
1710 ok(ret, "FreeLibrary error %ld\n", GetLastError());
1713 status = pNtUnmapViewOfSection(GetCurrentProcess(), addr1);
1714 ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %lx\n", status);
1716 CloseHandle(hmap);
1717 CloseHandle(hfile);
1720 static BOOL is_mem_writable(DWORD prot)
1722 switch (prot & 0xff)
1724 case PAGE_READWRITE:
1725 case PAGE_WRITECOPY:
1726 case PAGE_EXECUTE_READWRITE:
1727 case PAGE_EXECUTE_WRITECOPY:
1728 return TRUE;
1730 default:
1731 return FALSE;
1735 static void test_VirtualProtect(void *base, void *section)
1737 static const struct test_data
1739 DWORD prot_set, prot_get;
1740 } td[] =
1742 { 0, 0 }, /* 0x00 */
1743 { PAGE_NOACCESS, PAGE_NOACCESS }, /* 0x01 */
1744 { PAGE_READONLY, PAGE_READONLY }, /* 0x02 */
1745 { PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x03 */
1746 { PAGE_READWRITE, PAGE_WRITECOPY }, /* 0x04 */
1747 { PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x05 */
1748 { PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x06 */
1749 { PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x07 */
1750 { PAGE_WRITECOPY, PAGE_WRITECOPY }, /* 0x08 */
1751 { PAGE_WRITECOPY | PAGE_NOACCESS, 0 }, /* 0x09 */
1752 { PAGE_WRITECOPY | PAGE_READONLY, 0 }, /* 0x0a */
1753 { PAGE_WRITECOPY | PAGE_NOACCESS | PAGE_READONLY, 0 }, /* 0x0b */
1754 { PAGE_WRITECOPY | PAGE_READWRITE, 0 }, /* 0x0c */
1755 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x0d */
1756 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x0e */
1757 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x0f */
1759 { PAGE_EXECUTE, PAGE_EXECUTE }, /* 0x10 */
1760 { PAGE_EXECUTE_READ, PAGE_EXECUTE_READ }, /* 0x20 */
1761 { PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x30 */
1762 { PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY }, /* 0x40 */
1763 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0x50 */
1764 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0x60 */
1765 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x70 */
1766 { PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_WRITECOPY }, /* 0x80 */
1767 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE, 0 }, /* 0x90 */
1768 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ, 0 }, /* 0xa0 */
1769 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0xb0 */
1770 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE, 0 }, /* 0xc0 */
1771 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0xd0 */
1772 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0xe0 */
1773 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 } /* 0xf0 */
1775 DWORD ret, orig_prot, old_prot, rw_prot, exec_prot, i, j;
1776 MEMORY_BASIC_INFORMATION info;
1778 SetLastError(0xdeadbeef);
1779 ret = VirtualProtect(section, page_size, PAGE_NOACCESS, &old_prot);
1780 ok(ret, "VirtualProtect error %ld\n", GetLastError());
1782 orig_prot = old_prot;
1784 for (i = 0; i < ARRAY_SIZE(td); i++)
1786 SetLastError(0xdeadbeef);
1787 ret = VirtualQuery(section, &info, sizeof(info));
1788 ok(ret, "VirtualQuery failed %ld\n", GetLastError());
1789 ok(info.BaseAddress == section, "%ld: got %p != expected %p\n", i, info.BaseAddress, section);
1790 ok(info.RegionSize == page_size, "%ld: got %#Ix != expected %#lx\n", i, info.RegionSize, page_size);
1791 ok(info.Protect == PAGE_NOACCESS, "%ld: got %#lx != expected PAGE_NOACCESS\n", i, info.Protect);
1792 ok(info.AllocationBase == base, "%ld: %p != %p\n", i, info.AllocationBase, base);
1793 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%ld: %#lx != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1794 ok(info.State == MEM_COMMIT, "%ld: %#lx != MEM_COMMIT\n", i, info.State);
1795 ok(info.Type == SEC_IMAGE, "%ld: %#lx != SEC_IMAGE\n", i, info.Type);
1797 old_prot = 0xdeadbeef;
1798 SetLastError(0xdeadbeef);
1799 ret = VirtualProtect(section, page_size, td[i].prot_set, &old_prot);
1800 if (td[i].prot_get)
1802 ok(ret, "%ld: VirtualProtect error %ld, requested prot %#lx\n", i, GetLastError(), td[i].prot_set);
1803 ok(old_prot == PAGE_NOACCESS, "%ld: got %#lx != expected PAGE_NOACCESS\n", i, old_prot);
1805 SetLastError(0xdeadbeef);
1806 ret = VirtualQuery(section, &info, sizeof(info));
1807 ok(ret, "VirtualQuery failed %ld\n", GetLastError());
1808 ok(info.BaseAddress == section, "%ld: got %p != expected %p\n", i, info.BaseAddress, section);
1809 ok(info.RegionSize == page_size, "%ld: got %#Ix != expected %#lx\n", i, info.RegionSize, page_size);
1810 ok(info.Protect == td[i].prot_get, "%ld: got %#lx != expected %#lx\n", i, info.Protect, td[i].prot_get);
1811 ok(info.AllocationBase == base, "%ld: %p != %p\n", i, info.AllocationBase, base);
1812 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%ld: %#lx != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1813 ok(info.State == MEM_COMMIT, "%ld: %#lx != MEM_COMMIT\n", i, info.State);
1814 ok(info.Type == SEC_IMAGE, "%ld: %#lx != SEC_IMAGE\n", i, info.Type);
1816 else
1818 ok(!ret, "%ld: VirtualProtect should fail\n", i);
1819 ok(GetLastError() == ERROR_INVALID_PARAMETER, "%ld: expected ERROR_INVALID_PARAMETER, got %ld\n", i, GetLastError());
1822 old_prot = 0xdeadbeef;
1823 SetLastError(0xdeadbeef);
1824 ret = VirtualProtect(section, page_size, PAGE_NOACCESS, &old_prot);
1825 ok(ret, "%ld: VirtualProtect error %ld\n", i, GetLastError());
1826 if (td[i].prot_get)
1827 ok(old_prot == td[i].prot_get, "%ld: got %#lx != expected %#lx\n", i, old_prot, td[i].prot_get);
1828 else
1829 ok(old_prot == PAGE_NOACCESS, "%ld: got %#lx != expected PAGE_NOACCESS\n", i, old_prot);
1832 exec_prot = 0;
1834 for (i = 0; i <= 4; i++)
1836 rw_prot = 0;
1838 for (j = 0; j <= 4; j++)
1840 DWORD prot = exec_prot | rw_prot;
1842 SetLastError(0xdeadbeef);
1843 ret = VirtualProtect(section, page_size, prot, &old_prot);
1844 if ((rw_prot && exec_prot) || (!rw_prot && !exec_prot))
1846 ok(!ret, "VirtualProtect(%02lx) should fail\n", prot);
1847 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
1849 else
1850 ok(ret, "VirtualProtect(%02lx) error %ld\n", prot, GetLastError());
1852 rw_prot = 1 << j;
1855 exec_prot = 1 << (i + 4);
1858 SetLastError(0xdeadbeef);
1859 ret = VirtualProtect(section, page_size, orig_prot, &old_prot);
1860 ok(ret, "VirtualProtect error %ld\n", GetLastError());
1863 static void test_section_access(void)
1865 static const struct test_data
1867 DWORD scn_file_access, scn_page_access, scn_page_access_after_write;
1868 } td[] =
1870 { 0, PAGE_NOACCESS, 0 },
1871 { IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1872 { IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1873 { IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1874 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1875 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ },
1876 { IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1877 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1879 { IMAGE_SCN_CNT_INITIALIZED_DATA, PAGE_NOACCESS, 0 },
1880 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1881 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1882 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1883 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1884 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
1885 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1886 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1888 { IMAGE_SCN_CNT_UNINITIALIZED_DATA, PAGE_NOACCESS, 0 },
1889 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1890 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1891 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1892 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1893 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
1894 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1895 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE }
1897 char buf[256];
1898 int i;
1899 DWORD dummy;
1900 HANDLE hfile;
1901 HMODULE hlib;
1902 char temp_path[MAX_PATH];
1903 char dll_name[MAX_PATH];
1904 SIZE_T size;
1905 PEB child_peb;
1906 PROCESS_BASIC_INFORMATION pbi;
1907 SECTION_IMAGE_INFORMATION image_info;
1908 MEMORY_BASIC_INFORMATION info;
1909 STARTUPINFOA sti;
1910 PROCESS_INFORMATION pi;
1911 NTSTATUS status;
1912 DWORD ret;
1914 /* prevent displaying of the "Unable to load this DLL" message box */
1915 SetErrorMode(SEM_FAILCRITICALERRORS);
1917 GetTempPathA(MAX_PATH, temp_path);
1919 for (i = 0; i < ARRAY_SIZE(td); i++)
1921 IMAGE_NT_HEADERS nt_header;
1923 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
1925 /*trace("creating %s\n", dll_name);*/
1926 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
1927 if (hfile == INVALID_HANDLE_VALUE)
1929 ok(0, "could not create %s\n", dll_name);
1930 return;
1933 SetLastError(0xdeadbeef);
1934 ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
1935 ok(ret, "WriteFile error %ld\n", GetLastError());
1937 nt_header = nt_header_template;
1938 nt_header.OptionalHeader.SectionAlignment = page_size;
1939 nt_header.OptionalHeader.FileAlignment = 0x200;
1940 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
1941 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
1943 section.SizeOfRawData = sizeof(section_data);
1944 section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
1945 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
1946 section.Misc.VirtualSize = section.SizeOfRawData;
1947 section.Characteristics = td[i].scn_file_access;
1948 SetLastError(0xdeadbeef);
1950 SetLastError(0xdeadbeef);
1951 ret = WriteFile(hfile, &nt_header, sizeof(nt_header), &dummy, NULL);
1952 ok(ret, "WriteFile error %ld\n", GetLastError());
1954 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
1955 ok(ret, "WriteFile error %ld\n", GetLastError());
1957 /* section data */
1958 SetFilePointer( hfile, nt_header.OptionalHeader.FileAlignment, NULL, FILE_BEGIN );
1959 SetLastError(0xdeadbeef);
1960 ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
1961 ok(ret, "WriteFile error %ld\n", GetLastError());
1963 CloseHandle(hfile);
1964 SetLastError(0xdeadbeef);
1965 hlib = LoadLibraryExA(dll_name, NULL, DONT_RESOLVE_DLL_REFERENCES);
1966 ok(hlib != 0, "LoadLibrary error %ld\n", GetLastError());
1968 SetLastError(0xdeadbeef);
1969 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
1970 ok(size == sizeof(info),
1971 "%d: VirtualQuery error %ld\n", i, GetLastError());
1972 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
1973 ok(info.RegionSize == page_size, "%d: got %#Ix != expected %#lx\n", i, info.RegionSize, page_size);
1974 ok(info.Protect == td[i].scn_page_access, "%d: got %#lx != expected %#lx\n", i, info.Protect, td[i].scn_page_access);
1975 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
1976 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#lx != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1977 ok(info.State == MEM_COMMIT, "%d: %#lx != MEM_COMMIT\n", i, info.State);
1978 ok(info.Type == SEC_IMAGE, "%d: %#lx != SEC_IMAGE\n", i, info.Type);
1979 if (info.Protect != PAGE_NOACCESS)
1980 ok(!memcmp((const char *)info.BaseAddress, section_data, section.SizeOfRawData), "wrong section data\n");
1982 test_VirtualProtect(hlib, (char *)hlib + section.VirtualAddress);
1984 /* Windows changes the WRITECOPY to WRITE protection on an image section write (for a changed page only) */
1985 if (is_mem_writable(info.Protect))
1987 char *p = info.BaseAddress;
1988 *p = 0xfe;
1989 SetLastError(0xdeadbeef);
1990 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
1991 ok(size == sizeof(info), "%d: VirtualQuery error %ld\n", i, GetLastError());
1992 /* FIXME: remove the condition below once Wine is fixed */
1993 todo_wine_if (info.Protect == PAGE_WRITECOPY || info.Protect == PAGE_EXECUTE_WRITECOPY)
1994 ok(info.Protect == td[i].scn_page_access_after_write, "%d: got %#lx != expected %#lx\n", i, info.Protect, td[i].scn_page_access_after_write);
1997 SetLastError(0xdeadbeef);
1998 ret = FreeLibrary(hlib);
1999 ok(ret, "FreeLibrary error %ld\n", GetLastError());
2001 test_image_mapping(dll_name, td[i].scn_page_access, TRUE);
2003 /* reset IMAGE_FILE_DLL otherwise CreateProcess fails */
2004 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
2005 SetLastError(0xdeadbeef);
2006 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2007 /* LoadLibrary called on an already memory-mapped file in
2008 * test_image_mapping() above leads to a file handle leak
2009 * under nt4, and inability to overwrite and delete the file
2010 * due to sharing violation error. Ignore it and skip the test,
2011 * but leave a not deletable temporary file.
2013 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile error %ld\n", GetLastError());
2014 SetFilePointer(hfile, sizeof(dos_header), NULL, FILE_BEGIN);
2015 SetLastError(0xdeadbeef);
2016 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
2017 ok(ret, "WriteFile error %ld\n", GetLastError());
2018 CloseHandle(hfile);
2020 memset(&sti, 0, sizeof(sti));
2021 sti.cb = sizeof(sti);
2022 SetLastError(0xdeadbeef);
2023 ret = CreateProcessA(dll_name, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &sti, &pi);
2024 ok(ret, "CreateProcess() error %ld\n", GetLastError());
2026 status = pNtQueryInformationProcess( pi.hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL );
2027 ok( !status, "ProcessBasicInformation got %lx\n", status );
2028 ret = ReadProcessMemory( pi.hProcess, pbi.PebBaseAddress, &child_peb, sizeof(child_peb), NULL );
2029 ok( ret, "ReadProcessMemory failed err %lu\n", GetLastError() );
2030 hlib = child_peb.ImageBaseAddress;
2032 SetLastError(0xdeadbeef);
2033 size = VirtualQueryEx(pi.hProcess, (char *)hlib + section.VirtualAddress, &info, sizeof(info));
2034 ok(size == sizeof(info),
2035 "%d: VirtualQuery error %ld\n", i, GetLastError());
2036 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
2037 ok(info.RegionSize == page_size, "%d: got %#Ix != expected %#lx\n", i, info.RegionSize, page_size);
2038 ok(info.Protect == td[i].scn_page_access, "%d: got %#lx != expected %#lx\n", i, info.Protect, td[i].scn_page_access);
2039 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
2040 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#lx != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
2041 ok(info.State == MEM_COMMIT, "%d: %#lx != MEM_COMMIT\n", i, info.State);
2042 ok(info.Type == SEC_IMAGE, "%d: %#lx != SEC_IMAGE\n", i, info.Type);
2043 if (info.Protect != PAGE_NOACCESS)
2045 SetLastError(0xdeadbeef);
2046 ret = ReadProcessMemory(pi.hProcess, info.BaseAddress, buf, section.SizeOfRawData, NULL);
2047 ok(ret, "ReadProcessMemory() error %ld\n", GetLastError());
2048 ok(!memcmp(buf, section_data, section.SizeOfRawData), "wrong section data\n");
2051 status = NtQueryInformationProcess(pi.hProcess, ProcessImageInformation,
2052 &image_info, sizeof(image_info), NULL );
2053 ok(!status, "Got unexpected status %#lx.\n", status);
2054 ok(!(image_info.ImageCharacteristics & IMAGE_FILE_DLL),
2055 "Got unexpected characteristics %#x.\n", nt_header.FileHeader.Characteristics);
2056 status = NtUnmapViewOfSection(pi.hProcess, info.BaseAddress);
2057 ok(!status, "Got unexpected status %#lx.\n", status);
2058 status = NtQueryInformationProcess(pi.hProcess, ProcessImageInformation,
2059 &image_info, sizeof(image_info), NULL );
2060 ok(!status, "Got unexpected status %#lx.\n", status);
2061 ok(!(image_info.ImageCharacteristics & IMAGE_FILE_DLL),
2062 "Got unexpected characteristics %#x.\n", nt_header.FileHeader.Characteristics);
2064 SetLastError(0xdeadbeef);
2065 ret = TerminateProcess(pi.hProcess, 0);
2066 ok(ret, "TerminateProcess() error %ld\n", GetLastError());
2067 ret = WaitForSingleObject(pi.hProcess, 3000);
2068 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %lx\n", ret);
2070 CloseHandle(pi.hThread);
2071 CloseHandle(pi.hProcess);
2073 test_image_mapping(dll_name, td[i].scn_page_access, FALSE);
2075 DeleteFileA(dll_name);
2079 static void check_tls_index(HANDLE dll, BOOL tls_initialized)
2081 BOOL found_dll = FALSE;
2082 LIST_ENTRY *root = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
2083 for (LIST_ENTRY *entry = root->Flink; entry != root; entry = entry->Flink)
2085 LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2086 if (wcsicmp(L"ntdll.dll", mod->BaseDllName.Buffer) == 0)
2088 /* Pick ntdll as a dll that definitely won't have TLS */
2089 ok(mod->TlsIndex == 0, "ntdll.dll TlsIndex: %d instead of 0\n", mod->TlsIndex);
2091 else if (mod->DllBase == dll)
2093 SHORT expected = tls_initialized ? -1 : 0;
2094 ok(mod->TlsIndex == expected, "Test exe TlsIndex: %d instead of %d\n", mod->TlsIndex, expected);
2095 found_dll = TRUE;
2097 else
2099 ok(mod->TlsIndex == 0 || mod->TlsIndex == -1, "%s TlsIndex: %d\n",
2100 debugstr_w(mod->BaseDllName.Buffer), mod->TlsIndex);
2103 ok(found_dll, "Couldn't find dll %p in module list\n", dll);
2106 static int tls_init_fn_output;
2108 static DWORD WINAPI tls_thread_fn(void* tlsidx_v)
2110 int tls_index = (int)(DWORD_PTR)(tlsidx_v);
2111 const char* str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[tls_index];
2112 ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str );
2113 ok( tls_init_fn_output == DLL_THREAD_ATTACH,
2114 "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_THREAD_ATTACH );
2115 tls_init_fn_output = 9999;
2116 return 0;
2119 static void test_import_resolution(void)
2121 char temp_path[MAX_PATH];
2122 char dll_name[MAX_PATH];
2123 DWORD dummy;
2124 void *expect, *tmp;
2125 char *str;
2126 SIZE_T size;
2127 HANDLE hfile, mapping;
2128 HMODULE mod, mod2;
2129 NTSTATUS status;
2130 LARGE_INTEGER offset;
2131 struct imports
2133 IMAGE_IMPORT_DESCRIPTOR descr[2];
2134 IMAGE_THUNK_DATA original_thunks[2];
2135 IMAGE_THUNK_DATA thunks[2];
2136 char module[16];
2137 struct { WORD hint; char name[32]; } function;
2138 IMAGE_TLS_DIRECTORY tls;
2139 UINT_PTR tls_init_fn_list[2];
2140 char tls_data[16];
2141 SHORT tls_index;
2142 SHORT tls_index_hi;
2143 int* tls_init_fn_output;
2144 UCHAR tls_init_fn[64]; /* Note: Uses rip-relative address of tls_init_fn_output, don't separate */
2145 UCHAR entry_point_fn[16];
2146 struct
2148 IMAGE_BASE_RELOCATION reloc;
2149 USHORT type_off[32];
2150 } rel;
2151 } data, *ptr;
2152 IMAGE_NT_HEADERS nt, *pnt;
2153 IMAGE_SECTION_HEADER section;
2154 SECTION_IMAGE_INFORMATION image;
2155 int test, tls_index_save, nb_rel;
2156 #if defined(__i386__)
2157 static const UCHAR tls_init_code[] = {
2158 0xE8, 0x00, 0x00, 0x00, 0x00, /* call 1f */
2159 0x59, /* 1: pop ecx */
2160 0x8B, 0x49, 0xF7, /* mov ecx, [ecx - 9] ; mov ecx, [tls_init_fn_output] */
2161 0x8B, 0x54, 0x24, 0x08, /* mov edx, [esp + 8] */
2162 0x89, 0x11, /* mov [ecx], edx */
2163 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */
2164 0xC2, 0x0C, 0x00, /* ret 12 */
2166 static const UCHAR entry_point_code[] = {
2167 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */
2168 0xC2, 0x0C, 0x00, /* ret 12 */
2170 #elif defined(__x86_64__)
2171 static const UCHAR tls_init_code[] = {
2172 0x48, 0x8B, 0x0D, 0xF1, 0xFF, 0xFF, 0xFF, /* mov rcx, [rip + tls_init_fn_output] */
2173 0x89, 0x11, /* mov [rcx], edx */
2174 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */
2175 0xC3, /* ret */
2177 static const UCHAR entry_point_code[] = {
2178 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */
2179 0xC3, /* ret */
2181 #else
2182 static const UCHAR tls_init_code[] = { 0x00 };
2183 static const UCHAR entry_point_code[] = { 0x00 };
2184 #endif
2186 for (test = 0; test < 7; test++)
2188 #define DATA_RVA(ptr) (page_size + ((char *)(ptr) - (char *)&data))
2189 #ifdef _WIN64
2190 #define ADD_RELOC(field) data.rel.type_off[nb_rel++] = (IMAGE_REL_BASED_DIR64 << 12) + offsetof( struct imports, field )
2191 #else
2192 #define ADD_RELOC(field) data.rel.type_off[nb_rel++] = (IMAGE_REL_BASED_HIGHLOW << 12) + offsetof( struct imports, field )
2193 #endif
2194 winetest_push_context( "%u", test );
2195 nt = nt_header_template;
2196 nt.FileHeader.NumberOfSections = 1;
2197 nt.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
2198 nt.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
2199 if (test != 2 && test != 5) nt.FileHeader.Characteristics |= IMAGE_FILE_DLL;
2200 nt.OptionalHeader.SectionAlignment = page_size;
2201 nt.OptionalHeader.FileAlignment = 0x200;
2202 nt.OptionalHeader.SizeOfImage = 2 * page_size;
2203 nt.OptionalHeader.SizeOfHeaders = nt.OptionalHeader.FileAlignment;
2204 nt.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
2205 if (test < 6) nt.OptionalHeader.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
2206 nt.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
2207 memset( nt.OptionalHeader.DataDirectory, 0, sizeof(nt.OptionalHeader.DataDirectory) );
2208 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = sizeof(data.descr);
2209 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = DATA_RVA(data.descr);
2210 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = sizeof(data.tls);
2211 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = DATA_RVA(&data.tls);
2213 memset( &data, 0, sizeof(data) );
2214 data.descr[0].OriginalFirstThunk = DATA_RVA( data.original_thunks );
2215 data.descr[0].FirstThunk = DATA_RVA( data.thunks );
2216 data.descr[0].Name = DATA_RVA( data.module );
2217 strcpy( data.module, "kernel32.dll" );
2218 strcpy( data.function.name, "CreateEventA" );
2219 data.original_thunks[0].u1.AddressOfData = DATA_RVA( &data.function );
2220 data.thunks[0].u1.AddressOfData = 0xdeadbeef;
2221 nb_rel = 0;
2223 data.tls.StartAddressOfRawData = nt.OptionalHeader.ImageBase + DATA_RVA( data.tls_data );
2224 ADD_RELOC( tls.StartAddressOfRawData );
2225 data.tls.EndAddressOfRawData = data.tls.StartAddressOfRawData + sizeof(data.tls_data);
2226 ADD_RELOC( tls.EndAddressOfRawData );
2227 data.tls.AddressOfIndex = nt.OptionalHeader.ImageBase + DATA_RVA( &data.tls_index );
2228 ADD_RELOC( tls.AddressOfIndex );
2229 strcpy( data.tls_data, "hello world" );
2230 data.tls_index = 9999;
2231 data.tls_index_hi = 9999;
2233 if (test == 3 && sizeof(tls_init_code) > 1)
2235 /* Windows doesn't consistently call tls init functions on dlls without entry points */
2236 assert(sizeof(tls_init_code) <= sizeof(data.tls_init_fn));
2237 assert(sizeof(entry_point_code) <= sizeof(data.entry_point_fn));
2238 memcpy(data.tls_init_fn, tls_init_code, sizeof(tls_init_code));
2239 memcpy(data.entry_point_fn, entry_point_code, sizeof(entry_point_code));
2240 tls_init_fn_output = 9999;
2241 data.tls_init_fn_output = &tls_init_fn_output;
2242 data.tls_init_fn_list[0] = nt.OptionalHeader.ImageBase + DATA_RVA(&data.tls_init_fn);
2243 ADD_RELOC( tls_init_fn_list[0] );
2244 data.tls.AddressOfCallBacks = nt.OptionalHeader.ImageBase + DATA_RVA(&data.tls_init_fn_list);
2245 ADD_RELOC( tls.AddressOfCallBacks );
2246 nt.OptionalHeader.AddressOfEntryPoint = DATA_RVA(&data.entry_point_fn);
2249 if (nb_rel % 2) nb_rel++;
2250 data.rel.reloc.VirtualAddress = nt.OptionalHeader.SectionAlignment;
2251 data.rel.reloc.SizeOfBlock = (char *)&data.rel.type_off[nb_rel] - (char *)&data.rel.reloc;
2252 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = data.rel.reloc.SizeOfBlock;
2253 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = DATA_RVA(&data.rel);
2255 GetTempPathA(MAX_PATH, temp_path);
2256 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
2258 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
2259 ok( hfile != INVALID_HANDLE_VALUE, "creation failed\n" );
2261 memset( &section, 0, sizeof(section) );
2262 memcpy( section.Name, ".text", sizeof(".text") );
2263 section.PointerToRawData = nt.OptionalHeader.FileAlignment;
2264 section.VirtualAddress = nt.OptionalHeader.SectionAlignment;
2265 section.Misc.VirtualSize = sizeof(data);
2266 section.SizeOfRawData = sizeof(data);
2267 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
2268 if (test == 3) section.Characteristics |= IMAGE_SCN_MEM_EXECUTE;
2270 WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
2271 WriteFile(hfile, &nt, sizeof(nt), &dummy, NULL);
2272 WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
2274 SetFilePointer( hfile, section.PointerToRawData, NULL, SEEK_SET );
2275 WriteFile(hfile, &data, sizeof(data), &dummy, NULL);
2277 CloseHandle( hfile );
2279 switch (test)
2281 case 0: /* normal load */
2282 mod = LoadLibraryA( dll_name );
2283 ok( mod != NULL, "failed to load err %lu\n", GetLastError() );
2284 if (!mod) break;
2285 ptr = (struct imports *)((char *)mod + page_size);
2286 expect = GetProcAddress( GetModuleHandleA( data.module ), data.function.name );
2287 ok( (void *)ptr->thunks[0].u1.Function == expect, "thunk %p instead of %p for %s.%s\n",
2288 (void *)ptr->thunks[0].u1.Function, expect, data.module, data.function.name );
2289 ok( ptr->tls_index < 32, "wrong tls index %d\n", ptr->tls_index );
2290 str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index];
2291 ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str );
2292 ok(ptr->tls_index_hi == 0, "TLS Index written as a short, high half: %d\n", ptr->tls_index_hi);
2293 check_tls_index(mod, ptr->tls_index != 9999);
2294 FreeLibrary( mod );
2295 break;
2296 case 1: /* load with DONT_RESOLVE_DLL_REFERENCES doesn't resolve imports */
2297 mod = LoadLibraryExA( dll_name, 0, DONT_RESOLVE_DLL_REFERENCES );
2298 ok( mod != NULL, "failed to load err %lu\n", GetLastError() );
2299 if (!mod) break;
2300 ptr = (struct imports *)((char *)mod + page_size);
2301 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
2302 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
2303 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
2305 mod2 = LoadLibraryA( dll_name );
2306 ok( mod2 == mod, "loaded twice %p / %p\n", mod, mod2 );
2307 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
2308 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
2309 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
2310 check_tls_index(mod, ptr->tls_index != 9999);
2311 FreeLibrary( mod2 );
2312 FreeLibrary( mod );
2313 break;
2314 case 2: /* load without IMAGE_FILE_DLL doesn't resolve imports */
2315 mod = LoadLibraryA( dll_name );
2316 ok( mod != NULL, "failed to load err %lu\n", GetLastError() );
2317 if (!mod) break;
2318 ptr = (struct imports *)((char *)mod + page_size);
2319 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
2320 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
2321 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
2322 check_tls_index(mod, ptr->tls_index != 9999);
2323 FreeLibrary( mod );
2324 break;
2325 case 3: /* load with tls init function */
2326 mod = LoadLibraryA( dll_name );
2327 ok( mod != NULL, "failed to load err %lu\n", GetLastError() );
2328 if (!mod) break;
2329 ptr = (struct imports *)((char *)mod + page_size);
2330 tls_index_save = ptr->tls_index;
2331 ok( ptr->tls_index < 32, "wrong tls index %d\n", ptr->tls_index );
2332 if (sizeof(tls_init_code) > 1)
2334 str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index];
2335 ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str );
2336 /* tls init function will write the reason to *tls_init_fn_output */
2337 ok( tls_init_fn_output == DLL_PROCESS_ATTACH,
2338 "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_PROCESS_ATTACH );
2339 tls_init_fn_output = 9999;
2340 WaitForSingleObject(CreateThread(NULL, 0, tls_thread_fn, (void*)(DWORD_PTR)ptr->tls_index, 0, NULL), INFINITE);
2341 ok( tls_init_fn_output == DLL_THREAD_DETACH,
2342 "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_THREAD_DETACH );
2344 check_tls_index(mod, ptr->tls_index != 9999);
2345 tls_init_fn_output = 9999;
2346 FreeLibrary( mod );
2347 if (tls_index_save != 9999 && sizeof(tls_init_code) > 1)
2348 ok( tls_init_fn_output == DLL_PROCESS_DETACH,
2349 "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_PROCESS_DETACH );
2350 break;
2351 case 4: /* map with ntdll */
2352 case 5: /* map with ntdll, without IMAGE_FILE_DLL */
2353 case 6: /* map with ntdll, without IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE */
2354 hfile = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
2355 ok( hfile != INVALID_HANDLE_VALUE, "CreateFile failed err %lu\n", GetLastError() );
2356 mapping = CreateFileMappingA( hfile, NULL, SEC_IMAGE | PAGE_READONLY, 0, 0, NULL );
2357 CloseHandle( hfile );
2358 if (test == 6 &&
2359 (nt_header_template.FileHeader.Machine == IMAGE_FILE_MACHINE_ARMNT ||
2360 nt_header_template.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64))
2362 ok( !mapping, "CreateFileMappingA succeeded\n" );
2363 ok( GetLastError() == ERROR_BAD_EXE_FORMAT, "wrong error %lu\n", GetLastError() );
2364 break;
2366 status = pNtQuerySection( mapping, SectionImageInformation, &image, sizeof(image), &size );
2367 ok( !status, "NtQuerySection failed %lx\n", status );
2368 ok( test == 6 ? !image.ImageDynamicallyRelocated : image.ImageDynamicallyRelocated,
2369 "image flags %x\n", image.ImageFlags);
2370 ok( !image.ImageContainsCode, "contains code %x\n", image.ImageContainsCode);
2371 ok( mapping != 0, "CreateFileMappingA failed err %lu\n", GetLastError() );
2372 /* make sure that the address is not available */
2373 tmp = VirtualAlloc( (void *)nt.OptionalHeader.ImageBase, 0x10000,
2374 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
2375 mod = NULL;
2376 size = 0;
2377 offset.QuadPart = 0;
2378 status = pNtMapViewOfSection( mapping, GetCurrentProcess(), (void **)&mod, 0, 0, &offset,
2379 &size, 1 /* ViewShare */, 0, PAGE_READONLY );
2380 todo_wine_if (test == 5)
2381 ok( status == (test == 6 ? STATUS_IMAGE_NOT_AT_BASE : STATUS_SUCCESS),
2382 "NtMapViewOfSection failed %lx\n", status );
2383 ok( mod != (void *)nt.OptionalHeader.ImageBase, "loaded at image base %p\n", mod );
2384 pnt = pRtlImageNtHeader( mod );
2385 ptr = (void *)((char *)mod + page_size);
2386 if (test == 6)
2388 ok( (void *)pnt->OptionalHeader.ImageBase != mod, "not relocated from %p\n", mod );
2389 ok( (char *)ptr->tls.StartAddressOfRawData == (char *)nt.OptionalHeader.ImageBase + DATA_RVA( data.tls_data ),
2390 "tls relocated %p / %p\n", (void *)ptr->tls.StartAddressOfRawData,
2391 (char *)nt.OptionalHeader.ImageBase + DATA_RVA( data.tls_data ));
2393 else todo_wine_if (test == 5)
2395 ok( (void *)pnt->OptionalHeader.ImageBase == mod, "not at base %p / %p\n",
2396 (void *)pnt->OptionalHeader.ImageBase, mod );
2397 ok( (char *)ptr->tls.StartAddressOfRawData == (char *)mod + DATA_RVA( data.tls_data ),
2398 "tls not relocated %p / %p\n", (void *)ptr->tls.StartAddressOfRawData,
2399 (char *)mod + DATA_RVA( data.tls_data ));
2401 UnmapViewOfFile( mod );
2402 CloseHandle( mapping );
2403 if (tmp) VirtualFree( tmp, 0, MEM_RELEASE );
2404 break;
2406 DeleteFileA( dll_name );
2407 winetest_pop_context();
2408 #undef DATA_RVA
2412 static HANDLE gen_forward_chain_testdll( char testdll_path[MAX_PATH],
2413 const char source_dll[MAX_PATH],
2414 BOOL is_export, BOOL is_import,
2415 DWORD *exp_func_base_rva,
2416 DWORD *imp_thunk_base_rva )
2418 DWORD text_rva = page_size; /* assumes that the PE/COFF headers fit in a page */
2419 DWORD text_size = page_size;
2420 DWORD edata_rva = text_rva + text_size;
2421 DWORD edata_size = page_size;
2422 DWORD idata_rva = edata_rva + text_size;
2423 DWORD idata_size = page_size;
2424 DWORD eof_rva = idata_rva + edata_size;
2425 const IMAGE_SECTION_HEADER sections[3] = {
2427 .Name = ".text",
2428 .Misc = { .VirtualSize = text_size },
2429 .VirtualAddress = text_rva,
2430 .SizeOfRawData = text_size,
2431 .PointerToRawData = text_rva,
2432 .Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE,
2435 .Name = ".edata",
2436 .Misc = { .VirtualSize = edata_size },
2437 .VirtualAddress = edata_rva,
2438 .SizeOfRawData = edata_size,
2439 .PointerToRawData = edata_rva,
2440 .Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,
2443 .Name = ".idata",
2444 .Misc = { .VirtualSize = edata_size },
2445 .VirtualAddress = idata_rva,
2446 .SizeOfRawData = idata_size,
2447 .PointerToRawData = idata_rva,
2448 .Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE,
2451 struct expdesc
2453 const IMAGE_EXPORT_DIRECTORY dir;
2455 DWORD functions[2];
2457 const DWORD names[2];
2458 const WORD name_ords[2];
2459 const char str_forward_test_func[32];
2460 const char str_forward_test_func2[32];
2462 char dll_name[MAX_PATH]; /* dynamically populated */
2463 char strpool[2][MAX_PATH + 16]; /* for names of export forwarders */
2464 } expdesc = {
2465 .dir = {
2466 .Characteristics = 0,
2467 .TimeDateStamp = 0x12345678,
2468 .Name = edata_rva + offsetof(struct expdesc, dll_name),
2469 .Base = 1,
2470 .NumberOfFunctions = ARRAY_SIZE(expdesc.functions),
2471 .NumberOfNames = ARRAY_SIZE(expdesc.names),
2472 .AddressOfFunctions = edata_rva + offsetof(struct expdesc, functions),
2473 .AddressOfNames = edata_rva + offsetof(struct expdesc, names),
2474 .AddressOfNameOrdinals = edata_rva + offsetof(struct expdesc, name_ords),
2476 .functions = {
2477 text_rva + 0x4, /* may be overwritten */
2478 text_rva + 0x8, /* may be overwritten */
2480 .names = {
2481 edata_rva + offsetof(struct expdesc, str_forward_test_func),
2482 edata_rva + offsetof(struct expdesc, str_forward_test_func2),
2484 .name_ords = {
2488 .str_forward_test_func = "forward_test_func",
2489 .str_forward_test_func2 = "forward_test_func2",
2491 struct impdesc
2493 const IMAGE_IMPORT_DESCRIPTOR descr[2];
2494 const IMAGE_THUNK_DATA original_thunks[3];
2495 const IMAGE_THUNK_DATA thunks[3];
2496 const struct { WORD hint; char name[32]; } impname_forward_test_func;
2498 char module[MAX_PATH]; /* dynamically populated */
2499 } impdesc = {
2500 .descr = {
2502 .OriginalFirstThunk = idata_rva + offsetof(struct impdesc, original_thunks),
2503 .TimeDateStamp = 0,
2504 .ForwarderChain = -1,
2505 .Name = idata_rva + offsetof(struct impdesc, module),
2506 .FirstThunk = idata_rva + offsetof(struct impdesc, thunks),
2508 {{ 0 }},
2510 .original_thunks = {
2511 {{ idata_rva + offsetof(struct impdesc, impname_forward_test_func) }},
2512 {{ IMAGE_ORDINAL_FLAG | 2 }},
2513 {{ 0 }},
2515 .thunks = {
2516 {{ idata_rva + offsetof(struct impdesc, impname_forward_test_func) }},
2517 {{ IMAGE_ORDINAL_FLAG | 2 }},
2518 {{ 0 }},
2520 .impname_forward_test_func = { 0, "forward_test_func" },
2522 IMAGE_NT_HEADERS nt_header;
2523 char temp_path[MAX_PATH];
2524 HANDLE file, file_w;
2525 LARGE_INTEGER qpc;
2526 DWORD outlen;
2527 BOOL ret;
2528 int res;
2530 QueryPerformanceCounter( &qpc );
2531 res = snprintf( expdesc.dll_name, ARRAY_SIZE(expdesc.dll_name),
2532 "ldr%05lx.dll", qpc.LowPart & 0xfffffUL );
2533 ok( res > 0 && res < ARRAY_SIZE(expdesc.dll_name), "snprintf failed\n" );
2535 if (source_dll)
2537 const char *export_names[2] = {
2538 "forward_test_func",
2539 "#2",
2541 const char *backslash = strrchr( source_dll, '\\' );
2542 const char *dllname = backslash ? backslash + 1 : source_dll;
2543 const char *dot = strrchr( dllname, '.' );
2544 size_t ext_start = dot ? dot - dllname : strlen(dllname);
2545 size_t i;
2547 res = snprintf( impdesc.module, ARRAY_SIZE(impdesc.module), "%s", dllname );
2548 ok( res > 0 && res < ARRAY_SIZE(impdesc.module), "snprintf() failed\n" );
2550 for (i = 0; i < ARRAY_SIZE(export_names); i++)
2552 char *buf;
2553 size_t buf_size;
2555 assert( i < ARRAY_SIZE(expdesc.strpool) );
2556 buf = expdesc.strpool[i];
2557 buf_size = ARRAY_SIZE(expdesc.strpool[i]);
2559 assert( ext_start < buf_size );
2560 memcpy( buf, dllname, ext_start );
2561 buf += ext_start;
2562 buf_size -= ext_start;
2564 res = snprintf( buf, buf_size, ".%s", export_names[i] );
2565 ok( res > 0 && res < buf_size, "snprintf() failed\n" );
2567 assert( i < ARRAY_SIZE(expdesc.functions) );
2568 expdesc.functions[i] = edata_rva + (expdesc.strpool[i] - (char *)&expdesc);
2572 nt_header = nt_header_template;
2573 nt_header.FileHeader.TimeDateStamp = 0x12345678;
2574 nt_header.FileHeader.NumberOfSections = ARRAY_SIZE(sections);
2575 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
2577 nt_header.OptionalHeader.SizeOfCode = text_size;
2578 nt_header.OptionalHeader.SectionAlignment = page_size;
2579 nt_header.OptionalHeader.FileAlignment = page_size;
2580 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(sections);
2581 nt_header.OptionalHeader.SizeOfImage = eof_rva;
2582 if (is_export)
2584 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = edata_rva;
2585 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sizeof(expdesc);
2587 /* Always have an import descriptor (even if empty) just like a real DLL */
2588 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = idata_rva;
2589 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = is_import ? sizeof(impdesc) : sizeof(IMAGE_IMPORT_DESCRIPTOR);
2591 ok( nt_header.OptionalHeader.SizeOfHeaders <= text_rva,
2592 "headers (size %#lx) should not overlap with text area (RVA %#lx)\n",
2593 nt_header.OptionalHeader.SizeOfHeaders, text_rva );
2595 outlen = GetTempPathA( ARRAY_SIZE(temp_path), temp_path );
2596 ok( outlen > 0 && outlen < ARRAY_SIZE(temp_path), "GetTempPathA() err=%lu\n", GetLastError() );
2598 res = snprintf( testdll_path, MAX_PATH, "%s\\%s", temp_path, expdesc.dll_name );
2599 ok( res > 0 && res < MAX_PATH, "snprintf failed\n" );
2601 /* Open file handle that will be deleted on close or process termination */
2602 file = CreateFileA( testdll_path,
2603 DELETE,
2604 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2605 NULL,
2606 CREATE_NEW,
2607 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
2608 NULL );
2609 ok( file != INVALID_HANDLE_VALUE, "CreateFile(%s) for delete returned error %lu\n",
2610 wine_dbgstr_a( testdll_path ), GetLastError() );
2612 /* Open file again with write access */
2613 file_w = CreateFileA( testdll_path,
2614 GENERIC_WRITE,
2615 FILE_SHARE_READ | FILE_SHARE_DELETE,
2616 NULL,
2617 OPEN_EXISTING,
2618 FILE_ATTRIBUTE_NORMAL,
2619 NULL );
2620 ok( file_w != INVALID_HANDLE_VALUE, "CreateFile(%s) for write returned error %lu\n",
2621 wine_dbgstr_a( testdll_path ), GetLastError() );
2623 ret = WriteFile( file_w, &dos_header, sizeof(dos_header), &outlen, NULL );
2624 ok( ret && outlen == sizeof(dos_header), "write dos_header: err=%lu outlen=%lu\n", GetLastError(), outlen );
2626 ret = WriteFile( file_w, &nt_header, sizeof(nt_header), &outlen, NULL );
2627 ok( ret && outlen == sizeof(nt_header), "write nt_header: err=%lu outlen=%lu\n", GetLastError(), outlen );
2629 ret = WriteFile( file_w, sections, sizeof(sections), &outlen, NULL );
2630 ok( ret && outlen == sizeof(sections), "write sections: err=%lu outlen=%lu\n", GetLastError(), outlen );
2632 if (is_export)
2634 SetFilePointer( file_w, edata_rva, NULL, FILE_BEGIN );
2635 ret = WriteFile( file_w, &expdesc, sizeof(expdesc), &outlen, NULL );
2636 ok( ret && outlen == sizeof(expdesc), "write expdesc: err=%lu outlen=%lu\n", GetLastError(), outlen );
2639 if (is_import)
2641 SetFilePointer( file_w, idata_rva, NULL, FILE_BEGIN );
2642 ret = WriteFile( file_w, &impdesc, sizeof(impdesc), &outlen, NULL );
2643 ok( ret && outlen == sizeof(impdesc), "write impdesc: err=%lu outlen=%lu\n", GetLastError(), outlen );
2646 ret = SetFilePointer( file_w, eof_rva, NULL, FILE_BEGIN );
2647 ok( ret, "%lu\n", GetLastError() );
2648 ret = SetEndOfFile( file_w );
2649 ok( ret, "%lu\n", GetLastError() );
2651 ret = CloseHandle( file_w );
2652 ok( ret, "%lu\n", GetLastError() );
2654 if (exp_func_base_rva)
2656 *exp_func_base_rva = is_export ? edata_rva + ((char *)&expdesc.functions - (char *)&expdesc) : 0;
2659 if (imp_thunk_base_rva)
2661 *imp_thunk_base_rva = is_import ? idata_rva + ((char *)&impdesc.thunks - (char *)&impdesc) : 0;
2664 return file;
2667 static void subtest_export_forwarder_dep_chain( size_t num_chained_export_modules,
2668 size_t exporter_index,
2669 BOOL test_static_import )
2671 size_t num_modules = num_chained_export_modules + !!test_static_import;
2672 size_t importer_index = test_static_import ? num_modules - 1 : 0;
2673 DWORD imp_thunk_base_rva, exp_func_base_rva;
2674 size_t ultimate_depender_index = 0; /* latest module depending on modules earlier in chain */
2675 char temp_paths[4][MAX_PATH];
2676 HANDLE temp_files[4];
2677 UINT_PTR exports[2];
2678 HMODULE modules[4];
2679 BOOL res;
2680 size_t i;
2682 assert(exporter_index < num_chained_export_modules);
2683 assert(num_modules > 1);
2684 assert(num_modules <= ARRAY_SIZE(temp_paths));
2685 assert(num_modules <= ARRAY_SIZE(temp_files));
2686 assert(num_modules <= ARRAY_SIZE(modules));
2688 if (winetest_debug > 1)
2689 trace( "Generate a chain of test DLL fixtures\n" );
2691 for (i = 0; i < num_modules; i++)
2693 temp_files[i] = gen_forward_chain_testdll( temp_paths[i],
2694 i >= 1 ? temp_paths[i - 1] : NULL,
2695 i < num_chained_export_modules,
2696 importer_index && i == importer_index,
2697 i == 0 ? &exp_func_base_rva : NULL,
2698 i == importer_index ? &imp_thunk_base_rva : NULL );
2701 if (winetest_debug > 1)
2702 trace( "Load the entire test DLL chain\n" );
2704 for (i = 0; i < num_modules; i++)
2706 HMODULE module;
2708 ok( !GetModuleHandleA( temp_paths[i] ), "%s already loaded\n",
2709 wine_dbgstr_a( temp_paths[i] ) );
2711 modules[i] = LoadLibraryA( temp_paths[i] );
2712 ok( !!modules[i], "LoadLibraryA(temp_paths[%Iu] = %s) err=%lu\n",
2713 i, wine_dbgstr_a( temp_paths[i] ), GetLastError() );
2715 if (i == importer_index)
2717 /* Statically importing export forwarder introduces a load-time dependency */
2718 ultimate_depender_index = max( ultimate_depender_index, importer_index );
2721 module = GetModuleHandleA( temp_paths[i] );
2722 ok( module == modules[i], "modules[%Iu] expected %p, got %p err=%lu\n",
2723 i, modules[i], module, GetLastError() );
2726 if (winetest_debug > 1)
2727 trace( "Get address of exported functions from the source module\n" );
2729 for (i = 0; i < ARRAY_SIZE(exports); i++)
2731 char *mod_base = (char *)modules[0]; /* source (non-forward) DLL */
2732 exports[i] = (UINT_PTR)(mod_base + ((DWORD *)(mod_base + exp_func_base_rva))[i]);
2735 if (winetest_debug > 1)
2736 trace( "Check import address table of the importer DLL, if any\n" );
2738 if (importer_index)
2740 UINT_PTR *imp_thunk_base = (UINT_PTR *)((char *)modules[importer_index] + imp_thunk_base_rva);
2741 for (i = 0; i < ARRAY_SIZE(exports); i++)
2743 ok( imp_thunk_base[i] == exports[i], "import thunk mismatch [%Iu]: (%#Ix, %#Ix)\n",
2744 i, imp_thunk_base[i], exports[i] );
2748 if (winetest_debug > 1)
2749 trace( "Call GetProcAddress() on the exporter DLL, if any\n" );
2751 if (exporter_index)
2753 UINT_PTR proc;
2755 proc = (UINT_PTR)GetProcAddress( modules[exporter_index], "forward_test_func" );
2756 ok( proc == exports[0], "GetProcAddress mismatch [0]: (%#Ix, %#Ix)\n", proc, exports[0] );
2758 proc = (UINT_PTR)GetProcAddress( modules[exporter_index], (LPSTR)2 );
2759 ok( proc == exports[1], "GetProcAddress mismatch [1]: (%#Ix, %#Ix)\n", proc, exports[1] );
2761 /* Dynamically importing export forwarder introduces a runtime dependency */
2762 ultimate_depender_index = max( ultimate_depender_index, exporter_index );
2765 if (winetest_debug > 1)
2766 trace( "Unreference modules except the ultimate dependant DLL\n" );
2768 for (i = 0; i < ultimate_depender_index; i++)
2770 HMODULE module;
2772 res = FreeLibrary( modules[i] );
2773 ok( res, "FreeLibrary(modules[%Iu]) err=%lu\n", i, GetLastError() );
2775 /* FreeLibrary() should *not* unload the DLL immediately */
2776 module = GetModuleHandleA( temp_paths[i] );
2777 todo_wine_if(i < ultimate_depender_index && i + 1 != importer_index)
2778 ok( module == modules[i], "modules[%Iu] expected %p, got %p (unloaded?) err=%lu\n",
2779 i, modules[i], module, GetLastError() );
2782 if (winetest_debug > 1)
2783 trace( "The ultimate dependant DLL should keep other DLLs from being unloaded\n" );
2785 for (i = 0; i < num_modules; i++)
2787 HMODULE module = GetModuleHandleA( temp_paths[i] );
2789 todo_wine_if(i < ultimate_depender_index && i + 1 != importer_index)
2790 ok( module == modules[i], "modules[%Iu] expected %p, got %p (unloaded?) err=%lu\n",
2791 i, modules[i], module, GetLastError() );
2794 if (winetest_debug > 1)
2795 trace( "Unreference the remaining modules (including the dependant DLL)\n" );
2797 for (i = ultimate_depender_index; i < num_modules; i++)
2799 res = FreeLibrary( modules[i] );
2800 ok( res, "FreeLibrary(modules[%Iu]) err=%lu\n", i, GetLastError() );
2802 /* FreeLibrary() should unload the DLL immediately */
2803 ok( !GetModuleHandleA( temp_paths[i] ), "modules[%Iu] should not be kept loaded (2)\n", i );
2806 if (winetest_debug > 1)
2807 trace( "All modules should be unloaded; the unloading process should not reload any DLL\n" );
2809 for (i = 0; i < num_modules; i++)
2811 ok( !GetModuleHandleA( temp_paths[i] ), "modules[%Iu] should not be kept loaded (3)\n", i );
2814 if (winetest_debug > 1)
2815 trace( "Close and delete temp files\n" );
2817 for (i = 0; i < num_modules; i++)
2819 /* handles should be delete-on-close */
2820 CloseHandle( temp_files[i] );
2824 static void test_export_forwarder_dep_chain(void)
2826 winetest_push_context( "no import" );
2827 /* export forwarder does not introduce a dependency on its own */
2828 subtest_export_forwarder_dep_chain( 2, 0, FALSE );
2829 winetest_pop_context();
2831 winetest_push_context( "static import of export forwarder" );
2832 subtest_export_forwarder_dep_chain( 2, 0, TRUE );
2833 winetest_pop_context();
2835 winetest_push_context( "static import of chained export forwarder" );
2836 subtest_export_forwarder_dep_chain( 3, 0, TRUE );
2837 winetest_pop_context();
2839 winetest_push_context( "dynamic import of export forwarder" );
2840 subtest_export_forwarder_dep_chain( 2, 1, FALSE );
2841 winetest_pop_context();
2843 winetest_push_context( "dynamic import of chained export forwarder" );
2844 subtest_export_forwarder_dep_chain( 3, 2, FALSE );
2845 winetest_pop_context();
2848 #define MAX_COUNT 10
2849 static HANDLE attached_thread[MAX_COUNT];
2850 static DWORD attached_thread_count;
2851 static HANDLE event, mutex, semaphore;
2852 static HANDLE stop_event, loader_lock_event, peb_lock_event, heap_lock_event, cs_lock_event, ack_event;
2853 static CRITICAL_SECTION cs_lock;
2854 static int test_dll_phase, inside_loader_lock, inside_peb_lock, inside_heap_lock, inside_cs_lock;
2855 static LONG fls_callback_count;
2857 static DWORD WINAPI mutex_thread_proc(void *param)
2859 HANDLE wait_list[5];
2860 DWORD ret;
2862 ret = WaitForSingleObject(mutex, 0);
2863 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret);
2865 SetEvent(param);
2867 wait_list[0] = stop_event;
2868 wait_list[1] = loader_lock_event;
2869 wait_list[2] = peb_lock_event;
2870 wait_list[3] = heap_lock_event;
2871 wait_list[4] = cs_lock_event;
2873 trace("%04lx: mutex_thread_proc: starting\n", GetCurrentThreadId());
2874 while (1)
2876 ret = WaitForMultipleObjects(ARRAY_SIZE(wait_list), wait_list, FALSE, 50);
2877 if (ret == WAIT_OBJECT_0) break;
2878 else if (ret == WAIT_OBJECT_0 + 1)
2880 ULONG_PTR loader_lock_magic;
2881 trace("%04lx: mutex_thread_proc: Entering loader lock\n", GetCurrentThreadId());
2882 ret = pLdrLockLoaderLock(0, NULL, &loader_lock_magic);
2883 ok(!ret, "LdrLockLoaderLock error %#lx\n", ret);
2884 inside_loader_lock++;
2885 SetEvent(ack_event);
2887 else if (ret == WAIT_OBJECT_0 + 2)
2889 trace("%04lx: mutex_thread_proc: Entering PEB lock\n", GetCurrentThreadId());
2890 pRtlAcquirePebLock();
2891 inside_peb_lock++;
2892 SetEvent(ack_event);
2894 else if (ret == WAIT_OBJECT_0 + 3)
2896 trace("%04lx: mutex_thread_proc: Entering heap lock\n", GetCurrentThreadId());
2897 HeapLock(GetProcessHeap());
2898 inside_heap_lock++;
2899 SetEvent(ack_event);
2901 else if (ret == WAIT_OBJECT_0 + 4)
2903 trace("%04lx: mutex_thread_proc: Entering CS lock\n", GetCurrentThreadId());
2904 EnterCriticalSection(&cs_lock);
2905 inside_cs_lock++;
2906 SetEvent(ack_event);
2910 trace("%04lx: mutex_thread_proc: exiting\n", GetCurrentThreadId());
2911 return 196;
2914 static DWORD WINAPI semaphore_thread_proc(void *param)
2916 DWORD ret;
2918 ret = WaitForSingleObject(semaphore, 0);
2919 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret);
2921 SetEvent(param);
2923 while (1)
2925 if (winetest_debug > 1)
2926 trace("%04lx: semaphore_thread_proc: still alive\n", GetCurrentThreadId());
2927 if (WaitForSingleObject(stop_event, 50) != WAIT_TIMEOUT) break;
2930 trace("%04lx: semaphore_thread_proc: exiting\n", GetCurrentThreadId());
2931 return 196;
2934 static DWORD WINAPI noop_thread_proc(void *param)
2936 if (param)
2938 LONG *noop_thread_started = param;
2939 InterlockedIncrement(noop_thread_started);
2942 trace("%04lx: noop_thread_proc: exiting\n", GetCurrentThreadId());
2943 return 195;
2946 static VOID WINAPI fls_callback(PVOID lpFlsData)
2948 ok(lpFlsData == (void*) 0x31415, "lpFlsData is %p, expected %p\n", lpFlsData, (void*) 0x31415);
2949 InterlockedIncrement(&fls_callback_count);
2952 static LIST_ENTRY *fls_list_head;
2954 static unsigned int check_linked_list(const LIST_ENTRY *le, const LIST_ENTRY *search_entry, unsigned int *index_found)
2956 unsigned int count = 0;
2957 LIST_ENTRY *entry;
2959 *index_found = ~0;
2961 for (entry = le->Flink; entry != le; entry = entry->Flink)
2963 if (entry == search_entry)
2965 ok(*index_found == ~0, "Duplicate list entry.\n");
2966 *index_found = count;
2968 ++count;
2970 return count;
2973 static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param)
2975 static LONG noop_thread_started;
2976 static DWORD fls_index = FLS_OUT_OF_INDEXES, fls_index2 = FLS_OUT_OF_INDEXES;
2977 static int fls_count = 0;
2978 static int thread_detach_count = 0;
2979 static int thread_count;
2980 DWORD ret;
2982 ok(!inside_loader_lock, "inside_loader_lock should not be set\n");
2983 ok(!inside_peb_lock, "inside_peb_lock should not be set\n");
2985 switch (reason)
2987 case DLL_PROCESS_ATTACH:
2988 trace("dll: %p, DLL_PROCESS_ATTACH, %p\n", hinst, param);
2990 ret = pRtlDllShutdownInProgress();
2991 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
2993 /* Set up the FLS slot, if FLS is available */
2994 if (pFlsGetValue)
2996 void* value;
2997 BOOL bret;
2998 ret = pFlsAlloc(&fls_callback);
2999 ok(ret != FLS_OUT_OF_INDEXES, "FlsAlloc returned %ld\n", ret);
3000 fls_index = ret;
3001 SetLastError(0xdeadbeef);
3002 value = pFlsGetValue(fls_index);
3003 ok(!value, "FlsGetValue returned %p, expected NULL\n", value);
3004 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %lu\n", GetLastError());
3005 bret = pFlsSetValue(fls_index, (void*) 0x31415);
3006 ok(bret, "FlsSetValue failed\n");
3007 fls_count++;
3009 fls_index2 = pFlsAlloc(&fls_callback);
3010 ok(fls_index2 != FLS_OUT_OF_INDEXES, "FlsAlloc returned %ld\n", ret);
3012 ++thread_count;
3013 break;
3014 case DLL_PROCESS_DETACH:
3016 DWORD code, expected_code, i;
3017 HANDLE handle, process;
3018 void *addr;
3019 SIZE_T size;
3020 LARGE_INTEGER offset;
3021 DEBUG_EVENT de;
3023 trace("dll: %p, DLL_PROCESS_DETACH, %p\n", hinst, param);
3025 if (test_dll_phase == 4 || test_dll_phase == 5)
3027 ok(0, "dll_entry_point(DLL_PROCESS_DETACH) should not be called\n");
3028 break;
3031 /* The process should already deadlock at this point */
3032 if (test_dll_phase == 6)
3034 /* In reality, code below never gets executed, probably some other
3035 * code tries to access process heap and deadlocks earlier, even XP
3036 * doesn't call the DLL entry point on process detach either.
3038 HeapLock(GetProcessHeap());
3039 todo_wine
3040 ok(0, "dll_entry_point: process should already deadlock\n");
3041 break;
3043 else if (test_dll_phase == 7)
3045 EnterCriticalSection(&cs_lock);
3048 if (test_dll_phase == 0 || test_dll_phase == 1 || test_dll_phase == 3 || test_dll_phase == 7)
3049 ok(param != NULL, "dll: param %p\n", param);
3050 else
3051 ok(!param, "dll: param %p\n", param);
3053 if (test_dll_phase == 0 || test_dll_phase == 1) expected_code = 195;
3054 else if (test_dll_phase == 3) expected_code = 196;
3055 else if (test_dll_phase == 7) expected_code = 199;
3056 else expected_code = STILL_ACTIVE;
3058 ret = pRtlDllShutdownInProgress();
3059 if (test_dll_phase == 0 || test_dll_phase == 1 || test_dll_phase == 3)
3061 ok(ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3063 else
3065 /* FIXME: remove once Wine is fixed */
3066 todo_wine_if (!(expected_code == STILL_ACTIVE || expected_code == 196))
3067 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3070 /* In the case that the process is terminating, FLS slots should still be accessible, but
3071 * the callback should be already run for this thread and the contents already NULL.
3073 if (param && pFlsGetValue)
3075 void* value;
3076 SetLastError(0xdeadbeef);
3077 value = pFlsGetValue(fls_index);
3078 ok(value == NULL, "FlsGetValue returned %p, expected NULL\n", value);
3079 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %lu\n", GetLastError());
3080 ok(fls_callback_count == thread_detach_count + 1,
3081 "wrong FLS callback count %ld, expected %d\n", fls_callback_count, thread_detach_count + 1);
3083 if (pFlsFree)
3085 BOOL ret;
3086 /* Call FlsFree now and run the remaining callbacks from uncleanly terminated threads */
3087 ret = pFlsFree(fls_index);
3088 ok(ret, "FlsFree failed with error %lu\n", GetLastError());
3089 fls_index = FLS_OUT_OF_INDEXES;
3090 ok(fls_callback_count == fls_count,
3091 "wrong FLS callback count %ld, expected %d\n", fls_callback_count, fls_count);
3094 ok(attached_thread_count >= 2, "attached thread count should be >= 2\n");
3096 for (i = 0; i < attached_thread_count; i++)
3098 /* Calling GetExitCodeThread() without waiting for thread termination
3099 * leads to different results due to a race condition.
3101 if (expected_code != STILL_ACTIVE)
3103 ret = WaitForSingleObject(attached_thread[i], 1000);
3104 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret);
3106 ret = GetExitCodeThread(attached_thread[i], &code);
3107 trace("dll: GetExitCodeThread(%lu) => %ld,%lu\n", i, ret, code);
3108 ok(ret == 1, "GetExitCodeThread returned %ld, expected 1\n", ret);
3109 ok(code == expected_code, "expected thread exit code %lu, got %lu\n", expected_code, code);
3112 ret = WaitForSingleObject(event, 0);
3113 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3115 ret = WaitForSingleObject(mutex, 0);
3116 if (expected_code == STILL_ACTIVE)
3117 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3118 else
3119 ok(ret == WAIT_ABANDONED, "expected WAIT_ABANDONED, got %#lx\n", ret);
3121 /* semaphore is not abandoned on thread termination */
3122 ret = WaitForSingleObject(semaphore, 0);
3123 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3125 if (expected_code == STILL_ACTIVE)
3127 ret = WaitForSingleObject(attached_thread[0], 0);
3128 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3129 ret = WaitForSingleObject(attached_thread[1], 0);
3130 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3132 else
3134 ret = WaitForSingleObject(attached_thread[0], 0);
3135 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret);
3136 ret = WaitForSingleObject(attached_thread[1], 0);
3137 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret);
3140 /* win7 doesn't allow creating a thread during process shutdown but
3141 * earlier Windows versions allow it.
3143 noop_thread_started = 0;
3144 SetLastError(0xdeadbeef);
3145 handle = CreateThread(NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
3146 if (param)
3148 ok(!handle, "CreateThread should fail\n");
3149 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
3151 else
3153 ok(handle != 0, "CreateThread error %ld\n", GetLastError());
3154 ret = WaitForSingleObject(handle, 1000);
3155 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3156 ok(!noop_thread_started, "thread shouldn't start yet\n");
3157 CloseHandle(handle);
3160 SetLastError(0xdeadbeef);
3161 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, GetCurrentProcessId());
3162 ok(process != NULL, "OpenProcess error %ld\n", GetLastError());
3164 noop_thread_started = 0;
3165 SetLastError(0xdeadbeef);
3166 handle = CreateRemoteThread(process, NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
3167 if (param)
3169 ok(!handle, "CreateRemoteThread should fail\n");
3170 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
3172 else
3174 ok(handle != 0, "CreateRemoteThread error %ld\n", GetLastError());
3175 ret = WaitForSingleObject(handle, 1000);
3176 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3177 ok(!noop_thread_started, "thread shouldn't start yet\n");
3178 CloseHandle(handle);
3181 SetLastError(0xdeadbeef);
3182 handle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
3183 ok(handle != 0, "CreateFileMapping error %ld\n", GetLastError());
3185 offset.u.LowPart = 0;
3186 offset.u.HighPart = 0;
3187 addr = NULL;
3188 size = 0;
3189 ret = pNtMapViewOfSection(handle, process, &addr, 0, 0, &offset,
3190 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
3191 ok(ret == STATUS_SUCCESS, "NtMapViewOfSection error %#lx\n", ret);
3192 ret = pNtUnmapViewOfSection(process, addr);
3193 ok(ret == STATUS_SUCCESS, "NtUnmapViewOfSection error %#lx\n", ret);
3195 CloseHandle(handle);
3196 CloseHandle(process);
3198 handle = GetModuleHandleA("winver.exe");
3199 ok(!handle, "winver.exe shouldn't be loaded yet\n");
3200 SetLastError(0xdeadbeef);
3201 handle = LoadLibraryA("winver.exe");
3202 ok(handle != 0, "LoadLibrary error %ld\n", GetLastError());
3203 SetLastError(0xdeadbeef);
3204 ret = FreeLibrary(handle);
3205 ok(ret, "FreeLibrary error %ld\n", GetLastError());
3206 handle = GetModuleHandleA("winver.exe");
3207 if (param)
3208 ok(handle != 0, "winver.exe should not be unloaded\n");
3209 else
3210 todo_wine
3211 ok(!handle, "winver.exe should be unloaded\n");
3213 SetLastError(0xdeadbeef);
3214 ret = WaitForDebugEvent(&de, 0);
3215 ok(!ret, "WaitForDebugEvent should fail\n");
3216 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
3218 SetLastError(0xdeadbeef);
3219 ret = DebugActiveProcess(GetCurrentProcessId());
3220 ok(!ret, "DebugActiveProcess should fail\n");
3221 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
3223 SetLastError(0xdeadbeef);
3224 ret = WaitForDebugEvent(&de, 0);
3225 ok(!ret, "WaitForDebugEvent should fail\n");
3226 ok(GetLastError() == ERROR_SEM_TIMEOUT, "expected ERROR_SEM_TIMEOUT, got %ld\n", GetLastError());
3228 if (test_dll_phase == 2)
3230 trace("dll: call ExitProcess()\n");
3231 *child_failures = winetest_get_failures();
3232 ExitProcess(197);
3234 trace("dll: %p, DLL_PROCESS_DETACH, %p => DONE\n", hinst, param);
3235 break;
3237 case DLL_THREAD_ATTACH:
3238 trace("dll: %p, DLL_THREAD_ATTACH, %p\n", hinst, param);
3240 ++thread_count;
3242 ret = pRtlDllShutdownInProgress();
3243 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3245 if (attached_thread_count < MAX_COUNT)
3247 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &attached_thread[attached_thread_count],
3248 0, TRUE, DUPLICATE_SAME_ACCESS);
3249 attached_thread_count++;
3252 /* Make sure the FLS slot is empty, if FLS is available */
3253 if (pFlsGetValue)
3255 void* value;
3256 BOOL ret;
3257 SetLastError(0xdeadbeef);
3258 value = pFlsGetValue(fls_index);
3259 ok(!value, "FlsGetValue returned %p, expected NULL\n", value);
3260 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %lu\n", GetLastError());
3261 ret = pFlsSetValue(fls_index, (void*) 0x31415);
3262 ok(ret, "FlsSetValue failed\n");
3263 fls_count++;
3266 break;
3267 case DLL_THREAD_DETACH:
3268 trace("dll: %p, DLL_THREAD_DETACH, %p\n", hinst, param);
3269 --thread_count;
3270 thread_detach_count++;
3272 ret = pRtlDllShutdownInProgress();
3273 /* win7 doesn't allow creating a thread during process shutdown but
3274 * earlier Windows versions allow it. In that case DLL_THREAD_DETACH is
3275 * sent on thread exit, but DLL_THREAD_ATTACH is never received.
3277 if (noop_thread_started)
3278 ok(ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3279 else
3280 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3282 /* FLS data should already be destroyed, if FLS is available.
3284 if (pFlsGetValue && fls_index != FLS_OUT_OF_INDEXES)
3286 unsigned int index, count;
3287 void* value;
3288 BOOL bret;
3290 SetLastError(0xdeadbeef);
3291 value = pFlsGetValue(fls_index);
3292 ok(!value, "FlsGetValue returned %p, expected NULL\n", value);
3293 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %lu\n", GetLastError());
3295 bret = pFlsSetValue(fls_index2, (void*) 0x31415);
3296 ok(bret, "FlsSetValue failed\n");
3298 if (fls_list_head)
3300 count = check_linked_list(fls_list_head, &NtCurrentTeb()->FlsSlots->fls_list_entry, &index);
3301 ok(count <= thread_count, "Got unexpected count %u, thread_count %u.\n", count, thread_count);
3302 ok(index == ~0, "Got unexpected index %u.\n", index);
3306 break;
3307 default:
3308 trace("dll: %p, %ld, %p\n", hinst, reason, param);
3309 break;
3312 *child_failures = winetest_get_failures();
3314 return TRUE;
3317 static void child_process(const char *dll_name, DWORD target_offset)
3319 void *target;
3320 DWORD ret, dummy, i, code, expected_code;
3321 HANDLE file, thread, process;
3322 HMODULE hmod;
3323 struct PROCESS_BASIC_INFORMATION_PRIVATE pbi;
3324 DWORD_PTR affinity;
3326 trace("phase %d: writing %p at %#lx\n", test_dll_phase, dll_entry_point, target_offset);
3328 if (pFlsAlloc)
3330 fls_list_head = NtCurrentTeb()->Peb->FlsListHead.Flink ? &NtCurrentTeb()->Peb->FlsListHead
3331 : NtCurrentTeb()->FlsSlots->fls_list_entry.Flink;
3334 SetLastError(0xdeadbeef);
3335 mutex = CreateMutexW(NULL, FALSE, NULL);
3336 ok(mutex != 0, "CreateMutex error %ld\n", GetLastError());
3338 SetLastError(0xdeadbeef);
3339 semaphore = CreateSemaphoreW(NULL, 1, 1, NULL);
3340 ok(semaphore != 0, "CreateSemaphore error %ld\n", GetLastError());
3342 SetLastError(0xdeadbeef);
3343 event = CreateEventW(NULL, TRUE, FALSE, NULL);
3344 ok(event != 0, "CreateEvent error %ld\n", GetLastError());
3346 SetLastError(0xdeadbeef);
3347 loader_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
3348 ok(loader_lock_event != 0, "CreateEvent error %ld\n", GetLastError());
3350 SetLastError(0xdeadbeef);
3351 peb_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
3352 ok(peb_lock_event != 0, "CreateEvent error %ld\n", GetLastError());
3354 SetLastError(0xdeadbeef);
3355 heap_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
3356 ok(heap_lock_event != 0, "CreateEvent error %ld\n", GetLastError());
3358 InitializeCriticalSection(&cs_lock);
3359 SetLastError(0xdeadbeef);
3360 cs_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
3361 ok(cs_lock_event != 0, "CreateEvent error %ld\n", GetLastError());
3363 SetLastError(0xdeadbeef);
3364 ack_event = CreateEventW(NULL, FALSE, FALSE, NULL);
3365 ok(ack_event != 0, "CreateEvent error %ld\n", GetLastError());
3367 file = CreateFileA(dll_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3368 if (file == INVALID_HANDLE_VALUE)
3370 ok(0, "could not open %s\n", dll_name);
3371 return;
3373 SetFilePointer(file, target_offset, NULL, FILE_BEGIN);
3374 SetLastError(0xdeadbeef);
3375 target = dll_entry_point;
3376 ret = WriteFile(file, &target, sizeof(target), &dummy, NULL);
3377 ok(ret, "WriteFile error %ld\n", GetLastError());
3378 CloseHandle(file);
3380 SetLastError(0xdeadbeef);
3381 hmod = LoadLibraryA(dll_name);
3382 ok(hmod != 0, "LoadLibrary error %ld\n", GetLastError());
3384 SetLastError(0xdeadbeef);
3385 stop_event = CreateEventW(NULL, TRUE, FALSE, NULL);
3386 ok(stop_event != 0, "CreateEvent error %ld\n", GetLastError());
3388 SetLastError(0xdeadbeef);
3389 thread = CreateThread(NULL, 0, mutex_thread_proc, event, 0, &dummy);
3390 ok(thread != 0, "CreateThread error %ld\n", GetLastError());
3391 WaitForSingleObject(event, 3000);
3392 CloseHandle(thread);
3394 ResetEvent(event);
3396 SetLastError(0xdeadbeef);
3397 thread = CreateThread(NULL, 0, semaphore_thread_proc, event, 0, &dummy);
3398 ok(thread != 0, "CreateThread error %ld\n", GetLastError());
3399 WaitForSingleObject(event, 3000);
3400 CloseHandle(thread);
3402 ResetEvent(event);
3403 Sleep(100);
3405 ok(attached_thread_count == 2, "attached thread count should be 2\n");
3406 for (i = 0; i < attached_thread_count; i++)
3408 ret = GetExitCodeThread(attached_thread[i], &code);
3409 trace("child: GetExitCodeThread(%lu) => %ld,%lu\n", i, ret, code);
3410 ok(ret == 1, "GetExitCodeThread returned %ld, expected 1\n", ret);
3411 ok(code == STILL_ACTIVE, "expected thread exit code STILL_ACTIVE, got %lu\n", code);
3414 ret = WaitForSingleObject(attached_thread[0], 0);
3415 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3416 ret = WaitForSingleObject(attached_thread[1], 0);
3417 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3419 ret = WaitForSingleObject(event, 0);
3420 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3421 ret = WaitForSingleObject(mutex, 0);
3422 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3423 ret = WaitForSingleObject(semaphore, 0);
3424 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3426 ret = pRtlDllShutdownInProgress();
3427 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3429 SetLastError(0xdeadbeef);
3430 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, GetCurrentProcessId());
3431 ok(process != NULL, "OpenProcess error %ld\n", GetLastError());
3433 SetLastError(0xdeadbeef);
3434 ret = TerminateProcess(0, 195);
3435 ok(!ret, "TerminateProcess(0) should fail\n");
3436 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
3438 Sleep(100);
3440 affinity = 1;
3441 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
3442 ok(!ret, "NtSetInformationProcess error %#lx\n", ret);
3444 switch (test_dll_phase)
3446 case 0:
3447 ret = pRtlDllShutdownInProgress();
3448 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3450 trace("call NtTerminateProcess(0, 195)\n");
3451 ret = pNtTerminateProcess(0, 195);
3452 ok(!ret, "NtTerminateProcess error %#lx\n", ret);
3454 memset(&pbi, 0, sizeof(pbi));
3455 ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
3456 ok(!ret, "NtQueryInformationProcess error %#lx\n", ret);
3457 ok(pbi.ExitStatus == STILL_ACTIVE || pbi.ExitStatus == 195,
3458 "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus);
3459 affinity = 1;
3460 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
3461 ok(!ret, "NtSetInformationProcess error %#lx\n", ret);
3463 ret = pRtlDllShutdownInProgress();
3464 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3466 hmod = GetModuleHandleA(dll_name);
3467 ok(hmod != 0, "DLL should not be unloaded\n");
3469 SetLastError(0xdeadbeef);
3470 thread = CreateThread(NULL, 0, noop_thread_proc, &dummy, 0, &ret);
3471 ok(!thread, "CreateThread should fail\n");
3472 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
3474 trace("call LdrShutdownProcess()\n");
3475 pLdrShutdownProcess();
3477 ret = pRtlDllShutdownInProgress();
3478 ok(ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3480 hmod = GetModuleHandleA(dll_name);
3481 ok(hmod != 0, "DLL should not be unloaded\n");
3483 memset(&pbi, 0, sizeof(pbi));
3484 ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
3485 ok(!ret, "NtQueryInformationProcess error %#lx\n", ret);
3486 ok(pbi.ExitStatus == STILL_ACTIVE || pbi.ExitStatus == 195,
3487 "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus);
3488 affinity = 1;
3489 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
3490 ok(!ret, "NtSetInformationProcess error %#lx\n", ret);
3491 break;
3493 case 1: /* normal ExitProcess */
3494 ret = pRtlDllShutdownInProgress();
3495 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3496 break;
3498 case 2: /* ExitProcess will be called by the PROCESS_DETACH handler */
3499 ret = pRtlDllShutdownInProgress();
3500 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3502 trace("call FreeLibrary(%p)\n", hmod);
3503 SetLastError(0xdeadbeef);
3504 ret = FreeLibrary(hmod);
3505 ok(ret, "FreeLibrary error %ld\n", GetLastError());
3506 hmod = GetModuleHandleA(dll_name);
3507 ok(!hmod, "DLL should be unloaded\n");
3509 if (test_dll_phase == 2)
3510 ok(0, "FreeLibrary+ExitProcess should never return\n");
3512 ret = pRtlDllShutdownInProgress();
3513 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3515 break;
3517 case 3:
3518 trace("signalling thread exit\n");
3519 SetEvent(stop_event);
3520 break;
3522 case 4:
3523 trace("setting loader_lock_event\n");
3524 SetEvent(loader_lock_event);
3525 WaitForSingleObject(ack_event, 1000);
3526 ok(inside_loader_lock != 0, "inside_loader_lock is not set\n");
3528 /* calling NtTerminateProcess should not cause a deadlock */
3529 trace("call NtTerminateProcess(0, 198)\n");
3530 ret = pNtTerminateProcess(0, 198);
3531 ok(!ret, "NtTerminateProcess error %#lx\n", ret);
3533 *child_failures = winetest_get_failures();
3535 /* Windows fails to release loader lock acquired from another thread,
3536 * so the LdrUnlockLoaderLock call fails here and ExitProcess deadlocks
3537 * later on, so NtTerminateProcess is used instead.
3539 trace("call NtTerminateProcess(GetCurrentProcess(), 198)\n");
3540 pNtTerminateProcess(GetCurrentProcess(), 198);
3541 ok(0, "NtTerminateProcess should not return\n");
3542 break;
3544 case 5:
3545 trace("setting peb_lock_event\n");
3546 SetEvent(peb_lock_event);
3547 WaitForSingleObject(ack_event, 1000);
3548 ok(inside_peb_lock != 0, "inside_peb_lock is not set\n");
3550 *child_failures = winetest_get_failures();
3552 /* calling ExitProcess should cause a deadlock */
3553 trace("call ExitProcess(198)\n");
3554 ExitProcess(198);
3555 ok(0, "ExitProcess should not return\n");
3556 break;
3558 case 6:
3559 trace("setting heap_lock_event\n");
3560 SetEvent(heap_lock_event);
3561 WaitForSingleObject(ack_event, 1000);
3562 ok(inside_heap_lock != 0, "inside_heap_lock is not set\n");
3564 *child_failures = winetest_get_failures();
3566 /* calling ExitProcess should cause a deadlock */
3567 trace("call ExitProcess(1)\n");
3568 ExitProcess(1);
3569 ok(0, "ExitProcess should not return\n");
3570 break;
3572 case 7:
3573 trace("setting cs_lock_event\n");
3574 SetEvent(cs_lock_event);
3575 WaitForSingleObject(ack_event, 1000);
3576 ok(inside_cs_lock != 0, "inside_cs_lock is not set\n");
3578 *child_failures = winetest_get_failures();
3580 /* calling ExitProcess should not cause a deadlock */
3581 trace("call ExitProcess(199)\n");
3582 ExitProcess(199);
3583 ok(0, "ExitProcess should not return\n");
3584 break;
3586 default:
3587 assert(0);
3588 break;
3591 if (test_dll_phase == 0) expected_code = 195;
3592 else if (test_dll_phase == 3) expected_code = 196;
3593 else if (test_dll_phase == 4) expected_code = 198;
3594 else expected_code = STILL_ACTIVE;
3596 if (expected_code == STILL_ACTIVE)
3598 ret = WaitForSingleObject(attached_thread[0], 100);
3599 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3600 ret = WaitForSingleObject(attached_thread[1], 100);
3601 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3603 else
3605 ret = WaitForSingleObject(attached_thread[0], 2000);
3606 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret);
3607 ret = WaitForSingleObject(attached_thread[1], 2000);
3608 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret);
3611 for (i = 0; i < attached_thread_count; i++)
3613 ret = GetExitCodeThread(attached_thread[i], &code);
3614 trace("child: GetExitCodeThread(%lu) => %ld,%lu\n", i, ret, code);
3615 ok(ret == 1, "GetExitCodeThread returned %ld, expected 1\n", ret);
3616 ok(code == expected_code, "expected thread exit code %lu, got %lu\n", expected_code, code);
3619 *child_failures = winetest_get_failures();
3621 trace("call ExitProcess(195)\n");
3622 ExitProcess(195);
3625 static void test_ExitProcess(void)
3627 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
3628 #include "pshpack1.h"
3629 #ifdef __x86_64__
3630 static struct section_data
3632 BYTE mov_rax[2];
3633 void *target;
3634 BYTE jmp_rax[2];
3635 } section_data = { { 0x48,0xb8 }, dll_entry_point, { 0xff,0xe0 } };
3636 #elif defined(__i386__)
3637 static struct section_data
3639 BYTE mov_eax;
3640 void *target;
3641 BYTE jmp_eax[2];
3642 } section_data = { 0xb8, dll_entry_point, { 0xff,0xe0 } };
3643 #elif defined(__aarch64__)
3644 static struct section_data
3646 DWORD ldr; /* ldr x0,target */
3647 DWORD br; /* br x0 */
3648 void *target;
3649 } section_data = { 0x58000040, 0xd61f0000, dll_entry_point };
3650 #endif
3651 #include "poppack.h"
3652 DWORD dummy, file_align;
3653 HANDLE file, thread, process, hmap, hmap_dup;
3654 char temp_path[MAX_PATH], dll_name[MAX_PATH], cmdline[MAX_PATH * 2];
3655 DWORD ret, target_offset, old_prot;
3656 char **argv, buf[256];
3657 PROCESS_INFORMATION pi;
3658 STARTUPINFOA si = { sizeof(si) };
3659 CONTEXT ctx;
3660 struct PROCESS_BASIC_INFORMATION_PRIVATE pbi;
3661 MEMORY_BASIC_INFORMATION mbi;
3662 DWORD_PTR affinity;
3663 void *addr;
3664 LARGE_INTEGER offset;
3665 SIZE_T size;
3666 IMAGE_NT_HEADERS nt_header;
3668 if (!pRtlDllShutdownInProgress)
3670 win_skip("RtlDllShutdownInProgress is not available on this platform (XP+)\n");
3671 return;
3673 if (!pNtQueryInformationProcess || !pNtSetInformationProcess)
3675 win_skip("NtQueryInformationProcess/NtSetInformationProcess are not available on this platform\n");
3676 return;
3678 if (!pNtAllocateVirtualMemory || !pNtFreeVirtualMemory)
3680 win_skip("NtAllocateVirtualMemory/NtFreeVirtualMemory are not available on this platform\n");
3681 return;
3684 /* prevent displaying of the "Unable to load this DLL" message box */
3685 SetErrorMode(SEM_FAILCRITICALERRORS);
3687 GetTempPathA(MAX_PATH, temp_path);
3688 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
3690 /*trace("creating %s\n", dll_name);*/
3691 file = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
3692 if (file == INVALID_HANDLE_VALUE)
3694 ok(0, "could not create %s\n", dll_name);
3695 return;
3698 SetLastError(0xdeadbeef);
3699 ret = WriteFile(file, &dos_header, sizeof(dos_header), &dummy, NULL);
3700 ok(ret, "WriteFile error %ld\n", GetLastError());
3702 nt_header = nt_header_template;
3703 nt_header.OptionalHeader.AddressOfEntryPoint = 0x1000;
3704 nt_header.OptionalHeader.SectionAlignment = 0x1000;
3705 nt_header.OptionalHeader.FileAlignment = 0x200;
3706 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000;
3707 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
3708 SetLastError(0xdeadbeef);
3709 ret = WriteFile(file, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
3710 ok(ret, "WriteFile error %ld\n", GetLastError());
3711 SetLastError(0xdeadbeef);
3712 ret = WriteFile(file, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
3713 ok(ret, "WriteFile error %ld\n", GetLastError());
3715 section.SizeOfRawData = sizeof(section_data);
3716 section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
3717 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
3718 section.Misc.VirtualSize = sizeof(section_data);
3719 section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
3720 SetLastError(0xdeadbeef);
3721 ret = WriteFile(file, &section, sizeof(section), &dummy, NULL);
3722 ok(ret, "WriteFile error %ld\n", GetLastError());
3724 file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
3725 assert(file_align < sizeof(filler));
3726 SetLastError(0xdeadbeef);
3727 ret = WriteFile(file, filler, file_align, &dummy, NULL);
3728 ok(ret, "WriteFile error %ld\n", GetLastError());
3730 target_offset = SetFilePointer(file, 0, NULL, FILE_CURRENT) + FIELD_OFFSET(struct section_data, target);
3732 /* section data */
3733 SetLastError(0xdeadbeef);
3734 ret = WriteFile(file, &section_data, sizeof(section_data), &dummy, NULL);
3735 ok(ret, "WriteFile error %ld\n", GetLastError());
3737 CloseHandle(file);
3739 winetest_get_mainargs(&argv);
3741 /* phase 0 */
3742 *child_failures = -1;
3743 sprintf(cmdline, "\"%s\" loader %s %lu 0", argv[0], dll_name, target_offset);
3744 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3745 ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError());
3746 ret = WaitForSingleObject(pi.hProcess, 10000);
3747 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3748 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
3749 GetExitCodeProcess(pi.hProcess, &ret);
3750 ok(ret == 195, "expected exit code 195, got %lu\n", ret);
3751 if (*child_failures)
3753 trace("%ld failures in child process\n", *child_failures);
3754 winetest_add_failures(*child_failures);
3756 CloseHandle(pi.hThread);
3757 CloseHandle(pi.hProcess);
3759 /* phase 1 */
3760 *child_failures = -1;
3761 sprintf(cmdline, "\"%s\" loader %s %lu 1", argv[0], dll_name, target_offset);
3762 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3763 ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError());
3764 ret = WaitForSingleObject(pi.hProcess, 10000);
3765 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3766 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
3767 GetExitCodeProcess(pi.hProcess, &ret);
3768 ok(ret == 195, "expected exit code 195, got %lu\n", ret);
3769 if (*child_failures)
3771 trace("%ld failures in child process\n", *child_failures);
3772 winetest_add_failures(*child_failures);
3774 CloseHandle(pi.hThread);
3775 CloseHandle(pi.hProcess);
3777 /* phase 2 */
3778 *child_failures = -1;
3779 sprintf(cmdline, "\"%s\" loader %s %lu 2", argv[0], dll_name, target_offset);
3780 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3781 ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError());
3782 ret = WaitForSingleObject(pi.hProcess, 10000);
3783 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3784 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
3785 GetExitCodeProcess(pi.hProcess, &ret);
3786 ok(ret == 197, "expected exit code 197, got %lu\n", ret);
3787 if (*child_failures)
3789 trace("%ld failures in child process\n", *child_failures);
3790 winetest_add_failures(*child_failures);
3792 CloseHandle(pi.hThread);
3793 CloseHandle(pi.hProcess);
3795 /* phase 3 */
3796 *child_failures = -1;
3797 sprintf(cmdline, "\"%s\" loader %s %lu 3", argv[0], dll_name, target_offset);
3798 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3799 ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError());
3800 ret = WaitForSingleObject(pi.hProcess, 10000);
3801 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3802 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
3803 GetExitCodeProcess(pi.hProcess, &ret);
3804 ok(ret == 195, "expected exit code 195, got %lu\n", ret);
3805 if (*child_failures)
3807 trace("%ld failures in child process\n", *child_failures);
3808 winetest_add_failures(*child_failures);
3810 CloseHandle(pi.hThread);
3811 CloseHandle(pi.hProcess);
3813 /* phase 4 */
3814 if (pLdrLockLoaderLock && pLdrUnlockLoaderLock)
3816 *child_failures = -1;
3817 sprintf(cmdline, "\"%s\" loader %s %lu 4", argv[0], dll_name, target_offset);
3818 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3819 ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError());
3820 ret = WaitForSingleObject(pi.hProcess, 10000);
3821 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3822 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
3823 GetExitCodeProcess(pi.hProcess, &ret);
3824 ok(ret == 198, "expected exit code 198, got %lu\n", ret);
3825 if (*child_failures)
3827 trace("%ld failures in child process\n", *child_failures);
3828 winetest_add_failures(*child_failures);
3830 CloseHandle(pi.hThread);
3831 CloseHandle(pi.hProcess);
3833 else
3834 win_skip("LdrLockLoaderLock/LdrUnlockLoaderLock are not available on this platform\n");
3836 /* phase 5 */
3837 if (pRtlAcquirePebLock && pRtlReleasePebLock)
3839 *child_failures = -1;
3840 sprintf(cmdline, "\"%s\" loader %s %lu 5", argv[0], dll_name, target_offset);
3841 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3842 ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError());
3843 ret = WaitForSingleObject(pi.hProcess, 5000);
3844 ok(ret == WAIT_TIMEOUT, "child process should fail to terminate\n");
3845 if (ret != WAIT_OBJECT_0)
3847 trace("terminating child process\n");
3848 TerminateProcess(pi.hProcess, 199);
3850 ret = WaitForSingleObject(pi.hProcess, 1000);
3851 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3852 GetExitCodeProcess(pi.hProcess, &ret);
3853 ok(ret == 199, "expected exit code 199, got %lu\n", ret);
3854 if (*child_failures)
3856 trace("%ld failures in child process\n", *child_failures);
3857 winetest_add_failures(*child_failures);
3859 CloseHandle(pi.hThread);
3860 CloseHandle(pi.hProcess);
3862 else
3863 win_skip("RtlAcquirePebLock/RtlReleasePebLock are not available on this platform\n");
3865 /* phase 6 */
3866 *child_failures = -1;
3867 sprintf(cmdline, "\"%s\" loader %s %lu 6", argv[0], dll_name, target_offset);
3868 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3869 ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError());
3870 ret = WaitForSingleObject(pi.hProcess, 5000);
3871 todo_wine
3872 ok(ret == WAIT_TIMEOUT, "child process should fail to terminate\n");
3873 if (ret != WAIT_OBJECT_0)
3875 trace("terminating child process\n");
3876 TerminateProcess(pi.hProcess, 201);
3878 ret = WaitForSingleObject(pi.hProcess, 1000);
3879 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3880 GetExitCodeProcess(pi.hProcess, &ret);
3881 todo_wine
3882 ok(ret == 201, "expected exit code 201, got %lu\n", ret);
3883 if (*child_failures)
3885 trace("%ld failures in child process\n", *child_failures);
3886 winetest_add_failures(*child_failures);
3888 CloseHandle(pi.hThread);
3889 CloseHandle(pi.hProcess);
3891 /* phase 7 */
3892 *child_failures = -1;
3893 sprintf(cmdline, "\"%s\" loader %s %lu 7", argv[0], dll_name, target_offset);
3894 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3895 ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError());
3896 ret = WaitForSingleObject(pi.hProcess, 5000);
3897 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3898 if (ret != WAIT_OBJECT_0)
3900 trace("terminating child process\n");
3901 TerminateProcess(pi.hProcess, 199);
3903 ret = WaitForSingleObject(pi.hProcess, 1000);
3904 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3905 GetExitCodeProcess(pi.hProcess, &ret);
3906 ok(ret == 199, "expected exit code 199, got %lu\n", ret);
3907 if (*child_failures)
3909 trace("%ld failures in child process\n", *child_failures);
3910 winetest_add_failures(*child_failures);
3912 CloseHandle(pi.hThread);
3913 CloseHandle(pi.hProcess);
3915 /* test remote process termination */
3916 SetLastError(0xdeadbeef);
3917 ret = CreateProcessA(argv[0], NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
3918 ok(ret, "CreateProcess(%s) error %ld\n", argv[0], GetLastError());
3920 SetLastError(0xdeadbeef);
3921 addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
3922 ok(addr != NULL, "VirtualAllocEx error %ld\n", GetLastError());
3923 SetLastError(0xdeadbeef);
3924 ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READONLY, &old_prot);
3925 ok(ret, "VirtualProtectEx error %ld\n", GetLastError());
3926 ok(old_prot == PAGE_READWRITE, "expected PAGE_READWRITE, got %#lx\n", old_prot);
3927 SetLastError(0xdeadbeef);
3928 size = VirtualQueryEx(pi.hProcess, NULL, &mbi, sizeof(mbi));
3929 ok(size == sizeof(mbi), "VirtualQueryEx error %ld\n", GetLastError());
3931 SetLastError(0xdeadbeef);
3932 ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size);
3933 ok(ret, "ReadProcessMemory error %ld\n", GetLastError());
3934 ok(size == 4, "expected 4, got %Iu\n", size);
3936 SetLastError(0xdeadbeef);
3937 hmap = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
3938 ok(hmap != 0, "CreateFileMapping error %ld\n", GetLastError());
3940 SetLastError(0xdeadbeef);
3941 ret = DuplicateHandle(GetCurrentProcess(), hmap, pi.hProcess, &hmap_dup,
3942 0, FALSE, DUPLICATE_SAME_ACCESS);
3943 ok(ret, "DuplicateHandle error %ld\n", GetLastError());
3945 offset.u.LowPart = 0;
3946 offset.u.HighPart = 0;
3947 addr = NULL;
3948 size = 0;
3949 ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset,
3950 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
3951 ok(!ret, "NtMapViewOfSection error %#lx\n", ret);
3952 ret = pNtUnmapViewOfSection(pi.hProcess, addr);
3953 ok(!ret, "NtUnmapViewOfSection error %#lx\n", ret);
3955 SetLastError(0xdeadbeef);
3956 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
3957 ok(thread != 0, "CreateRemoteThread error %ld\n", GetLastError());
3958 SetLastError(0xdeadbeef);
3959 ctx.ContextFlags = CONTEXT_INTEGER;
3960 ret = GetThreadContext(thread, &ctx);
3961 ok(ret, "GetThreadContext error %ld\n", GetLastError());
3962 SetLastError(0xdeadbeef);
3963 ctx.ContextFlags = CONTEXT_INTEGER;
3964 ret = SetThreadContext(thread, &ctx);
3965 ok(ret, "SetThreadContext error %ld\n", GetLastError());
3966 SetLastError(0xdeadbeef);
3967 ret = SetThreadPriority(thread, 0);
3968 ok(ret, "SetThreadPriority error %ld\n", GetLastError());
3970 SetLastError(0xdeadbeef);
3971 ret = TerminateThread(thread, 199);
3972 ok(ret, "TerminateThread error %ld\n", GetLastError());
3973 /* Calling GetExitCodeThread() without waiting for thread termination
3974 * leads to different results due to a race condition.
3976 ret = WaitForSingleObject(thread, 1000);
3977 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %lx\n", ret);
3978 GetExitCodeThread(thread, &ret);
3979 ok(ret == 199, "expected exit code 199, got %lu\n", ret);
3981 SetLastError(0xdeadbeef);
3982 ret = TerminateProcess(pi.hProcess, 198);
3983 ok(ret, "TerminateProcess error %ld\n", GetLastError());
3984 /* Checking process state without waiting for process termination
3985 * leads to different results due to a race condition.
3987 ret = WaitForSingleObject(pi.hProcess, 1000);
3988 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %lx\n", ret);
3990 SetLastError(0xdeadbeef);
3991 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pi.dwProcessId);
3992 ok(process != NULL, "OpenProcess error %ld\n", GetLastError());
3993 CloseHandle(process);
3995 memset(&pbi, 0, sizeof(pbi));
3996 ret = pNtQueryInformationProcess(pi.hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
3997 ok(!ret, "NtQueryInformationProcess error %#lx\n", ret);
3998 ok(pbi.ExitStatus == 198, "expected 198, got %lu\n", pbi.ExitStatus);
3999 affinity = 1;
4000 ret = pNtSetInformationProcess(pi.hProcess, ProcessAffinityMask, &affinity, sizeof(affinity));
4001 ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#lx\n", ret);
4003 SetLastError(0xdeadbeef);
4004 ctx.ContextFlags = CONTEXT_INTEGER;
4005 ret = GetThreadContext(thread, &ctx);
4006 ok(!ret, "GetThreadContext should fail\n");
4007 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
4008 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
4009 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */ ||
4010 GetLastError() == ERROR_ACCESS_DENIED /* Win10 32-bit */,
4011 "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4012 SetLastError(0xdeadbeef);
4013 ctx.ContextFlags = CONTEXT_INTEGER;
4014 ret = SetThreadContext(thread, &ctx);
4015 ok(!ret, "SetThreadContext should fail\n");
4016 ok(GetLastError() == ERROR_ACCESS_DENIED ||
4017 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
4018 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
4019 "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4020 SetLastError(0xdeadbeef);
4021 ret = SetThreadPriority(thread, 0);
4022 ok(ret, "SetThreadPriority error %ld\n", GetLastError());
4023 CloseHandle(thread);
4025 ret = WaitForSingleObject(pi.hThread, 1000);
4026 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %lx\n", ret);
4027 SetLastError(0xdeadbeef);
4028 ctx.ContextFlags = CONTEXT_INTEGER;
4029 ret = GetThreadContext(pi.hThread, &ctx);
4030 ok(!ret, "GetThreadContext should fail\n");
4031 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
4032 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
4033 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */ ||
4034 GetLastError() == ERROR_ACCESS_DENIED /* Win10 32-bit */,
4035 "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4036 SetLastError(0xdeadbeef);
4037 ctx.ContextFlags = CONTEXT_INTEGER;
4038 ret = SetThreadContext(pi.hThread, &ctx);
4039 ok(!ret, "SetThreadContext should fail\n");
4040 ok(GetLastError() == ERROR_ACCESS_DENIED ||
4041 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
4042 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
4043 "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4044 SetLastError(0xdeadbeef);
4045 ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READWRITE, &old_prot);
4046 ok(!ret, "VirtualProtectEx should fail\n");
4047 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4048 SetLastError(0xdeadbeef);
4049 size = 0;
4050 ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size);
4051 ok(!ret, "ReadProcessMemory should fail\n");
4052 ok(GetLastError() == ERROR_PARTIAL_COPY || GetLastError() == ERROR_ACCESS_DENIED,
4053 "expected ERROR_PARTIAL_COPY, got %ld\n", GetLastError());
4054 ok(!size, "expected 0, got %Iu\n", size);
4055 SetLastError(0xdeadbeef);
4056 ret = VirtualFreeEx(pi.hProcess, addr, 0, MEM_RELEASE);
4057 ok(!ret, "VirtualFreeEx should fail\n");
4058 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4059 SetLastError(0xdeadbeef);
4060 addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
4061 ok(!addr, "VirtualAllocEx should fail\n");
4062 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4063 SetLastError(0xdeadbeef);
4064 size = VirtualQueryEx(pi.hProcess, NULL, &mbi, sizeof(mbi));
4065 ok(!size, "VirtualQueryEx should fail\n");
4066 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4068 /* CloseHandle() call below leads to premature process termination
4069 * under some Windows versions.
4071 if (0)
4073 SetLastError(0xdeadbeef);
4074 ret = CloseHandle(hmap_dup);
4075 ok(ret, "CloseHandle should not fail\n");
4078 SetLastError(0xdeadbeef);
4079 ret = DuplicateHandle(GetCurrentProcess(), hmap, pi.hProcess, &hmap_dup,
4080 0, FALSE, DUPLICATE_SAME_ACCESS);
4081 ok(!ret, "DuplicateHandle should fail\n");
4082 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4084 offset.u.LowPart = 0;
4085 offset.u.HighPart = 0;
4086 addr = NULL;
4087 size = 0;
4088 ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset,
4089 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
4090 ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#lx\n", ret);
4092 SetLastError(0xdeadbeef);
4093 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
4094 ok(!thread, "CreateRemoteThread should fail\n");
4095 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4097 SetLastError(0xdeadbeef);
4098 ret = DebugActiveProcess(pi.dwProcessId);
4099 ok(!ret, "DebugActiveProcess should fail\n");
4100 ok(GetLastError() == ERROR_ACCESS_DENIED /* 64-bit */ || GetLastError() == ERROR_NOT_SUPPORTED /* 32-bit */,
4101 "ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4103 GetExitCodeProcess(pi.hProcess, &ret);
4104 ok(ret == 198, "expected exit code 198, got %lu\n", ret);
4105 CloseHandle(pi.hThread);
4106 CloseHandle(pi.hProcess);
4108 ret = DeleteFileA(dll_name);
4109 ok(ret, "DeleteFile error %ld\n", GetLastError());
4110 #else
4111 skip("x86 specific ExitProcess test\n");
4112 #endif
4115 static PVOID WINAPI failuredllhook(ULONG ul, DELAYLOAD_INFO* pd)
4117 ok(ul == 4, "expected 4, got %lu\n", ul);
4118 ok(!!pd, "no delayload info supplied\n");
4119 if (pd)
4121 ok(pd->Size == sizeof(*pd), "got %lu\n", pd->Size);
4122 ok(!!pd->DelayloadDescriptor, "no DelayloadDescriptor supplied\n");
4123 if (pd->DelayloadDescriptor)
4125 ok(pd->DelayloadDescriptor->Attributes.AllAttributes == 1,
4126 "expected 1, got %lu\n", pd->DelayloadDescriptor->Attributes.AllAttributes);
4127 ok(pd->DelayloadDescriptor->DllNameRVA == 0x2000,
4128 "expected 0x2000, got %lx\n", pd->DelayloadDescriptor->DllNameRVA);
4129 ok(pd->DelayloadDescriptor->ModuleHandleRVA == 0x201a,
4130 "expected 0x201a, got %lx\n", pd->DelayloadDescriptor->ModuleHandleRVA);
4131 ok(pd->DelayloadDescriptor->ImportAddressTableRVA > pd->DelayloadDescriptor->ModuleHandleRVA,
4132 "expected %lx > %lx\n", pd->DelayloadDescriptor->ImportAddressTableRVA,
4133 pd->DelayloadDescriptor->ModuleHandleRVA);
4134 ok(pd->DelayloadDescriptor->ImportNameTableRVA > pd->DelayloadDescriptor->ImportAddressTableRVA,
4135 "expected %lx > %lx\n", pd->DelayloadDescriptor->ImportNameTableRVA,
4136 pd->DelayloadDescriptor->ImportAddressTableRVA);
4137 ok(pd->DelayloadDescriptor->BoundImportAddressTableRVA == 0,
4138 "expected 0, got %lx\n", pd->DelayloadDescriptor->BoundImportAddressTableRVA);
4139 ok(pd->DelayloadDescriptor->UnloadInformationTableRVA == 0,
4140 "expected 0, got %lx\n", pd->DelayloadDescriptor->UnloadInformationTableRVA);
4141 ok(pd->DelayloadDescriptor->TimeDateStamp == 0,
4142 "expected 0, got %lx\n", pd->DelayloadDescriptor->TimeDateStamp);
4145 ok(!!pd->ThunkAddress, "no ThunkAddress supplied\n");
4146 if (pd->ThunkAddress)
4147 ok(pd->ThunkAddress->u1.Ordinal, "no ThunkAddress value supplied\n");
4149 ok(!!pd->TargetDllName, "no TargetDllName supplied\n");
4150 if (pd->TargetDllName)
4151 ok(!strcmp(pd->TargetDllName, "secur32.dll"),
4152 "expected \"secur32.dll\", got \"%s\"\n", pd->TargetDllName);
4154 ok(pd->TargetApiDescriptor.ImportDescribedByName == 0,
4155 "expected 0, got %lx\n", pd->TargetApiDescriptor.ImportDescribedByName);
4156 ok(pd->TargetApiDescriptor.Description.Ordinal == 0 ||
4157 pd->TargetApiDescriptor.Description.Ordinal == 999,
4158 "expected 0, got %lx\n", pd->TargetApiDescriptor.Description.Ordinal);
4160 ok(!!pd->TargetModuleBase, "no TargetModuleBase supplied\n");
4161 ok(pd->Unused == NULL, "expected NULL, got %p\n", pd->Unused);
4162 ok(pd->LastError, "no LastError supplied\n");
4164 cb_count++;
4165 return (void*)0xdeadbeef;
4168 static PVOID WINAPI failuresyshook(const char *dll, const char *function)
4170 ok(!strcmp(dll, "secur32.dll"), "wrong dll: %s\n", dll);
4171 ok(!((ULONG_PTR)function >> 16), "expected ordinal, got %p\n", function);
4172 cb_count_sys++;
4173 return (void*)0x12345678;
4176 static void test_ResolveDelayLoadedAPI(void)
4178 static const char test_dll[] = "secur32.dll";
4179 static const char test_func[] = "SealMessage";
4180 char temp_path[MAX_PATH];
4181 char dll_name[MAX_PATH];
4182 IMAGE_DELAYLOAD_DESCRIPTOR idd, *delaydir;
4183 IMAGE_THUNK_DATA itd32;
4184 HANDLE hfile;
4185 HMODULE hlib;
4186 DWORD dummy, file_size, i;
4187 WORD hint = 0;
4188 BOOL ret;
4189 IMAGE_NT_HEADERS nt_header;
4191 static const struct test_data
4193 BOOL func;
4194 UINT_PTR ordinal;
4195 BOOL succeeds;
4196 } td[] =
4199 TRUE, 0, TRUE
4202 FALSE, IMAGE_ORDINAL_FLAG | 2, TRUE
4205 FALSE, IMAGE_ORDINAL_FLAG | 5, TRUE
4208 FALSE, IMAGE_ORDINAL_FLAG | 0, FALSE
4211 FALSE, IMAGE_ORDINAL_FLAG | 999, FALSE
4215 if (!pResolveDelayLoadedAPI)
4217 win_skip("ResolveDelayLoadedAPI is not available\n");
4218 return;
4221 if (0) /* crashes on native */
4223 SetLastError(0xdeadbeef);
4224 ok(!pResolveDelayLoadedAPI(NULL, NULL, NULL, NULL, NULL, 0),
4225 "ResolveDelayLoadedAPI succeeded\n");
4226 ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %lx\n", GetLastError());
4228 cb_count = 0;
4229 SetLastError(0xdeadbeef);
4230 ok(!pResolveDelayLoadedAPI(NULL, NULL, failuredllhook, NULL, NULL, 0),
4231 "ResolveDelayLoadedAPI succeeded\n");
4232 ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %lx\n", GetLastError());
4233 ok(cb_count == 1, "Wrong callback count: %d\n", cb_count);
4236 GetTempPathA(MAX_PATH, temp_path);
4237 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
4238 trace("creating %s\n", dll_name);
4239 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
4240 if (hfile == INVALID_HANDLE_VALUE)
4242 ok(0, "could not create %s\n", dll_name);
4243 return;
4246 SetLastError(0xdeadbeef);
4247 ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
4248 ok(ret, "WriteFile error %ld\n", GetLastError());
4250 nt_header = nt_header_template;
4251 nt_header.FileHeader.NumberOfSections = 2;
4252 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
4254 nt_header.OptionalHeader.SectionAlignment = 0x1000;
4255 nt_header.OptionalHeader.FileAlignment = 0x1000;
4256 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x2200;
4257 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + 2 * sizeof(IMAGE_SECTION_HEADER);
4258 nt_header.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
4259 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress = 0x1000;
4260 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size = 2 * sizeof(idd);
4262 SetLastError(0xdeadbeef);
4263 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
4264 ok(ret, "WriteFile error %ld\n", GetLastError());
4266 SetLastError(0xdeadbeef);
4267 ret = WriteFile(hfile, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
4268 ok(ret, "WriteFile error %ld\n", GetLastError());
4270 /* sections */
4271 section.PointerToRawData = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
4272 section.VirtualAddress = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
4273 section.Misc.VirtualSize = 0x1000;
4274 section.SizeOfRawData = 2 * sizeof(idd);
4275 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
4276 SetLastError(0xdeadbeef);
4277 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
4278 ok(ret, "WriteFile error %ld\n", GetLastError());
4280 section.PointerToRawData = 0x2000;
4281 section.VirtualAddress = 0x2000;
4282 i = ARRAY_SIZE(td);
4283 section.SizeOfRawData = sizeof(test_dll) + sizeof(hint) + sizeof(test_func) + sizeof(HMODULE) +
4284 2 * (i + 1) * sizeof(IMAGE_THUNK_DATA);
4285 ok(section.SizeOfRawData <= 0x1000, "Too much tests, add a new section!\n");
4286 section.Misc.VirtualSize = 0x1000;
4287 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
4288 SetLastError(0xdeadbeef);
4289 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
4290 ok(ret, "WriteFile error %ld\n", GetLastError());
4292 /* fill up to delay data */
4293 SetFilePointer( hfile, nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress, NULL, SEEK_SET );
4295 /* delay data */
4296 idd.Attributes.AllAttributes = 1;
4297 idd.DllNameRVA = 0x2000;
4298 idd.ModuleHandleRVA = idd.DllNameRVA + sizeof(test_dll) + sizeof(hint) + sizeof(test_func);
4299 idd.ImportAddressTableRVA = idd.ModuleHandleRVA + sizeof(HMODULE);
4300 idd.ImportNameTableRVA = idd.ImportAddressTableRVA + (i + 1) * sizeof(IMAGE_THUNK_DATA);
4301 idd.BoundImportAddressTableRVA = 0;
4302 idd.UnloadInformationTableRVA = 0;
4303 idd.TimeDateStamp = 0;
4305 SetLastError(0xdeadbeef);
4306 ret = WriteFile(hfile, &idd, sizeof(idd), &dummy, NULL);
4307 ok(ret, "WriteFile error %ld\n", GetLastError());
4309 SetLastError(0xdeadbeef);
4310 ret = WriteFile(hfile, filler, sizeof(idd), &dummy, NULL);
4311 ok(ret, "WriteFile error %ld\n", GetLastError());
4313 /* fill up to extended delay data */
4314 SetFilePointer( hfile, idd.DllNameRVA, NULL, SEEK_SET );
4316 /* extended delay data */
4317 SetLastError(0xdeadbeef);
4318 ret = WriteFile(hfile, test_dll, sizeof(test_dll), &dummy, NULL);
4319 ok(ret, "WriteFile error %ld\n", GetLastError());
4321 SetLastError(0xdeadbeef);
4322 ret = WriteFile(hfile, &hint, sizeof(hint), &dummy, NULL);
4323 ok(ret, "WriteFile error %ld\n", GetLastError());
4325 SetLastError(0xdeadbeef);
4326 ret = WriteFile(hfile, test_func, sizeof(test_func), &dummy, NULL);
4327 ok(ret, "WriteFile error %ld\n", GetLastError());
4329 SetFilePointer( hfile, idd.ImportAddressTableRVA, NULL, SEEK_SET );
4331 for (i = 0; i < ARRAY_SIZE(td); i++)
4333 /* 0x1a00 is an empty space between delay data and extended delay data, real thunks are not necessary */
4334 itd32.u1.Function = nt_header.OptionalHeader.ImageBase + 0x1a00 + i * 0x20;
4335 SetLastError(0xdeadbeef);
4336 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
4337 ok(ret, "WriteFile error %ld\n", GetLastError());
4340 itd32.u1.Function = 0;
4341 SetLastError(0xdeadbeef);
4342 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
4343 ok(ret, "WriteFile error %ld\n", GetLastError());
4345 for (i = 0; i < ARRAY_SIZE(td); i++)
4347 if (td[i].func)
4348 itd32.u1.AddressOfData = idd.DllNameRVA + sizeof(test_dll);
4349 else
4350 itd32.u1.Ordinal = td[i].ordinal;
4351 SetLastError(0xdeadbeef);
4352 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
4353 ok(ret, "WriteFile error %ld\n", GetLastError());
4356 itd32.u1.Ordinal = 0;
4357 SetLastError(0xdeadbeef);
4358 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
4359 ok(ret, "WriteFile error %ld\n", GetLastError());
4361 /* fill up to eof */
4362 SetFilePointer( hfile, section.VirtualAddress + section.Misc.VirtualSize, NULL, SEEK_SET );
4363 SetEndOfFile( hfile );
4364 CloseHandle(hfile);
4366 SetLastError(0xdeadbeef);
4367 hlib = LoadLibraryA(dll_name);
4368 ok(hlib != NULL, "LoadLibrary error %lu\n", GetLastError());
4369 if (!hlib)
4371 skip("couldn't load %s.\n", dll_name);
4372 DeleteFileA(dll_name);
4373 return;
4376 delaydir = pRtlImageDirectoryEntryToData(hlib, TRUE, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, &file_size);
4377 if (!delaydir)
4379 skip("haven't found section for delay import directory.\n");
4380 FreeLibrary(hlib);
4381 DeleteFileA(dll_name);
4382 return;
4385 for (;;)
4387 IMAGE_THUNK_DATA *itdn, *itda;
4388 HMODULE htarget;
4390 if (!delaydir->DllNameRVA ||
4391 !delaydir->ImportAddressTableRVA ||
4392 !delaydir->ImportNameTableRVA) break;
4394 itdn = RVAToAddr(delaydir->ImportNameTableRVA, hlib);
4395 itda = RVAToAddr(delaydir->ImportAddressTableRVA, hlib);
4396 htarget = LoadLibraryA(RVAToAddr(delaydir->DllNameRVA, hlib));
4398 for (i = 0; i < ARRAY_SIZE(td); i++)
4400 void *ret, *load;
4402 /* relocate thunk address by hand since we don't generate reloc records */
4403 itda[i].u1.AddressOfData += (char *)hlib - (char *)nt_header.OptionalHeader.ImageBase;
4405 if (IMAGE_SNAP_BY_ORDINAL(itdn[i].u1.Ordinal))
4406 load = (void *)GetProcAddress(htarget, (LPSTR)IMAGE_ORDINAL(itdn[i].u1.Ordinal));
4407 else
4409 const IMAGE_IMPORT_BY_NAME* iibn = RVAToAddr(itdn[i].u1.AddressOfData, hlib);
4410 load = (void *)GetProcAddress(htarget, (char*)iibn->Name);
4413 /* test without failure dll callback */
4414 cb_count = cb_count_sys = 0;
4415 ret = pResolveDelayLoadedAPI(hlib, delaydir, NULL, failuresyshook, &itda[i], 0);
4416 if (td[i].succeeds)
4418 ok(ret != NULL, "Test %lu: ResolveDelayLoadedAPI failed\n", i);
4419 ok(ret == load, "Test %lu: expected %p, got %p\n", i, load, ret);
4420 ok(ret == (void*)itda[i].u1.AddressOfData, "Test %lu: expected %p, got %p\n",
4421 i, ret, (void*)itda[i].u1.AddressOfData);
4422 ok(!cb_count, "Test %lu: Wrong callback count: %d\n", i, cb_count);
4423 ok(!cb_count_sys, "Test %lu: Wrong sys callback count: %d\n", i, cb_count_sys);
4425 else
4427 ok(ret == (void*)0x12345678, "Test %lu: ResolveDelayLoadedAPI succeeded with %p\n", i, ret);
4428 ok(!cb_count, "Test %lu: Wrong callback count: %d\n", i, cb_count);
4429 ok(cb_count_sys == 1, "Test %lu: Wrong sys callback count: %d\n", i, cb_count_sys);
4432 /* test with failure dll callback */
4433 cb_count = cb_count_sys = 0;
4434 ret = pResolveDelayLoadedAPI(hlib, delaydir, failuredllhook, failuresyshook, &itda[i], 0);
4435 if (td[i].succeeds)
4437 ok(ret != NULL, "Test %lu: ResolveDelayLoadedAPI failed\n", i);
4438 ok(ret == load, "Test %lu: expected %p, got %p\n", i, load, ret);
4439 ok(ret == (void*)itda[i].u1.AddressOfData, "Test %lu: expected %p, got %p\n",
4440 i, ret, (void*)itda[i].u1.AddressOfData);
4441 ok(!cb_count, "Test %lu: Wrong callback count: %d\n", i, cb_count);
4442 ok(!cb_count_sys, "Test %lu: Wrong sys callback count: %d\n", i, cb_count_sys);
4444 else
4446 if (ret == (void*)0x12345678)
4448 /* Win10+ sometimes buffers the address of the stub function */
4449 ok(!cb_count, "Test %lu: Wrong callback count: %d\n", i, cb_count);
4450 ok(!cb_count_sys, "Test %lu: Wrong sys callback count: %d\n", i, cb_count_sys);
4452 else if (ret == (void*)0xdeadbeef)
4454 ok(cb_count == 1, "Test %lu: Wrong callback count: %d\n", i, cb_count);
4455 ok(!cb_count_sys, "Test %lu: Wrong sys callback count: %d\n", i, cb_count_sys);
4457 else
4458 ok(0, "Test %lu: ResolveDelayLoadedAPI succeeded with %p\n", i, ret);
4461 delaydir++;
4464 FreeLibrary(hlib);
4465 trace("deleting %s\n", dll_name);
4466 DeleteFileA(dll_name);
4469 static void test_InMemoryOrderModuleList(void)
4471 PEB_LDR_DATA *ldr = NtCurrentTeb()->Peb->LdrData;
4472 LIST_ENTRY *entry1, *mark1 = &ldr->InLoadOrderModuleList;
4473 LIST_ENTRY *entry2, *mark2 = &ldr->InMemoryOrderModuleList;
4474 LDR_DATA_TABLE_ENTRY *module1, *module2;
4476 ok(ldr->Initialized == TRUE, "expected TRUE, got %u\n", ldr->Initialized);
4478 for (entry1 = mark1->Flink, entry2 = mark2->Flink;
4479 entry1 != mark1 && entry2 != mark2;
4480 entry1 = entry1->Flink, entry2 = entry2->Flink)
4482 module1 = CONTAINING_RECORD(entry1, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
4483 module2 = CONTAINING_RECORD(entry2, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
4484 ok(module1 == module2, "expected module1 == module2, got %p and %p\n", module1, module2);
4486 ok(entry1 == mark1, "expected entry1 == mark1, got %p and %p\n", entry1, mark1);
4487 ok(entry2 == mark2, "expected entry2 == mark2, got %p and %p\n", entry2, mark2);
4490 static BOOL is_path_made_of(const char *filename, const char *pfx, const char *sfx)
4492 const size_t len = strlen(pfx);
4493 return !strncasecmp(filename, pfx, len) && filename[len] == '\\' &&
4494 !strcasecmp(filename + len + 1, sfx);
4497 static void test_wow64_redirection_for_dll(const char *libname, BOOL will_fail)
4499 HMODULE lib;
4500 char buf[256];
4501 const char *modname;
4503 if (!GetModuleHandleA(libname))
4505 lib = LoadLibraryExA(libname, NULL, 0);
4506 ok(lib != NULL, "Loading %s should succeed with WOW64 redirection disabled\n", libname);
4507 /* Win 7/2008R2 return the un-redirected path (i.e. c:\windows\system32\dwrite.dll), test loading it. */
4508 GetModuleFileNameA(lib, buf, sizeof(buf));
4509 FreeLibrary(lib);
4510 lib = LoadLibraryExA(buf, NULL, 0);
4511 ok(lib != NULL, "Loading %s from full path should succeed with WOW64 redirection disabled\n", libname);
4512 if (lib)
4513 FreeLibrary(lib);
4514 modname = strrchr(libname, '\\');
4515 modname = modname ? modname + 1 : libname;
4516 todo_wine_if(will_fail)
4517 ok(is_path_made_of(buf, system_dir, modname) ||
4518 /* Win7 report from syswow64 */ broken(is_path_made_of(buf, syswow_dir, modname)),
4519 "Unexpected loaded DLL name %s for %s\n", buf, libname);
4521 else
4523 skip("%s was already loaded in the process\n", libname);
4527 static void test_wow64_redirection(void)
4529 void *OldValue;
4530 char buffer[MAX_PATH];
4531 static const char *dlls[] = {"wlanapi.dll", "dxgi.dll", "dwrite.dll"};
4532 unsigned i;
4534 if (!is_wow64)
4535 return;
4537 /* Disable FS redirection, then test loading system libraries (pick ones that shouldn't
4538 * already be loaded in this process).
4540 ok(pWow64DisableWow64FsRedirection(&OldValue), "Disabling FS redirection failed\n");
4541 for (i = 0; i < ARRAY_SIZE(dlls); i++)
4543 test_wow64_redirection_for_dll(dlls[i], FALSE);
4544 /* even absolute paths to syswow64 are loaded with path to system32 */
4545 snprintf(buffer, ARRAY_SIZE(buffer), "%s\\%s", syswow_dir, dlls[i]);
4546 test_wow64_redirection_for_dll(buffer, TRUE);
4549 ok(pWow64RevertWow64FsRedirection(OldValue), "Re-enabling FS redirection failed\n");
4550 /* and results don't depend whether redirection is enabled or not */
4551 for (i = 0; i < ARRAY_SIZE(dlls); i++)
4553 test_wow64_redirection_for_dll(dlls[i], FALSE);
4554 snprintf(buffer, ARRAY_SIZE(buffer), "%s\\%s", syswow_dir, dlls[i]);
4555 test_wow64_redirection_for_dll(buffer, TRUE);
4559 static void test_dll_file( const char *name )
4561 HMODULE module = GetModuleHandleA( name );
4562 IMAGE_NT_HEADERS *nt, *nt_file;
4563 IMAGE_SECTION_HEADER *sec, *sec_file;
4564 char path[MAX_PATH];
4565 HANDLE file, mapping;
4566 int i = 0;
4567 void *ptr;
4569 GetModuleFileNameA( module, path, MAX_PATH );
4570 file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
4571 ok( file != INVALID_HANDLE_VALUE, "can't open '%s': %lu\n", path, GetLastError() );
4573 mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 0, NULL );
4574 ok( mapping != NULL, "%s: CreateFileMappingW failed err %lu\n", name, GetLastError() );
4575 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
4576 ok( ptr != NULL, "%s: MapViewOfFile failed err %lu\n", name, GetLastError() );
4577 CloseHandle( mapping );
4578 CloseHandle( file );
4580 nt = pRtlImageNtHeader( module );
4581 nt_file = pRtlImageNtHeader( ptr );
4582 ok( nt_file != NULL, "%s: invalid header\n", path );
4583 #define OK_FIELD(x, f) ok( nt->x == nt_file->x, "%s:%u: wrong " #x " " f " / " f "\n", name, i, nt->x, nt_file->x )
4584 OK_FIELD( FileHeader.NumberOfSections, "%x" );
4585 OK_FIELD( OptionalHeader.AddressOfEntryPoint, "%lx" );
4586 OK_FIELD( OptionalHeader.NumberOfRvaAndSizes, "%lx" );
4587 for (i = 0; i < nt->OptionalHeader.NumberOfRvaAndSizes; i++)
4589 OK_FIELD( OptionalHeader.DataDirectory[i].VirtualAddress, "%lx" );
4590 OK_FIELD( OptionalHeader.DataDirectory[i].Size, "%lx" );
4592 sec = IMAGE_FIRST_SECTION( nt );
4593 sec_file = IMAGE_FIRST_SECTION( nt_file );
4594 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
4595 ok( !memcmp( sec + i, sec_file + i, sizeof(*sec) ), "%s: wrong section %d\n", name, i );
4596 UnmapViewOfFile( ptr );
4597 #undef OK_FIELD
4600 static void test_LoadPackagedLibrary(void)
4602 HMODULE h;
4604 if (!pLoadPackagedLibrary)
4606 win_skip("LoadPackagedLibrary is not available.\n");
4607 return;
4610 SetLastError( 0xdeadbeef );
4611 h = pLoadPackagedLibrary(L"kernel32.dll", 0);
4612 ok(!h && GetLastError() == APPMODEL_ERROR_NO_PACKAGE, "Got unexpected handle %p, GetLastError() %lu.\n",
4613 h, GetLastError());
4616 static void test_Wow64Transition(void)
4618 char buffer[400];
4619 MEMORY_SECTION_NAME *name = (MEMORY_SECTION_NAME *)buffer;
4620 const WCHAR *filepart;
4621 void **pWow64Transition;
4622 NTSTATUS status;
4624 if (!(pWow64Transition = (void *)GetProcAddress(GetModuleHandleA("ntdll"), "Wow64Transition")))
4626 skip("Wow64Transition is not present\n");
4627 return;
4629 if (!is_wow64)
4631 skip("Wow64Transition is not patched\n");
4632 return;
4635 status = NtQueryVirtualMemory(GetCurrentProcess(), *pWow64Transition,
4636 MemoryMappedFilenameInformation, name, sizeof(buffer), NULL);
4637 ok(!status, "got %#lx\n", status);
4638 filepart = name->SectionFileName.Buffer + name->SectionFileName.Length / sizeof(WCHAR);
4639 while (*filepart != '\\') --filepart;
4640 ok(!wcsnicmp(filepart, L"\\wow64cpu.dll", wcslen(L"\\wow64cpu.dll")), "got file name %s\n",
4641 debugstr_wn(name->SectionFileName.Buffer, name->SectionFileName.Length / sizeof(WCHAR)));
4644 START_TEST(loader)
4646 int argc;
4647 char **argv;
4648 HANDLE ntdll, mapping, kernel32;
4649 SYSTEM_INFO si;
4650 DWORD len;
4652 ntdll = GetModuleHandleA("ntdll.dll");
4653 kernel32 = GetModuleHandleA("kernel32.dll");
4654 pNtCreateSection = (void *)GetProcAddress(ntdll, "NtCreateSection");
4655 pNtQuerySection = (void *)GetProcAddress(ntdll, "NtQuerySection");
4656 pNtMapViewOfSection = (void *)GetProcAddress(ntdll, "NtMapViewOfSection");
4657 pNtUnmapViewOfSection = (void *)GetProcAddress(ntdll, "NtUnmapViewOfSection");
4658 pNtTerminateProcess = (void *)GetProcAddress(ntdll, "NtTerminateProcess");
4659 pNtQueryInformationProcess = (void *)GetProcAddress(ntdll, "NtQueryInformationProcess");
4660 pNtSetInformationProcess = (void *)GetProcAddress(ntdll, "NtSetInformationProcess");
4661 pLdrShutdownProcess = (void *)GetProcAddress(ntdll, "LdrShutdownProcess");
4662 pRtlDllShutdownInProgress = (void *)GetProcAddress(ntdll, "RtlDllShutdownInProgress");
4663 pNtAllocateVirtualMemory = (void *)GetProcAddress(ntdll, "NtAllocateVirtualMemory");
4664 pNtFreeVirtualMemory = (void *)GetProcAddress(ntdll, "NtFreeVirtualMemory");
4665 pLdrLockLoaderLock = (void *)GetProcAddress(ntdll, "LdrLockLoaderLock");
4666 pLdrUnlockLoaderLock = (void *)GetProcAddress(ntdll, "LdrUnlockLoaderLock");
4667 pLdrLoadDll = (void *)GetProcAddress(ntdll, "LdrLoadDll");
4668 pLdrUnloadDll = (void *)GetProcAddress(ntdll, "LdrUnloadDll");
4669 pRtlInitUnicodeString = (void *)GetProcAddress(ntdll, "RtlInitUnicodeString");
4670 pRtlAcquirePebLock = (void *)GetProcAddress(ntdll, "RtlAcquirePebLock");
4671 pRtlReleasePebLock = (void *)GetProcAddress(ntdll, "RtlReleasePebLock");
4672 pRtlImageDirectoryEntryToData = (void *)GetProcAddress(ntdll, "RtlImageDirectoryEntryToData");
4673 pRtlImageNtHeader = (void *)GetProcAddress(ntdll, "RtlImageNtHeader");
4674 pFlsAlloc = (void *)GetProcAddress(kernel32, "FlsAlloc");
4675 pFlsSetValue = (void *)GetProcAddress(kernel32, "FlsSetValue");
4676 pFlsGetValue = (void *)GetProcAddress(kernel32, "FlsGetValue");
4677 pFlsFree = (void *)GetProcAddress(kernel32, "FlsFree");
4678 pIsWow64Process = (void *)GetProcAddress(kernel32, "IsWow64Process");
4679 pWow64DisableWow64FsRedirection = (void *)GetProcAddress(kernel32, "Wow64DisableWow64FsRedirection");
4680 pWow64RevertWow64FsRedirection = (void *)GetProcAddress(kernel32, "Wow64RevertWow64FsRedirection");
4681 pResolveDelayLoadedAPI = (void *)GetProcAddress(kernel32, "ResolveDelayLoadedAPI");
4682 pLoadPackagedLibrary = (void *)GetProcAddress(kernel32, "LoadPackagedLibrary");
4684 if (pIsWow64Process) pIsWow64Process( GetCurrentProcess(), &is_wow64 );
4685 GetSystemInfo( &si );
4686 page_size = si.dwPageSize;
4687 dos_header.e_magic = IMAGE_DOS_SIGNATURE;
4688 dos_header.e_lfanew = sizeof(dos_header);
4690 mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_loader");
4691 ok(mapping != 0, "CreateFileMapping failed\n");
4692 child_failures = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 4096);
4693 if (*child_failures == -1)
4695 *child_failures = 0;
4697 else
4698 *child_failures = -1;
4700 argc = winetest_get_mainargs(&argv);
4701 if (argc > 4)
4703 test_dll_phase = atoi(argv[4]);
4704 child_process(argv[2], atol(argv[3]));
4705 return;
4708 len = GetSystemDirectoryA(system_dir, ARRAY_SIZE(system_dir));
4709 ok(len && len < ARRAY_SIZE(system_dir), "Couldn't get system directory: %lu\n", GetLastError());
4710 if (is_wow64)
4712 len = GetSystemWow64DirectoryA(syswow_dir, ARRAY_SIZE(syswow_dir));
4713 ok(len && len < ARRAY_SIZE(syswow_dir), "Couldn't get wow directory: %lu\n", GetLastError());
4716 test_filenames();
4717 test_ResolveDelayLoadedAPI();
4718 test_ImportDescriptors();
4719 test_section_access();
4720 test_import_resolution();
4721 test_export_forwarder_dep_chain();
4722 test_ExitProcess();
4723 test_InMemoryOrderModuleList();
4724 test_LoadPackagedLibrary();
4725 test_wow64_redirection();
4726 test_dll_file( "ntdll.dll" );
4727 test_dll_file( "kernel32.dll" );
4728 test_dll_file( "advapi32.dll" );
4729 test_dll_file( "user32.dll" );
4730 test_Wow64Transition();
4731 /* loader test must be last, it can corrupt the internal loader state on Windows */
4732 test_Loader();