kernel32/tests: Also test wrong architecture with matching 32/64 bitness.
[wine.git] / dlls / kernel32 / tests / loader.c
blobfe2957c82615840f81b633fea6e3c7563aa0171c
1 /*
2 * Unit test suite for the PE loader.
4 * Copyright 2006,2011 Dmitry Timoshkov
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define NONAMELESSUNION
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <assert.h>
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winternl.h"
31 #include "wine/test.h"
32 #include "delayloadhandler.h"
34 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
35 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
37 #define ALIGN_SIZE(size, alignment) (((size) + (alignment - 1)) & ~((alignment - 1)))
39 struct PROCESS_BASIC_INFORMATION_PRIVATE
41 DWORD_PTR ExitStatus;
42 PPEB PebBaseAddress;
43 DWORD_PTR AffinityMask;
44 DWORD_PTR BasePriority;
45 ULONG_PTR UniqueProcessId;
46 ULONG_PTR InheritedFromUniqueProcessId;
49 static LONG *child_failures;
50 static WORD cb_count;
51 static DWORD page_size;
53 static NTSTATUS (WINAPI *pNtCreateSection)(HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *,
54 const LARGE_INTEGER *, ULONG, ULONG, HANDLE );
55 static NTSTATUS (WINAPI *pNtQuerySection)(HANDLE, SECTION_INFORMATION_CLASS, void *, SIZE_T, SIZE_T *);
56 static NTSTATUS (WINAPI *pNtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG, SIZE_T, const LARGE_INTEGER *, SIZE_T *, ULONG, ULONG, ULONG);
57 static NTSTATUS (WINAPI *pNtUnmapViewOfSection)(HANDLE, PVOID);
58 static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
59 static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
60 static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE, DWORD);
61 static void (WINAPI *pLdrShutdownProcess)(void);
62 static BOOLEAN (WINAPI *pRtlDllShutdownInProgress)(void);
63 static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG, SIZE_T *, ULONG, ULONG);
64 static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG);
65 static NTSTATUS (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG *, ULONG_PTR *);
66 static NTSTATUS (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG_PTR);
67 static void (WINAPI *pRtlAcquirePebLock)(void);
68 static void (WINAPI *pRtlReleasePebLock)(void);
69 static PVOID (WINAPI *pResolveDelayLoadedAPI)(PVOID, PCIMAGE_DELAYLOAD_DESCRIPTOR,
70 PDELAYLOAD_FAILURE_DLL_CALLBACK, PVOID,
71 PIMAGE_THUNK_DATA ThunkAddress,ULONG);
72 static PVOID (WINAPI *pRtlImageDirectoryEntryToData)(HMODULE,BOOL,WORD,ULONG *);
73 static DWORD (WINAPI *pFlsAlloc)(PFLS_CALLBACK_FUNCTION);
74 static BOOL (WINAPI *pFlsSetValue)(DWORD, PVOID);
75 static PVOID (WINAPI *pFlsGetValue)(DWORD);
76 static BOOL (WINAPI *pFlsFree)(DWORD);
77 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
79 static PVOID RVAToAddr(DWORD_PTR rva, HMODULE module)
81 if (rva == 0)
82 return NULL;
83 return ((char*) module) + rva;
86 static IMAGE_DOS_HEADER dos_header;
88 static const IMAGE_NT_HEADERS nt_header_template =
90 IMAGE_NT_SIGNATURE, /* Signature */
92 #if defined __i386__
93 IMAGE_FILE_MACHINE_I386, /* Machine */
94 #elif defined __x86_64__
95 IMAGE_FILE_MACHINE_AMD64, /* Machine */
96 #elif defined __powerpc__
97 IMAGE_FILE_MACHINE_POWERPC, /* Machine */
98 #elif defined __arm__
99 IMAGE_FILE_MACHINE_ARMNT, /* Machine */
100 #elif defined __aarch64__
101 IMAGE_FILE_MACHINE_ARM64, /* Machine */
102 #else
103 # error You must specify the machine type
104 #endif
105 1, /* NumberOfSections */
106 0, /* TimeDateStamp */
107 0, /* PointerToSymbolTable */
108 0, /* NumberOfSymbols */
109 sizeof(IMAGE_OPTIONAL_HEADER), /* SizeOfOptionalHeader */
110 IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL /* Characteristics */
112 { IMAGE_NT_OPTIONAL_HDR_MAGIC, /* Magic */
113 1, /* MajorLinkerVersion */
114 0, /* MinorLinkerVersion */
115 0, /* SizeOfCode */
116 0, /* SizeOfInitializedData */
117 0, /* SizeOfUninitializedData */
118 0, /* AddressOfEntryPoint */
119 0x10, /* BaseOfCode, also serves as e_lfanew in the truncated MZ header */
120 #ifndef _WIN64
121 0, /* BaseOfData */
122 #endif
123 0x10000000, /* ImageBase */
124 0, /* SectionAlignment */
125 0, /* FileAlignment */
126 4, /* MajorOperatingSystemVersion */
127 0, /* MinorOperatingSystemVersion */
128 1, /* MajorImageVersion */
129 0, /* MinorImageVersion */
130 4, /* MajorSubsystemVersion */
131 0, /* MinorSubsystemVersion */
132 0, /* Win32VersionValue */
133 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000, /* SizeOfImage */
134 sizeof(dos_header) + sizeof(nt_header_template), /* SizeOfHeaders */
135 0, /* CheckSum */
136 IMAGE_SUBSYSTEM_WINDOWS_CUI, /* Subsystem */
137 0, /* DllCharacteristics */
138 0, /* SizeOfStackReserve */
139 0, /* SizeOfStackCommit */
140 0, /* SizeOfHeapReserve */
141 0, /* SizeOfHeapCommit */
142 0, /* LoaderFlags */
143 0, /* NumberOfRvaAndSizes */
144 { { 0 } } /* DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] */
148 static IMAGE_SECTION_HEADER section =
150 ".rodata", /* Name */
151 { 0 }, /* Misc */
152 0, /* VirtualAddress */
153 0, /* SizeOfRawData */
154 0, /* PointerToRawData */
155 0, /* PointerToRelocations */
156 0, /* PointerToLinenumbers */
157 0, /* NumberOfRelocations */
158 0, /* NumberOfLinenumbers */
159 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, /* Characteristics */
163 static const char filler[0x1000];
164 static const char section_data[0x10] = "section data";
166 static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size,
167 const IMAGE_NT_HEADERS *nt_header, char dll_name[MAX_PATH] )
169 char temp_path[MAX_PATH];
170 DWORD dummy, size, file_align;
171 HANDLE hfile;
172 BOOL ret;
174 GetTempPathA(MAX_PATH, temp_path);
175 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
177 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
178 ok( hfile != INVALID_HANDLE_VALUE, "failed to create %s err %u\n", dll_name, GetLastError() );
179 if (hfile == INVALID_HANDLE_VALUE) return 0;
181 SetLastError(0xdeadbeef);
182 ret = WriteFile(hfile, dos_header, dos_size, &dummy, NULL);
183 ok(ret, "WriteFile error %d\n", GetLastError());
185 SetLastError(0xdeadbeef);
186 ret = WriteFile(hfile, nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
187 ok(ret, "WriteFile error %d\n", GetLastError());
189 if (nt_header->FileHeader.SizeOfOptionalHeader)
191 SetLastError(0xdeadbeef);
192 ret = WriteFile(hfile, &nt_header->OptionalHeader,
193 min(nt_header->FileHeader.SizeOfOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER)),
194 &dummy, NULL);
195 ok(ret, "WriteFile error %d\n", GetLastError());
196 if (nt_header->FileHeader.SizeOfOptionalHeader > sizeof(IMAGE_OPTIONAL_HEADER))
198 file_align = nt_header->FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER);
199 assert(file_align < sizeof(filler));
200 SetLastError(0xdeadbeef);
201 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
202 ok(ret, "WriteFile error %d\n", GetLastError());
206 assert(nt_header->FileHeader.NumberOfSections <= 1);
207 if (nt_header->FileHeader.NumberOfSections)
209 section.SizeOfRawData = 10;
211 if (nt_header->OptionalHeader.SectionAlignment >= page_size)
213 section.PointerToRawData = dos_size;
214 section.VirtualAddress = nt_header->OptionalHeader.SectionAlignment;
215 section.Misc.VirtualSize = section.SizeOfRawData * 10;
217 else
219 section.PointerToRawData = nt_header->OptionalHeader.SizeOfHeaders;
220 section.VirtualAddress = nt_header->OptionalHeader.SizeOfHeaders;
221 section.Misc.VirtualSize = 5;
224 SetLastError(0xdeadbeef);
225 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
226 ok(ret, "WriteFile error %d\n", GetLastError());
228 /* section data */
229 SetLastError(0xdeadbeef);
230 ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
231 ok(ret, "WriteFile error %d\n", GetLastError());
233 size = GetFileSize(hfile, NULL);
234 CloseHandle(hfile);
235 return size;
238 static BOOL query_image_section( int id, const char *dll_name, const IMAGE_NT_HEADERS *nt_header )
240 SECTION_BASIC_INFORMATION info;
241 SECTION_IMAGE_INFORMATION image;
242 SIZE_T info_size = (SIZE_T)0xdeadbeef << 16;
243 NTSTATUS status;
244 HANDLE file, mapping;
245 ULONG file_size;
246 LARGE_INTEGER map_size;
247 SIZE_T max_stack, commit_stack;
248 void *entry_point;
250 /* truncated header is not handled correctly in windows <= w2k3 */
251 BOOL truncated;
253 file = CreateFileA( dll_name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE,
254 NULL, OPEN_EXISTING, 0, 0 );
255 ok( file != INVALID_HANDLE_VALUE, "%u: CreateFile error %d\n", id, GetLastError() );
256 file_size = GetFileSize( file, NULL );
258 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
259 NULL, NULL, PAGE_READONLY, SEC_IMAGE, file );
260 ok( !status, "%u: NtCreateSection failed err %x\n", id, status );
261 if (status)
263 CloseHandle( file );
264 return FALSE;
266 status = pNtQuerySection( mapping, SectionImageInformation, &image, sizeof(image), &info_size );
267 ok( !status, "%u: NtQuerySection failed err %x\n", id, status );
268 ok( info_size == sizeof(image), "%u: NtQuerySection wrong size %lu\n", id, info_size );
269 if (nt_header->OptionalHeader.Magic == (sizeof(void *) > sizeof(int) ? IMAGE_NT_OPTIONAL_HDR64_MAGIC
270 : IMAGE_NT_OPTIONAL_HDR32_MAGIC))
272 max_stack = nt_header->OptionalHeader.SizeOfStackReserve;
273 commit_stack = nt_header->OptionalHeader.SizeOfStackCommit;
274 entry_point = (char *)nt_header->OptionalHeader.ImageBase + nt_header->OptionalHeader.AddressOfEntryPoint;
275 truncated = nt_header->FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER);
277 else if (nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
279 max_stack = 0x100000;
280 commit_stack = 0x10000;
281 entry_point = (void *)0x81231234;
282 truncated = nt_header->FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER64);
284 else
286 const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt_header;
287 max_stack = nt32->OptionalHeader.SizeOfStackReserve;
288 commit_stack = nt32->OptionalHeader.SizeOfStackCommit;
289 entry_point = (char *)(ULONG_PTR)nt32->OptionalHeader.ImageBase + nt32->OptionalHeader.AddressOfEntryPoint;
290 truncated = nt_header->FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER32);
292 ok( (char *)image.TransferAddress == (char *)entry_point,
293 "%u: TransferAddress wrong %p / %p (%08x)\n", id,
294 image.TransferAddress, entry_point, nt_header->OptionalHeader.AddressOfEntryPoint );
295 ok( image.ZeroBits == 0, "%u: ZeroBits wrong %08x\n", id, image.ZeroBits );
296 ok( image.MaximumStackSize == max_stack || broken(truncated),
297 "%u: MaximumStackSize wrong %lx / %lx\n", id, image.MaximumStackSize, max_stack );
298 ok( image.CommittedStackSize == commit_stack || broken(truncated),
299 "%u: CommittedStackSize wrong %lx / %lx\n", id, image.CommittedStackSize, commit_stack );
300 if (truncated)
301 ok( !image.SubSystemType || broken(truncated),
302 "%u: SubSystemType wrong %08x / 00000000\n", id, image.SubSystemType );
303 else
304 ok( image.SubSystemType == nt_header->OptionalHeader.Subsystem,
305 "%u: SubSystemType wrong %08x / %08x\n", id,
306 image.SubSystemType, nt_header->OptionalHeader.Subsystem );
307 ok( image.SubsystemVersionLow == nt_header->OptionalHeader.MinorSubsystemVersion,
308 "%u: SubsystemVersionLow wrong %04x / %04x\n", id,
309 image.SubsystemVersionLow, nt_header->OptionalHeader.MinorSubsystemVersion );
310 ok( image.SubsystemVersionHigh == nt_header->OptionalHeader.MajorSubsystemVersion,
311 "%u: SubsystemVersionHigh wrong %04x / %04x\n", id,
312 image.SubsystemVersionHigh, nt_header->OptionalHeader.MajorSubsystemVersion );
313 ok( image.ImageCharacteristics == nt_header->FileHeader.Characteristics,
314 "%u: ImageCharacteristics wrong %04x / %04x\n", id,
315 image.ImageCharacteristics, nt_header->FileHeader.Characteristics );
316 ok( image.DllCharacteristics == nt_header->OptionalHeader.DllCharacteristics || broken(truncated),
317 "%u: DllCharacteristics wrong %04x / %04x\n", id,
318 image.DllCharacteristics, nt_header->OptionalHeader.DllCharacteristics );
319 ok( image.Machine == nt_header->FileHeader.Machine, "%u: Machine wrong %04x / %04x\n", id,
320 image.Machine, nt_header->FileHeader.Machine );
321 ok( image.LoaderFlags == nt_header->OptionalHeader.LoaderFlags,
322 "%u: LoaderFlags wrong %08x / %08x\n", id,
323 image.LoaderFlags, nt_header->OptionalHeader.LoaderFlags );
324 ok( image.ImageFileSize == file_size || broken(!image.ImageFileSize), /* winxpsp1 */
325 "%u: ImageFileSize wrong %08x / %08x\n", id, image.ImageFileSize, file_size );
326 ok( image.CheckSum == nt_header->OptionalHeader.CheckSum, "%u: CheckSum wrong %08x / %08x\n", id,
327 image.CheckSum, nt_header->OptionalHeader.CheckSum );
328 if (nt_header->OptionalHeader.SizeOfCode || nt_header->OptionalHeader.AddressOfEntryPoint)
329 todo_wine
330 ok( image.ImageContainsCode == TRUE, "%u: ImageContainsCode wrong %u\n", id,
331 image.ImageContainsCode );
332 else if ((nt_header->OptionalHeader.SectionAlignment % page_size) ||
333 (nt_header->FileHeader.NumberOfSections == 1 &&
334 (section.Characteristics & IMAGE_SCN_MEM_EXECUTE)))
335 todo_wine
336 ok( image.ImageContainsCode == TRUE || broken(!image.ImageContainsCode), /* <= win8 */
337 "%u: ImageContainsCode wrong %u\n", id, image.ImageContainsCode );
338 else
339 ok( !image.ImageContainsCode, "%u: ImageContainsCode wrong %u\n", id, image.ImageContainsCode );
340 /* FIXME: needs more work: */
341 /* image.GpValue */
342 /* image.ImageFlags */
344 map_size.QuadPart = (nt_header->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
345 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
346 ok( !status, "NtQuerySection failed err %x\n", status );
347 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %x%08x / %x%08x\n",
348 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
349 CloseHandle( mapping );
351 map_size.QuadPart = (nt_header->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
352 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
353 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
354 ok( !status, "%u: NtCreateSection failed err %x\n", id, status );
355 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
356 ok( !status, "NtQuerySection failed err %x\n", status );
357 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %x%08x / %x%08x\n",
358 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
359 CloseHandle( mapping );
361 map_size.QuadPart++;
362 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
363 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
364 ok( status == STATUS_SECTION_TOO_BIG, "%u: NtCreateSection failed err %x\n", id, status );
366 SetFilePointerEx( file, map_size, NULL, FILE_BEGIN );
367 SetEndOfFile( file );
368 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
369 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
370 ok( status == STATUS_SECTION_TOO_BIG, "%u: NtCreateSection failed err %x\n", id, status );
372 map_size.QuadPart = 1;
373 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
374 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
375 ok( !status, "%u: NtCreateSection failed err %x\n", id, status );
376 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
377 ok( !status, "NtQuerySection failed err %x\n", status );
378 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %x%08x / %x%08x\n",
379 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
380 CloseHandle( mapping );
382 CloseHandle( file );
383 return image.ImageContainsCode;
386 /* helper to test image section mapping */
387 static NTSTATUS map_image_section( const IMAGE_NT_HEADERS *nt_header, int line )
389 char dll_name[MAX_PATH];
390 LARGE_INTEGER size;
391 HANDLE file, map;
392 NTSTATUS status;
393 ULONG file_size;
394 BOOL has_code;
395 HMODULE mod;
397 file_size = create_test_dll( &dos_header, sizeof(dos_header), nt_header, dll_name );
399 file = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
400 ok(file != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError());
402 size.QuadPart = file_size;
403 status = pNtCreateSection(&map, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
404 NULL, &size, PAGE_READONLY, SEC_IMAGE, file );
405 if (!status)
407 SECTION_BASIC_INFORMATION info;
408 SIZE_T info_size = 0xdeadbeef;
409 NTSTATUS ret = pNtQuerySection( map, SectionBasicInformation, &info, sizeof(info), &info_size );
410 ok( !ret, "NtQuerySection failed err %x\n", ret );
411 ok( info_size == sizeof(info), "NtQuerySection wrong size %lu\n", info_size );
412 ok( info.Attributes == (SEC_IMAGE | SEC_FILE), "NtQuerySection wrong attr %x\n", info.Attributes );
413 ok( info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", info.BaseAddress );
414 ok( info.Size.QuadPart == file_size, "NtQuerySection wrong size %x%08x / %08x\n",
415 info.Size.u.HighPart, info.Size.u.LowPart, file_size );
416 has_code = query_image_section( line, dll_name, nt_header );
417 /* test loading dll of wrong 32/64 bitness */
418 if (nt_header->OptionalHeader.Magic == (sizeof(void *) > sizeof(int) ? IMAGE_NT_OPTIONAL_HDR32_MAGIC
419 : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
421 SetLastError( 0xdeadbeef );
422 mod = LoadLibraryExA( dll_name, 0, DONT_RESOLVE_DLL_REFERENCES );
423 if (!has_code && nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
425 ok( mod != NULL, "%u: loading failed err %u\n", line, GetLastError() );
427 else
429 ok( !mod, "%u: loading succeeded\n", line );
430 ok( GetLastError() == ERROR_BAD_EXE_FORMAT, "%u: wrong error %u\n", line, GetLastError() );
432 if (mod) FreeLibrary( mod );
435 if (map) CloseHandle( map );
436 CloseHandle( file );
437 DeleteFileA( dll_name );
438 return status;
442 static void test_Loader(void)
444 static const struct test_data
446 DWORD size_of_dos_header;
447 WORD number_of_sections, size_of_optional_header;
448 DWORD section_alignment, file_alignment;
449 DWORD size_of_image, size_of_headers;
450 DWORD errors[4]; /* 0 means LoadLibrary should succeed */
451 } td[] =
453 { sizeof(dos_header),
454 1, 0, 0, 0, 0, 0,
455 { ERROR_BAD_EXE_FORMAT }
457 { sizeof(dos_header),
458 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
459 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0xe00,
460 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
461 { ERROR_BAD_EXE_FORMAT } /* XP doesn't like too small image size */
463 { sizeof(dos_header),
464 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
465 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
466 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
467 { ERROR_SUCCESS }
469 { sizeof(dos_header),
470 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
471 0x1f00,
472 0x1000,
473 { ERROR_SUCCESS }
475 { sizeof(dos_header),
476 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x200,
477 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x200,
478 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
479 { ERROR_SUCCESS, ERROR_INVALID_ADDRESS } /* vista is more strict */
481 { sizeof(dos_header),
482 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x1000,
483 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
484 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
485 { ERROR_BAD_EXE_FORMAT } /* XP doesn't like alignments */
487 { sizeof(dos_header),
488 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
489 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
490 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
491 { ERROR_SUCCESS }
493 { sizeof(dos_header),
494 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
495 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
496 0x200,
497 { ERROR_SUCCESS }
499 /* Mandatory are all fields up to SizeOfHeaders, everything else
500 * is really optional (at least that's true for XP).
502 { sizeof(dos_header),
503 1, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
504 sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER) + 0x10,
505 sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER),
506 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT, ERROR_INVALID_ADDRESS,
507 ERROR_NOACCESS }
509 { sizeof(dos_header),
510 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
511 0xd0, /* beyond of the end of file */
512 0xc0, /* beyond of the end of file */
513 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
515 { sizeof(dos_header),
516 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
517 0x1000,
519 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
521 { sizeof(dos_header),
522 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
525 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
527 #if 0 /* not power of 2 alignments need more test cases */
528 { sizeof(dos_header),
529 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x300, 0x300,
532 { ERROR_BAD_EXE_FORMAT } /* alignment is not power of 2 */
534 #endif
535 { sizeof(dos_header),
536 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 4, 4,
539 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
541 { sizeof(dos_header),
542 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 1, 1,
545 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
547 { sizeof(dos_header),
548 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
551 { ERROR_BAD_EXE_FORMAT } /* image size == 0 -> failure */
553 /* the following data mimics the PE image which upack creates */
554 { 0x10,
555 1, 0x148, 0x1000, 0x200,
556 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
557 0x200,
558 { ERROR_SUCCESS }
560 /* Minimal PE image that XP is able to load: 92 bytes */
561 { 0x04,
562 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum),
563 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
566 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
568 /* Minimal PE image that Windows7 is able to load: 268 bytes */
569 { 0x04,
570 0, 0xf0, /* optional header size just forces 0xf0 bytes to be written,
571 0 or another number don't change the behaviour, what really
572 matters is file size regardless of values in the headers */
573 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
574 0x40, /* minimal image size that Windows7 accepts */
576 { ERROR_SUCCESS }
579 int i;
580 DWORD file_size;
581 HANDLE h;
582 HMODULE hlib, hlib_as_data_file;
583 char dll_name[MAX_PATH];
584 SIZE_T size;
585 BOOL ret;
586 NTSTATUS status;
587 WORD orig_machine = nt_header_template.FileHeader.Machine;
588 IMAGE_NT_HEADERS nt_header;
590 /* prevent displaying of the "Unable to load this DLL" message box */
591 SetErrorMode(SEM_FAILCRITICALERRORS);
593 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
595 nt_header = nt_header_template;
596 nt_header.FileHeader.NumberOfSections = td[i].number_of_sections;
597 nt_header.FileHeader.SizeOfOptionalHeader = td[i].size_of_optional_header;
599 nt_header.OptionalHeader.SectionAlignment = td[i].section_alignment;
600 nt_header.OptionalHeader.FileAlignment = td[i].file_alignment;
601 nt_header.OptionalHeader.SizeOfImage = td[i].size_of_image;
602 nt_header.OptionalHeader.SizeOfHeaders = td[i].size_of_headers;
604 file_size = create_test_dll( &dos_header, td[i].size_of_dos_header, &nt_header, dll_name );
606 SetLastError(0xdeadbeef);
607 hlib = LoadLibraryA(dll_name);
608 if (hlib)
610 MEMORY_BASIC_INFORMATION info;
611 void *ptr;
613 ok( td[i].errors[0] == ERROR_SUCCESS, "%d: should have failed\n", i );
615 SetLastError(0xdeadbeef);
616 size = VirtualQuery(hlib, &info, sizeof(info));
617 ok(size == sizeof(info),
618 "%d: VirtualQuery error %d\n", i, GetLastError());
619 ok(info.BaseAddress == hlib, "%d: %p != %p\n", i, info.BaseAddress, hlib);
620 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
621 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
622 ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %lx != expected %x\n",
623 i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
624 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
625 if (nt_header.OptionalHeader.SectionAlignment < page_size)
626 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
627 else
628 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
629 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
631 SetLastError(0xdeadbeef);
632 ptr = VirtualAlloc(hlib, page_size, MEM_COMMIT, info.Protect);
633 ok(!ptr, "%d: VirtualAlloc should fail\n", i);
634 ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError());
636 SetLastError(0xdeadbeef);
637 size = VirtualQuery((char *)hlib + info.RegionSize, &info, sizeof(info));
638 ok(size == sizeof(info),
639 "%d: VirtualQuery error %d\n", i, GetLastError());
640 if (nt_header.OptionalHeader.SectionAlignment == page_size ||
641 nt_header.OptionalHeader.SectionAlignment == nt_header.OptionalHeader.FileAlignment)
643 ok(info.BaseAddress == (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %p != expected %p\n",
644 i, info.BaseAddress, (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
645 ok(info.AllocationBase == 0, "%d: %p != 0\n", i, info.AllocationBase);
646 ok(info.AllocationProtect == 0, "%d: %x != 0\n", i, info.AllocationProtect);
647 /*ok(info.RegionSize == not_practical_value, "%d: %lx != not_practical_value\n", i, info.RegionSize);*/
648 ok(info.State == MEM_FREE, "%d: %x != MEM_FREE\n", i, info.State);
649 ok(info.Type == 0, "%d: %x != 0\n", i, info.Type);
650 ok(info.Protect == PAGE_NOACCESS, "%d: %x != PAGE_NOACCESS\n", i, info.Protect);
652 else
654 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
655 ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib);
656 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
657 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
658 ok(info.RegionSize == ALIGN_SIZE(file_size, page_size), "%d: got %lx != expected %x\n",
659 i, info.RegionSize, ALIGN_SIZE(file_size, page_size));
660 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
661 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
662 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
665 /* header: check the zeroing of alignment */
666 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
668 const char *start;
670 start = (const char *)hlib + nt_header.OptionalHeader.SizeOfHeaders;
671 size = ALIGN_SIZE((ULONG_PTR)start, page_size) - (ULONG_PTR)start;
672 ok(!memcmp(start, filler, size), "%d: header alignment is not cleared\n", i);
675 if (nt_header.FileHeader.NumberOfSections)
677 SetLastError(0xdeadbeef);
678 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
679 ok(size == sizeof(info),
680 "%d: VirtualQuery error %d\n", i, GetLastError());
681 if (nt_header.OptionalHeader.SectionAlignment < page_size)
683 ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib);
684 ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %lx != expected %x\n",
685 i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
686 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
688 else
690 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
691 ok(info.RegionSize == ALIGN_SIZE(section.Misc.VirtualSize, page_size), "%d: got %lx != expected %x\n",
692 i, info.RegionSize, ALIGN_SIZE(section.Misc.VirtualSize, page_size));
693 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
695 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
696 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
697 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
698 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
700 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
701 ok(!memcmp((const char *)hlib + section.VirtualAddress + section.PointerToRawData, &nt_header, section.SizeOfRawData), "wrong section data\n");
702 else
703 ok(!memcmp((const char *)hlib + section.PointerToRawData, section_data, section.SizeOfRawData), "wrong section data\n");
705 /* check the zeroing of alignment */
706 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
708 const char *start;
710 start = (const char *)hlib + section.VirtualAddress + section.PointerToRawData + section.SizeOfRawData;
711 size = ALIGN_SIZE((ULONG_PTR)start, page_size) - (ULONG_PTR)start;
712 ok(memcmp(start, filler, size), "%d: alignment should not be cleared\n", i);
715 SetLastError(0xdeadbeef);
716 ptr = VirtualAlloc((char *)hlib + section.VirtualAddress, page_size, MEM_COMMIT, info.Protect);
717 ok(!ptr, "%d: VirtualAlloc should fail\n", i);
718 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_INVALID_ADDRESS,
719 "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError());
722 SetLastError(0xdeadbeef);
723 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
724 ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
725 ok(hlib_as_data_file == hlib, "hlib_as_file and hlib are different\n");
727 SetLastError(0xdeadbeef);
728 ret = FreeLibrary(hlib);
729 ok(ret, "FreeLibrary error %d\n", GetLastError());
731 SetLastError(0xdeadbeef);
732 hlib = GetModuleHandleA(dll_name);
733 ok(hlib != 0, "GetModuleHandle error %u\n", GetLastError());
735 SetLastError(0xdeadbeef);
736 ret = FreeLibrary(hlib_as_data_file);
737 ok(ret, "FreeLibrary error %d\n", GetLastError());
739 hlib = GetModuleHandleA(dll_name);
740 ok(!hlib, "GetModuleHandle should fail\n");
742 SetLastError(0xdeadbeef);
743 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
744 ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
745 ok((ULONG_PTR)hlib_as_data_file & 1, "hlib_as_data_file is even\n");
747 hlib = GetModuleHandleA(dll_name);
748 ok(!hlib, "GetModuleHandle should fail\n");
750 SetLastError(0xdeadbeef);
751 h = CreateFileA( dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
752 ok( h != INVALID_HANDLE_VALUE, "open failed err %u\n", GetLastError() );
753 CloseHandle( h );
755 SetLastError(0xdeadbeef);
756 ret = FreeLibrary(hlib_as_data_file);
757 ok(ret, "FreeLibrary error %d\n", GetLastError());
759 SetLastError(0xdeadbeef);
760 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE);
761 if (!((ULONG_PTR)hlib_as_data_file & 1) || /* winxp */
762 (!hlib_as_data_file && GetLastError() == ERROR_INVALID_PARAMETER)) /* w2k3 */
764 win_skip( "LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE not supported\n" );
765 FreeLibrary(hlib_as_data_file);
767 else
769 ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
771 SetLastError(0xdeadbeef);
772 h = CreateFileA( dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
773 todo_wine ok( h == INVALID_HANDLE_VALUE, "open succeeded\n" );
774 todo_wine ok( GetLastError() == ERROR_SHARING_VIOLATION, "wrong error %u\n", GetLastError() );
775 CloseHandle( h );
777 SetLastError(0xdeadbeef);
778 ret = FreeLibrary(hlib_as_data_file);
779 ok(ret, "FreeLibrary error %d\n", GetLastError());
782 query_image_section( i, dll_name, &nt_header );
784 else
786 BOOL error_match;
787 int error_index;
789 error_match = FALSE;
790 for (error_index = 0;
791 ! error_match && error_index < sizeof(td[i].errors) / sizeof(DWORD);
792 error_index++)
794 error_match = td[i].errors[error_index] == GetLastError();
796 ok(error_match, "%d: unexpected error %d\n", i, GetLastError());
799 SetLastError(0xdeadbeef);
800 ret = DeleteFileA(dll_name);
801 ok(ret, "DeleteFile error %d\n", GetLastError());
804 nt_header = nt_header_template;
805 nt_header.FileHeader.NumberOfSections = 1;
806 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
808 nt_header.OptionalHeader.SectionAlignment = page_size;
809 nt_header.OptionalHeader.AddressOfEntryPoint = 0x1234;
810 nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
811 nt_header.OptionalHeader.FileAlignment = page_size;
812 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
813 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
815 status = map_image_section( &nt_header, __LINE__ );
816 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
818 dos_header.e_magic = 0;
819 status = map_image_section( &nt_header, __LINE__ );
820 ok( status == STATUS_INVALID_IMAGE_NOT_MZ, "NtCreateSection error %08x\n", status );
822 dos_header.e_magic = IMAGE_DOS_SIGNATURE;
823 nt_header.Signature = IMAGE_OS2_SIGNATURE;
824 status = map_image_section( &nt_header, __LINE__ );
825 ok( status == STATUS_INVALID_IMAGE_NE_FORMAT, "NtCreateSection error %08x\n", status );
827 nt_header.Signature = 0xdeadbeef;
828 status = map_image_section( &nt_header, __LINE__ );
829 ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection error %08x\n", status );
831 nt_header.Signature = IMAGE_NT_SIGNATURE;
832 nt_header.OptionalHeader.Magic = 0xdead;
833 status = map_image_section( &nt_header, __LINE__ );
834 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08x\n", status );
836 nt_header.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC;
837 nt_header.FileHeader.Machine = 0xdead;
838 status = map_image_section( &nt_header, __LINE__ );
839 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
840 "NtCreateSection error %08x\n", status );
842 nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_UNKNOWN;
843 status = map_image_section( &nt_header, __LINE__ );
844 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
845 "NtCreateSection error %08x\n", status );
847 switch (orig_machine)
849 case IMAGE_FILE_MACHINE_I386: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_ARMNT; break;
850 case IMAGE_FILE_MACHINE_AMD64: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_ARM64; break;
851 case IMAGE_FILE_MACHINE_ARMNT: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_I386; break;
852 case IMAGE_FILE_MACHINE_ARM64: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64; break;
854 status = map_image_section( &nt_header, __LINE__ );
855 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
856 "NtCreateSection error %08x\n", status );
858 switch (orig_machine)
860 case IMAGE_FILE_MACHINE_I386: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64; break;
861 case IMAGE_FILE_MACHINE_AMD64: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_I386; break;
862 case IMAGE_FILE_MACHINE_ARMNT: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_ARM64; break;
863 case IMAGE_FILE_MACHINE_ARM64: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_ARMNT; break;
865 status = map_image_section( &nt_header, __LINE__ );
866 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
867 "NtCreateSection error %08x\n", status );
869 if (nt_header.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
871 IMAGE_NT_HEADERS64 nt64;
872 BOOL is_wow64 = FALSE;
874 if (pIsWow64Process) pIsWow64Process( GetCurrentProcess(), &is_wow64 );
875 memset( &nt64, 0, sizeof(nt64) );
876 nt64.Signature = IMAGE_NT_SIGNATURE;
877 nt64.FileHeader.Machine = orig_machine;
878 nt64.FileHeader.NumberOfSections = 1;
879 nt64.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
880 nt64.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL;
881 nt64.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
882 nt64.OptionalHeader.MajorLinkerVersion = 1;
883 nt64.OptionalHeader.SizeOfCode = 0x1000;
884 nt64.OptionalHeader.AddressOfEntryPoint = 0x1000;
885 nt64.OptionalHeader.ImageBase = 0x10000000;
886 nt64.OptionalHeader.SectionAlignment = 0x1000;
887 nt64.OptionalHeader.FileAlignment = 0x1000;
888 nt64.OptionalHeader.MajorOperatingSystemVersion = 4;
889 nt64.OptionalHeader.MajorImageVersion = 1;
890 nt64.OptionalHeader.MajorSubsystemVersion = 4;
891 nt64.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt64) + sizeof(IMAGE_SECTION_HEADER);
892 nt64.OptionalHeader.SizeOfImage = nt64.OptionalHeader.SizeOfHeaders + 0x1000;
893 nt64.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
894 nt64.OptionalHeader.SizeOfStackReserve = 0x321000;
895 nt64.OptionalHeader.SizeOfStackCommit = 0x123000;
896 section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
898 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, __LINE__ );
899 todo_wine_if(!is_wow64)
900 ok( status == (is_wow64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_INVALID_IMAGE_WIN_64),
901 "NtCreateSection error %08x\n", status );
903 switch (orig_machine)
905 case IMAGE_FILE_MACHINE_I386: nt64.FileHeader.Machine = IMAGE_FILE_MACHINE_ARM64; break;
906 case IMAGE_FILE_MACHINE_ARMNT: nt64.FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64; break;
908 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, __LINE__ );
909 todo_wine_if(!is_wow64)
910 ok( status == (is_wow64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_INVALID_IMAGE_WIN_64),
911 "NtCreateSection error %08x\n", status );
913 nt64.FileHeader.Machine = nt_header.FileHeader.Machine;
914 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, __LINE__ );
915 todo_wine
916 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
917 "NtCreateSection error %08x\n", status );
919 nt64.OptionalHeader.SizeOfCode = 0;
920 nt64.OptionalHeader.AddressOfEntryPoint = 0x1000;
921 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
922 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, __LINE__ );
923 todo_wine
924 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
925 "NtCreateSection error %08x\n", status );
927 nt64.OptionalHeader.SizeOfCode = 0;
928 nt64.OptionalHeader.AddressOfEntryPoint = 0;
929 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE;
930 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, __LINE__ );
931 todo_wine
932 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
933 "NtCreateSection error %08x\n", status );
935 nt64.OptionalHeader.SizeOfCode = 0x1000;
936 nt64.OptionalHeader.AddressOfEntryPoint = 0;
937 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
938 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, __LINE__ );
939 todo_wine
940 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
941 "NtCreateSection error %08x\n", status );
943 nt64.OptionalHeader.SizeOfCode = 0;
944 nt64.OptionalHeader.AddressOfEntryPoint = 0;
945 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
946 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, __LINE__ );
947 todo_wine
948 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
949 "NtCreateSection error %08x\n", status );
951 else
953 IMAGE_NT_HEADERS32 nt32;
955 memset( &nt32, 0, sizeof(nt32) );
956 nt32.Signature = IMAGE_NT_SIGNATURE;
957 nt32.FileHeader.Machine = orig_machine;
958 nt32.FileHeader.NumberOfSections = 1;
959 nt32.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32);
960 nt32.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL;
961 nt32.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
962 nt32.OptionalHeader.MajorLinkerVersion = 1;
963 nt32.OptionalHeader.SizeOfCode = 0x1000;
964 nt32.OptionalHeader.AddressOfEntryPoint = 0x1000;
965 nt32.OptionalHeader.ImageBase = 0x10000000;
966 nt32.OptionalHeader.SectionAlignment = 0x1000;
967 nt32.OptionalHeader.FileAlignment = 0x1000;
968 nt32.OptionalHeader.MajorOperatingSystemVersion = 4;
969 nt32.OptionalHeader.MajorImageVersion = 1;
970 nt32.OptionalHeader.MajorSubsystemVersion = 4;
971 nt32.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt32) + sizeof(IMAGE_SECTION_HEADER);
972 nt32.OptionalHeader.SizeOfImage = nt32.OptionalHeader.SizeOfHeaders + 0x1000;
973 nt32.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
974 nt32.OptionalHeader.SizeOfStackReserve = 0x321000;
975 nt32.OptionalHeader.SizeOfStackCommit = 0x123000;
976 section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
978 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, __LINE__ );
979 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08x\n", status );
981 switch (orig_machine)
983 case IMAGE_FILE_MACHINE_AMD64: nt32.FileHeader.Machine = IMAGE_FILE_MACHINE_ARMNT; break;
984 case IMAGE_FILE_MACHINE_ARM64: nt32.FileHeader.Machine = IMAGE_FILE_MACHINE_I386; break;
986 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, __LINE__ );
987 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(!status) /* win8 */,
988 "NtCreateSection error %08x\n", status );
990 nt32.FileHeader.Machine = nt_header.FileHeader.Machine;
991 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, __LINE__ );
992 todo_wine
993 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
995 nt32.OptionalHeader.SizeOfCode = 0;
996 nt32.OptionalHeader.AddressOfEntryPoint = 0x1000;
997 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
998 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, __LINE__ );
999 todo_wine
1000 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1002 nt32.OptionalHeader.SizeOfCode = 0;
1003 nt32.OptionalHeader.AddressOfEntryPoint = 0;
1004 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE;
1005 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, __LINE__ );
1006 todo_wine
1007 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1009 nt32.OptionalHeader.SizeOfCode = 0x1000;
1010 nt32.OptionalHeader.AddressOfEntryPoint = 0;
1011 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1012 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, __LINE__ );
1013 todo_wine
1014 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1016 nt32.OptionalHeader.SizeOfCode = 0;
1017 nt32.OptionalHeader.AddressOfEntryPoint = 0;
1018 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1019 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, __LINE__ );
1020 todo_wine
1021 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
1024 nt_header.FileHeader.Machine = orig_machine; /* restore it for the next tests */
1025 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
1028 /* Verify linking style of import descriptors */
1029 static void test_ImportDescriptors(void)
1031 HMODULE kernel32_module = NULL;
1032 PIMAGE_DOS_HEADER d_header;
1033 PIMAGE_NT_HEADERS nt_headers;
1034 DWORD import_dir_size;
1035 DWORD_PTR dir_offset;
1036 PIMAGE_IMPORT_DESCRIPTOR import_chunk;
1038 /* Load kernel32 module */
1039 kernel32_module = GetModuleHandleA("kernel32.dll");
1040 assert( kernel32_module != NULL );
1042 /* Get PE header info from module image */
1043 d_header = (PIMAGE_DOS_HEADER) kernel32_module;
1044 nt_headers = (PIMAGE_NT_HEADERS) (((char*) d_header) +
1045 d_header->e_lfanew);
1047 /* Get size of import entry directory */
1048 import_dir_size = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
1049 if (!import_dir_size)
1051 skip("Unable to continue testing due to missing import directory.\n");
1052 return;
1055 /* Get address of first import chunk */
1056 dir_offset = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
1057 import_chunk = RVAToAddr(dir_offset, kernel32_module);
1058 ok(import_chunk != 0, "Invalid import_chunk: %p\n", import_chunk);
1059 if (!import_chunk) return;
1061 /* Iterate through import descriptors and verify set name,
1062 * OriginalFirstThunk, and FirstThunk. Core Windows DLLs, such as
1063 * kernel32.dll, don't use Borland-style linking, where the table of
1064 * imported names is stored directly in FirstThunk and overwritten
1065 * by the relocation, instead of being stored in OriginalFirstThunk.
1066 * */
1067 for (; import_chunk->FirstThunk; import_chunk++)
1069 LPCSTR module_name = RVAToAddr(import_chunk->Name, kernel32_module);
1070 PIMAGE_THUNK_DATA name_table = RVAToAddr(
1071 U(*import_chunk).OriginalFirstThunk, kernel32_module);
1072 PIMAGE_THUNK_DATA iat = RVAToAddr(
1073 import_chunk->FirstThunk, kernel32_module);
1074 ok(module_name != NULL, "Imported module name should not be NULL\n");
1075 ok(name_table != NULL,
1076 "Name table for imported module %s should not be NULL\n",
1077 module_name);
1078 ok(iat != NULL, "IAT for imported module %s should not be NULL\n",
1079 module_name);
1083 static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL is_dll)
1085 HANDLE hfile, hmap;
1086 NTSTATUS status;
1087 LARGE_INTEGER offset;
1088 SIZE_T size;
1089 void *addr1, *addr2;
1090 MEMORY_BASIC_INFORMATION info;
1092 if (!pNtMapViewOfSection) return;
1094 SetLastError(0xdeadbeef);
1095 hfile = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
1096 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError());
1098 SetLastError(0xdeadbeef);
1099 hmap = CreateFileMappingW(hfile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, 0);
1100 ok(hmap != 0, "CreateFileMapping error %d\n", GetLastError());
1102 offset.u.LowPart = 0;
1103 offset.u.HighPart = 0;
1105 addr1 = NULL;
1106 size = 0;
1107 status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr1, 0, 0, &offset,
1108 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1109 ok(status == STATUS_SUCCESS, "NtMapViewOfSection error %x\n", status);
1110 ok(addr1 != 0, "mapped address should be valid\n");
1112 SetLastError(0xdeadbeef);
1113 size = VirtualQuery((char *)addr1 + section.VirtualAddress, &info, sizeof(info));
1114 ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
1115 ok(info.BaseAddress == (char *)addr1 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr1 + section.VirtualAddress);
1116 ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size);
1117 ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
1118 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1119 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1120 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
1121 ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
1123 addr2 = NULL;
1124 size = 0;
1125 status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr2, 0, 0, &offset,
1126 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1127 ok(status == STATUS_IMAGE_NOT_AT_BASE, "expected STATUS_IMAGE_NOT_AT_BASE, got %x\n", status);
1128 ok(addr2 != 0, "mapped address should be valid\n");
1129 ok(addr2 != addr1, "mapped addresses should be different\n");
1131 SetLastError(0xdeadbeef);
1132 size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info));
1133 ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
1134 ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress);
1135 ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size);
1136 ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
1137 ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2);
1138 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1139 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
1140 ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
1142 status = pNtUnmapViewOfSection(GetCurrentProcess(), addr2);
1143 ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status);
1145 addr2 = MapViewOfFile(hmap, 0, 0, 0, 0);
1146 ok(addr2 != 0, "mapped address should be valid\n");
1147 ok(addr2 != addr1, "mapped addresses should be different\n");
1149 SetLastError(0xdeadbeef);
1150 size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info));
1151 ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
1152 ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress);
1153 ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size);
1154 ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
1155 ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2);
1156 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1157 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
1158 ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
1160 UnmapViewOfFile(addr2);
1162 SetLastError(0xdeadbeef);
1163 addr2 = LoadLibraryA(dll_name);
1164 if (is_dll)
1166 ok(!addr2, "LoadLibrary should fail, is_dll %d\n", is_dll);
1167 ok(GetLastError() == ERROR_INVALID_ADDRESS, "expected ERROR_INVALID_ADDRESS, got %d\n", GetLastError());
1169 else
1171 BOOL ret;
1172 ok(addr2 != 0, "LoadLibrary error %d, is_dll %d\n", GetLastError(), is_dll);
1173 ok(addr2 != addr1, "mapped addresses should be different\n");
1175 SetLastError(0xdeadbeef);
1176 ret = FreeLibrary(addr2);
1177 ok(ret, "FreeLibrary error %d\n", GetLastError());
1180 status = pNtUnmapViewOfSection(GetCurrentProcess(), addr1);
1181 ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status);
1183 CloseHandle(hmap);
1184 CloseHandle(hfile);
1187 static BOOL is_mem_writable(DWORD prot)
1189 switch (prot & 0xff)
1191 case PAGE_READWRITE:
1192 case PAGE_WRITECOPY:
1193 case PAGE_EXECUTE_READWRITE:
1194 case PAGE_EXECUTE_WRITECOPY:
1195 return TRUE;
1197 default:
1198 return FALSE;
1202 static void test_VirtualProtect(void *base, void *section)
1204 static const struct test_data
1206 DWORD prot_set, prot_get;
1207 } td[] =
1209 { 0, 0 }, /* 0x00 */
1210 { PAGE_NOACCESS, PAGE_NOACCESS }, /* 0x01 */
1211 { PAGE_READONLY, PAGE_READONLY }, /* 0x02 */
1212 { PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x03 */
1213 { PAGE_READWRITE, PAGE_WRITECOPY }, /* 0x04 */
1214 { PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x05 */
1215 { PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x06 */
1216 { PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x07 */
1217 { PAGE_WRITECOPY, PAGE_WRITECOPY }, /* 0x08 */
1218 { PAGE_WRITECOPY | PAGE_NOACCESS, 0 }, /* 0x09 */
1219 { PAGE_WRITECOPY | PAGE_READONLY, 0 }, /* 0x0a */
1220 { PAGE_WRITECOPY | PAGE_NOACCESS | PAGE_READONLY, 0 }, /* 0x0b */
1221 { PAGE_WRITECOPY | PAGE_READWRITE, 0 }, /* 0x0c */
1222 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x0d */
1223 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x0e */
1224 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x0f */
1226 { PAGE_EXECUTE, PAGE_EXECUTE }, /* 0x10 */
1227 { PAGE_EXECUTE_READ, PAGE_EXECUTE_READ }, /* 0x20 */
1228 { PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x30 */
1229 { PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY }, /* 0x40 */
1230 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0x50 */
1231 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0x60 */
1232 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x70 */
1233 { PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_WRITECOPY }, /* 0x80 */
1234 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE, 0 }, /* 0x90 */
1235 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ, 0 }, /* 0xa0 */
1236 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0xb0 */
1237 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE, 0 }, /* 0xc0 */
1238 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0xd0 */
1239 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0xe0 */
1240 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 } /* 0xf0 */
1242 DWORD ret, orig_prot, old_prot, rw_prot, exec_prot, i, j;
1243 MEMORY_BASIC_INFORMATION info;
1245 SetLastError(0xdeadbeef);
1246 ret = VirtualProtect(section, page_size, PAGE_NOACCESS, &old_prot);
1247 ok(ret, "VirtualProtect error %d\n", GetLastError());
1249 orig_prot = old_prot;
1251 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
1253 SetLastError(0xdeadbeef);
1254 ret = VirtualQuery(section, &info, sizeof(info));
1255 ok(ret, "VirtualQuery failed %d\n", GetLastError());
1256 ok(info.BaseAddress == section, "%d: got %p != expected %p\n", i, info.BaseAddress, section);
1257 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1258 ok(info.Protect == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, info.Protect);
1259 ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
1260 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1261 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1262 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1264 old_prot = 0xdeadbeef;
1265 SetLastError(0xdeadbeef);
1266 ret = VirtualProtect(section, page_size, td[i].prot_set, &old_prot);
1267 if (td[i].prot_get)
1269 ok(ret, "%d: VirtualProtect error %d, requested prot %#x\n", i, GetLastError(), td[i].prot_set);
1270 ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
1272 SetLastError(0xdeadbeef);
1273 ret = VirtualQuery(section, &info, sizeof(info));
1274 ok(ret, "VirtualQuery failed %d\n", GetLastError());
1275 ok(info.BaseAddress == section, "%d: got %p != expected %p\n", i, info.BaseAddress, section);
1276 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1277 ok(info.Protect == td[i].prot_get, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_get);
1278 ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
1279 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1280 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1281 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1283 else
1285 ok(!ret, "%d: VirtualProtect should fail\n", i);
1286 ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
1289 old_prot = 0xdeadbeef;
1290 SetLastError(0xdeadbeef);
1291 ret = VirtualProtect(section, page_size, PAGE_NOACCESS, &old_prot);
1292 ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
1293 if (td[i].prot_get)
1294 ok(old_prot == td[i].prot_get, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_get);
1295 else
1296 ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
1299 exec_prot = 0;
1301 for (i = 0; i <= 4; i++)
1303 rw_prot = 0;
1305 for (j = 0; j <= 4; j++)
1307 DWORD prot = exec_prot | rw_prot;
1309 SetLastError(0xdeadbeef);
1310 ret = VirtualProtect(section, page_size, prot, &old_prot);
1311 if ((rw_prot && exec_prot) || (!rw_prot && !exec_prot))
1313 ok(!ret, "VirtualProtect(%02x) should fail\n", prot);
1314 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1316 else
1317 ok(ret, "VirtualProtect(%02x) error %d\n", prot, GetLastError());
1319 rw_prot = 1 << j;
1322 exec_prot = 1 << (i + 4);
1325 SetLastError(0xdeadbeef);
1326 ret = VirtualProtect(section, page_size, orig_prot, &old_prot);
1327 ok(ret, "VirtualProtect error %d\n", GetLastError());
1330 static void test_section_access(void)
1332 static const struct test_data
1334 DWORD scn_file_access, scn_page_access, scn_page_access_after_write;
1335 } td[] =
1337 { 0, PAGE_NOACCESS, 0 },
1338 { IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1339 { IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1340 { IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1341 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1342 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ },
1343 { IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1344 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1346 { IMAGE_SCN_CNT_INITIALIZED_DATA, PAGE_NOACCESS, 0 },
1347 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1348 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1349 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1350 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1351 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
1352 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1353 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1355 { IMAGE_SCN_CNT_UNINITIALIZED_DATA, PAGE_NOACCESS, 0 },
1356 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1357 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1358 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1359 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1360 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
1361 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1362 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE }
1364 char buf[256];
1365 int i;
1366 DWORD dummy, file_align;
1367 HANDLE hfile;
1368 HMODULE hlib;
1369 char temp_path[MAX_PATH];
1370 char dll_name[MAX_PATH];
1371 SIZE_T size;
1372 MEMORY_BASIC_INFORMATION info;
1373 STARTUPINFOA sti;
1374 PROCESS_INFORMATION pi;
1375 DWORD ret;
1377 /* prevent displaying of the "Unable to load this DLL" message box */
1378 SetErrorMode(SEM_FAILCRITICALERRORS);
1380 GetTempPathA(MAX_PATH, temp_path);
1382 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
1384 IMAGE_NT_HEADERS nt_header;
1386 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
1388 /*trace("creating %s\n", dll_name);*/
1389 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
1390 if (hfile == INVALID_HANDLE_VALUE)
1392 ok(0, "could not create %s\n", dll_name);
1393 return;
1396 SetLastError(0xdeadbeef);
1397 ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
1398 ok(ret, "WriteFile error %d\n", GetLastError());
1400 nt_header = nt_header_template;
1401 nt_header.FileHeader.NumberOfSections = 1;
1402 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1403 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED;
1405 nt_header.OptionalHeader.SectionAlignment = page_size;
1406 nt_header.OptionalHeader.FileAlignment = 0x200;
1407 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
1408 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
1409 SetLastError(0xdeadbeef);
1410 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
1411 ok(ret, "WriteFile error %d\n", GetLastError());
1412 SetLastError(0xdeadbeef);
1413 ret = WriteFile(hfile, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
1414 ok(ret, "WriteFile error %d\n", GetLastError());
1416 section.SizeOfRawData = sizeof(section_data);
1417 section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
1418 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
1419 section.Misc.VirtualSize = section.SizeOfRawData;
1420 section.Characteristics = td[i].scn_file_access;
1421 SetLastError(0xdeadbeef);
1422 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
1423 ok(ret, "WriteFile error %d\n", GetLastError());
1425 file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
1426 assert(file_align < sizeof(filler));
1427 SetLastError(0xdeadbeef);
1428 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
1429 ok(ret, "WriteFile error %d\n", GetLastError());
1431 /* section data */
1432 SetLastError(0xdeadbeef);
1433 ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
1434 ok(ret, "WriteFile error %d\n", GetLastError());
1436 CloseHandle(hfile);
1438 SetLastError(0xdeadbeef);
1439 hlib = LoadLibraryA(dll_name);
1440 ok(hlib != 0, "LoadLibrary error %d\n", GetLastError());
1442 SetLastError(0xdeadbeef);
1443 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
1444 ok(size == sizeof(info),
1445 "%d: VirtualQuery error %d\n", i, GetLastError());
1446 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
1447 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1448 ok(info.Protect == td[i].scn_page_access, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access);
1449 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
1450 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1451 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1452 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1453 if (info.Protect != PAGE_NOACCESS)
1454 ok(!memcmp((const char *)info.BaseAddress, section_data, section.SizeOfRawData), "wrong section data\n");
1456 test_VirtualProtect(hlib, (char *)hlib + section.VirtualAddress);
1458 /* Windows changes the WRITECOPY to WRITE protection on an image section write (for a changed page only) */
1459 if (is_mem_writable(info.Protect))
1461 char *p = info.BaseAddress;
1462 *p = 0xfe;
1463 SetLastError(0xdeadbeef);
1464 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
1465 ok(size == sizeof(info), "%d: VirtualQuery error %d\n", i, GetLastError());
1466 /* FIXME: remove the condition below once Wine is fixed */
1467 todo_wine_if (info.Protect == PAGE_WRITECOPY || info.Protect == PAGE_EXECUTE_WRITECOPY)
1468 ok(info.Protect == td[i].scn_page_access_after_write, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access_after_write);
1471 SetLastError(0xdeadbeef);
1472 ret = FreeLibrary(hlib);
1473 ok(ret, "FreeLibrary error %d\n", GetLastError());
1475 test_image_mapping(dll_name, td[i].scn_page_access, TRUE);
1477 /* reset IMAGE_FILE_DLL otherwise CreateProcess fails */
1478 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_RELOCS_STRIPPED;
1479 SetLastError(0xdeadbeef);
1480 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1481 /* LoadLibrary called on an already memory-mapped file in
1482 * test_image_mapping() above leads to a file handle leak
1483 * under nt4, and inability to overwrite and delete the file
1484 * due to sharing violation error. Ignore it and skip the test,
1485 * but leave a not deletable temporary file.
1487 ok(hfile != INVALID_HANDLE_VALUE || broken(hfile == INVALID_HANDLE_VALUE) /* nt4 */,
1488 "CreateFile error %d\n", GetLastError());
1489 if (hfile == INVALID_HANDLE_VALUE) goto nt4_is_broken;
1490 SetFilePointer(hfile, sizeof(dos_header), NULL, FILE_BEGIN);
1491 SetLastError(0xdeadbeef);
1492 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
1493 ok(ret, "WriteFile error %d\n", GetLastError());
1494 CloseHandle(hfile);
1496 memset(&sti, 0, sizeof(sti));
1497 sti.cb = sizeof(sti);
1498 SetLastError(0xdeadbeef);
1499 ret = CreateProcessA(dll_name, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &sti, &pi);
1500 ok(ret, "CreateProcess() error %d\n", GetLastError());
1502 SetLastError(0xdeadbeef);
1503 size = VirtualQueryEx(pi.hProcess, (char *)hlib + section.VirtualAddress, &info, sizeof(info));
1504 ok(size == sizeof(info),
1505 "%d: VirtualQuery error %d\n", i, GetLastError());
1506 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
1507 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1508 ok(info.Protect == td[i].scn_page_access, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access);
1509 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
1510 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1511 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1512 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1513 if (info.Protect != PAGE_NOACCESS)
1515 SetLastError(0xdeadbeef);
1516 ret = ReadProcessMemory(pi.hProcess, info.BaseAddress, buf, section.SizeOfRawData, NULL);
1517 ok(ret, "ReadProcessMemory() error %d\n", GetLastError());
1518 ok(!memcmp(buf, section_data, section.SizeOfRawData), "wrong section data\n");
1521 SetLastError(0xdeadbeef);
1522 ret = TerminateProcess(pi.hProcess, 0);
1523 ok(ret, "TerminateProcess() error %d\n", GetLastError());
1524 ret = WaitForSingleObject(pi.hProcess, 3000);
1525 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
1527 CloseHandle(pi.hThread);
1528 CloseHandle(pi.hProcess);
1530 test_image_mapping(dll_name, td[i].scn_page_access, FALSE);
1532 nt4_is_broken:
1533 SetLastError(0xdeadbeef);
1534 ret = DeleteFileA(dll_name);
1535 ok(ret || broken(!ret) /* nt4 */, "DeleteFile error %d\n", GetLastError());
1539 static void test_import_resolution(void)
1541 char temp_path[MAX_PATH];
1542 char dll_name[MAX_PATH];
1543 DWORD dummy;
1544 void *expect;
1545 char *str;
1546 HANDLE hfile;
1547 HMODULE mod, mod2;
1548 struct imports
1550 IMAGE_IMPORT_DESCRIPTOR descr[2];
1551 IMAGE_THUNK_DATA original_thunks[2];
1552 IMAGE_THUNK_DATA thunks[2];
1553 char module[16];
1554 struct { WORD hint; char name[32]; } function;
1555 IMAGE_TLS_DIRECTORY tls;
1556 char tls_data[16];
1557 SHORT tls_index;
1558 } data, *ptr;
1559 IMAGE_NT_HEADERS nt;
1560 IMAGE_SECTION_HEADER section;
1561 int test;
1563 for (test = 0; test < 3; test++)
1565 #define DATA_RVA(ptr) (page_size + ((char *)(ptr) - (char *)&data))
1566 nt = nt_header_template;
1567 nt.FileHeader.NumberOfSections = 1;
1568 nt.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1569 nt.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_RELOCS_STRIPPED;
1570 if (test != 2) nt.FileHeader.Characteristics |= IMAGE_FILE_DLL;
1571 nt.OptionalHeader.SectionAlignment = page_size;
1572 nt.OptionalHeader.FileAlignment = 0x200;
1573 nt.OptionalHeader.ImageBase = 0x12340000;
1574 nt.OptionalHeader.SizeOfImage = 2 * page_size;
1575 nt.OptionalHeader.SizeOfHeaders = nt.OptionalHeader.FileAlignment;
1576 nt.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
1577 memset( nt.OptionalHeader.DataDirectory, 0, sizeof(nt.OptionalHeader.DataDirectory) );
1578 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = sizeof(data.descr);
1579 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = DATA_RVA(data.descr);
1580 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = sizeof(data.tls);
1581 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = DATA_RVA(&data.tls);
1583 memset( &data, 0, sizeof(data) );
1584 data.descr[0].u.OriginalFirstThunk = DATA_RVA( data.original_thunks );
1585 data.descr[0].FirstThunk = DATA_RVA( data.thunks );
1586 data.descr[0].Name = DATA_RVA( data.module );
1587 strcpy( data.module, "kernel32.dll" );
1588 strcpy( data.function.name, "CreateEventA" );
1589 data.original_thunks[0].u1.AddressOfData = DATA_RVA( &data.function );
1590 data.thunks[0].u1.AddressOfData = 0xdeadbeef;
1592 data.tls.StartAddressOfRawData = nt.OptionalHeader.ImageBase + DATA_RVA( data.tls_data );
1593 data.tls.EndAddressOfRawData = data.tls.StartAddressOfRawData + sizeof(data.tls_data);
1594 data.tls.AddressOfIndex = nt.OptionalHeader.ImageBase + DATA_RVA( &data.tls_index );
1595 strcpy( data.tls_data, "hello world" );
1596 data.tls_index = 9999;
1598 GetTempPathA(MAX_PATH, temp_path);
1599 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
1601 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
1602 ok( hfile != INVALID_HANDLE_VALUE, "creation failed\n" );
1604 memset( &section, 0, sizeof(section) );
1605 memcpy( section.Name, ".text", sizeof(".text") );
1606 section.PointerToRawData = nt.OptionalHeader.FileAlignment;
1607 section.VirtualAddress = nt.OptionalHeader.SectionAlignment;
1608 section.Misc.VirtualSize = sizeof(data);
1609 section.SizeOfRawData = sizeof(data);
1610 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
1612 WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
1613 WriteFile(hfile, &nt, sizeof(nt), &dummy, NULL);
1614 WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
1616 SetFilePointer( hfile, section.PointerToRawData, NULL, SEEK_SET );
1617 WriteFile(hfile, &data, sizeof(data), &dummy, NULL);
1619 CloseHandle( hfile );
1621 switch (test)
1623 case 0: /* normal load */
1624 mod = LoadLibraryA( dll_name );
1625 ok( mod != NULL, "failed to load err %u\n", GetLastError() );
1626 if (!mod) break;
1627 ptr = (struct imports *)((char *)mod + page_size);
1628 expect = GetProcAddress( GetModuleHandleA( data.module ), data.function.name );
1629 ok( (void *)ptr->thunks[0].u1.Function == expect, "thunk %p instead of %p for %s.%s\n",
1630 (void *)ptr->thunks[0].u1.Function, expect, data.module, data.function.name );
1631 ok( ptr->tls_index < 32 || broken(ptr->tls_index == 9999), /* before vista */
1632 "wrong tls index %d\n", ptr->tls_index );
1633 if (ptr->tls_index != 9999)
1635 str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index];
1636 ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str );
1638 FreeLibrary( mod );
1639 break;
1640 case 1: /* load with DONT_RESOLVE_DLL_REFERENCES doesn't resolve imports */
1641 mod = LoadLibraryExA( dll_name, 0, DONT_RESOLVE_DLL_REFERENCES );
1642 ok( mod != NULL, "failed to load err %u\n", GetLastError() );
1643 if (!mod) break;
1644 ptr = (struct imports *)((char *)mod + page_size);
1645 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
1646 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
1647 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
1649 mod2 = LoadLibraryA( dll_name );
1650 ok( mod2 == mod, "loaded twice %p / %p\n", mod, mod2 );
1651 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
1652 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
1653 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
1654 FreeLibrary( mod2 );
1655 FreeLibrary( mod );
1656 break;
1657 case 2: /* load without IMAGE_FILE_DLL doesn't resolve imports */
1658 mod = LoadLibraryA( dll_name );
1659 ok( mod != NULL, "failed to load err %u\n", GetLastError() );
1660 if (!mod) break;
1661 ptr = (struct imports *)((char *)mod + page_size);
1662 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
1663 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
1664 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
1665 FreeLibrary( mod );
1666 break;
1668 DeleteFileA( dll_name );
1669 #undef DATA_RVA
1673 #define MAX_COUNT 10
1674 static HANDLE attached_thread[MAX_COUNT];
1675 static DWORD attached_thread_count;
1676 HANDLE stop_event, event, mutex, semaphore, loader_lock_event, peb_lock_event, heap_lock_event, ack_event;
1677 static int test_dll_phase, inside_loader_lock, inside_peb_lock, inside_heap_lock;
1678 static LONG fls_callback_count;
1680 static DWORD WINAPI mutex_thread_proc(void *param)
1682 HANDLE wait_list[4];
1683 DWORD ret;
1685 ret = WaitForSingleObject(mutex, 0);
1686 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1688 SetEvent(param);
1690 wait_list[0] = stop_event;
1691 wait_list[1] = loader_lock_event;
1692 wait_list[2] = peb_lock_event;
1693 wait_list[3] = heap_lock_event;
1695 trace("%04x: mutex_thread_proc: starting\n", GetCurrentThreadId());
1696 while (1)
1698 ret = WaitForMultipleObjects(sizeof(wait_list)/sizeof(wait_list[0]), wait_list, FALSE, 50);
1699 if (ret == WAIT_OBJECT_0) break;
1700 else if (ret == WAIT_OBJECT_0 + 1)
1702 ULONG_PTR loader_lock_magic;
1703 trace("%04x: mutex_thread_proc: Entering loader lock\n", GetCurrentThreadId());
1704 ret = pLdrLockLoaderLock(0, NULL, &loader_lock_magic);
1705 ok(!ret, "LdrLockLoaderLock error %#x\n", ret);
1706 inside_loader_lock++;
1707 SetEvent(ack_event);
1709 else if (ret == WAIT_OBJECT_0 + 2)
1711 trace("%04x: mutex_thread_proc: Entering PEB lock\n", GetCurrentThreadId());
1712 pRtlAcquirePebLock();
1713 inside_peb_lock++;
1714 SetEvent(ack_event);
1716 else if (ret == WAIT_OBJECT_0 + 3)
1718 trace("%04x: mutex_thread_proc: Entering heap lock\n", GetCurrentThreadId());
1719 HeapLock(GetProcessHeap());
1720 inside_heap_lock++;
1721 SetEvent(ack_event);
1725 trace("%04x: mutex_thread_proc: exiting\n", GetCurrentThreadId());
1726 return 196;
1729 static DWORD WINAPI semaphore_thread_proc(void *param)
1731 DWORD ret;
1733 ret = WaitForSingleObject(semaphore, 0);
1734 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1736 SetEvent(param);
1738 while (1)
1740 if (winetest_debug > 1)
1741 trace("%04x: semaphore_thread_proc: still alive\n", GetCurrentThreadId());
1742 if (WaitForSingleObject(stop_event, 50) != WAIT_TIMEOUT) break;
1745 trace("%04x: semaphore_thread_proc: exiting\n", GetCurrentThreadId());
1746 return 196;
1749 static DWORD WINAPI noop_thread_proc(void *param)
1751 if (param)
1753 LONG *noop_thread_started = param;
1754 InterlockedIncrement(noop_thread_started);
1757 trace("%04x: noop_thread_proc: exiting\n", GetCurrentThreadId());
1758 return 195;
1761 static VOID WINAPI fls_callback(PVOID lpFlsData)
1763 ok(lpFlsData == (void*) 0x31415, "lpFlsData is %p, expected %p\n", lpFlsData, (void*) 0x31415);
1764 InterlockedIncrement(&fls_callback_count);
1767 static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param)
1769 static LONG noop_thread_started;
1770 static DWORD fls_index = FLS_OUT_OF_INDEXES;
1771 static int fls_count = 0;
1772 static int thread_detach_count = 0;
1773 DWORD ret;
1775 ok(!inside_loader_lock, "inside_loader_lock should not be set\n");
1776 ok(!inside_peb_lock, "inside_peb_lock should not be set\n");
1778 switch (reason)
1780 case DLL_PROCESS_ATTACH:
1781 trace("dll: %p, DLL_PROCESS_ATTACH, %p\n", hinst, param);
1783 ret = pRtlDllShutdownInProgress();
1784 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1786 /* Set up the FLS slot, if FLS is available */
1787 if (pFlsGetValue)
1789 void* value;
1790 BOOL bret;
1791 ret = pFlsAlloc(&fls_callback);
1792 ok(ret != FLS_OUT_OF_INDEXES, "FlsAlloc returned %d\n", ret);
1793 fls_index = ret;
1794 SetLastError(0xdeadbeef);
1795 value = pFlsGetValue(fls_index);
1796 ok(!value, "FlsGetValue returned %p, expected NULL\n", value);
1797 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
1798 bret = pFlsSetValue(fls_index, (void*) 0x31415);
1799 ok(bret, "FlsSetValue failed\n");
1800 fls_count++;
1803 break;
1804 case DLL_PROCESS_DETACH:
1806 DWORD code, expected_code, i;
1807 HANDLE handle, process;
1808 void *addr;
1809 SIZE_T size;
1810 LARGE_INTEGER offset;
1811 DEBUG_EVENT de;
1813 trace("dll: %p, DLL_PROCESS_DETACH, %p\n", hinst, param);
1815 if (test_dll_phase == 4 || test_dll_phase == 5)
1817 ok(0, "dll_entry_point(DLL_PROCESS_DETACH) should not be called\n");
1818 break;
1821 /* The process should already deadlock at this point */
1822 if (test_dll_phase == 6)
1824 /* In reality, code below never gets executed, probably some other
1825 * code tries to access process heap and deadlocks earlier, even XP
1826 * doesn't call the DLL entry point on process detach either.
1828 HeapLock(GetProcessHeap());
1829 ok(0, "dll_entry_point: process should already deadlock\n");
1830 break;
1833 if (test_dll_phase == 0 || test_dll_phase == 1 || test_dll_phase == 3)
1834 ok(param != NULL, "dll: param %p\n", param);
1835 else
1836 ok(!param, "dll: param %p\n", param);
1838 if (test_dll_phase == 0 || test_dll_phase == 1) expected_code = 195;
1839 else if (test_dll_phase == 3) expected_code = 196;
1840 else expected_code = STILL_ACTIVE;
1842 if (test_dll_phase == 3)
1844 ret = pRtlDllShutdownInProgress();
1845 ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
1847 else
1849 ret = pRtlDllShutdownInProgress();
1851 /* FIXME: remove once Wine is fixed */
1852 todo_wine_if (!(expected_code == STILL_ACTIVE || expected_code == 196))
1853 ok(!ret || broken(ret) /* before Vista */, "RtlDllShutdownInProgress returned %d\n", ret);
1856 /* In the case that the process is terminating, FLS slots should still be accessible, but
1857 * the callback should be already run for this thread and the contents already NULL.
1858 * Note that this is broken for Win2k3, which runs the callbacks *after* the DLL entry
1859 * point has already run.
1861 if (param && pFlsGetValue)
1863 void* value;
1864 SetLastError(0xdeadbeef);
1865 value = pFlsGetValue(fls_index);
1866 todo_wine
1868 ok(broken(value == (void*) 0x31415) || /* Win2k3 */
1869 value == NULL, "FlsGetValue returned %p, expected NULL\n", value);
1871 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
1872 todo_wine
1874 ok(broken(fls_callback_count == thread_detach_count) || /* Win2k3 */
1875 fls_callback_count == thread_detach_count + 1,
1876 "wrong FLS callback count %d, expected %d\n", fls_callback_count, thread_detach_count + 1);
1879 if (pFlsFree)
1881 BOOL ret;
1882 /* Call FlsFree now and run the remaining callbacks from uncleanly terminated threads */
1883 ret = pFlsFree(fls_index);
1884 ok(ret, "FlsFree failed with error %u\n", GetLastError());
1885 fls_index = FLS_OUT_OF_INDEXES;
1886 todo_wine
1888 ok(fls_callback_count == fls_count,
1889 "wrong FLS callback count %d, expected %d\n", fls_callback_count, fls_count);
1893 ok(attached_thread_count >= 2, "attached thread count should be >= 2\n");
1895 for (i = 0; i < attached_thread_count; i++)
1897 /* Calling GetExitCodeThread() without waiting for thread termination
1898 * leads to different results due to a race condition.
1900 if (expected_code != STILL_ACTIVE)
1902 ret = WaitForSingleObject(attached_thread[i], 1000);
1903 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1905 ret = GetExitCodeThread(attached_thread[i], &code);
1906 trace("dll: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
1907 ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
1908 ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code);
1911 ret = WaitForSingleObject(event, 0);
1912 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1914 ret = WaitForSingleObject(mutex, 0);
1915 if (expected_code == STILL_ACTIVE)
1916 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1917 else
1918 ok(ret == WAIT_ABANDONED, "expected WAIT_ABANDONED, got %#x\n", ret);
1920 /* semaphore is not abandoned on thread termination */
1921 ret = WaitForSingleObject(semaphore, 0);
1922 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1924 if (expected_code == STILL_ACTIVE)
1926 ret = WaitForSingleObject(attached_thread[0], 0);
1927 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1928 ret = WaitForSingleObject(attached_thread[1], 0);
1929 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1931 else
1933 ret = WaitForSingleObject(attached_thread[0], 0);
1934 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1935 ret = WaitForSingleObject(attached_thread[1], 0);
1936 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1939 /* win7 doesn't allow creating a thread during process shutdown but
1940 * earlier Windows versions allow it.
1942 noop_thread_started = 0;
1943 SetLastError(0xdeadbeef);
1944 handle = CreateThread(NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
1945 if (param)
1947 ok(!handle || broken(handle != 0) /* before win7 */, "CreateThread should fail\n");
1948 if (!handle)
1949 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1950 else
1952 ret = WaitForSingleObject(handle, 1000);
1953 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1954 CloseHandle(handle);
1957 else
1959 ok(handle != 0, "CreateThread error %d\n", GetLastError());
1960 ret = WaitForSingleObject(handle, 1000);
1961 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1962 ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n");
1963 CloseHandle(handle);
1966 SetLastError(0xdeadbeef);
1967 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, GetCurrentProcessId());
1968 ok(process != NULL, "OpenProcess error %d\n", GetLastError());
1970 noop_thread_started = 0;
1971 SetLastError(0xdeadbeef);
1972 handle = CreateRemoteThread(process, NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
1973 if (param)
1975 ok(!handle || broken(handle != 0) /* before win7 */, "CreateRemoteThread should fail\n");
1976 if (!handle)
1977 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1978 else
1980 ret = WaitForSingleObject(handle, 1000);
1981 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1982 CloseHandle(handle);
1985 else
1987 ok(handle != 0, "CreateRemoteThread error %d\n", GetLastError());
1988 ret = WaitForSingleObject(handle, 1000);
1989 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1990 ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n");
1991 CloseHandle(handle);
1994 SetLastError(0xdeadbeef);
1995 handle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
1996 ok(handle != 0, "CreateFileMapping error %d\n", GetLastError());
1998 offset.u.LowPart = 0;
1999 offset.u.HighPart = 0;
2000 addr = NULL;
2001 size = 0;
2002 ret = pNtMapViewOfSection(handle, process, &addr, 0, 0, &offset,
2003 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
2004 ok(ret == STATUS_SUCCESS, "NtMapViewOfSection error %#x\n", ret);
2005 ret = pNtUnmapViewOfSection(process, addr);
2006 ok(ret == STATUS_SUCCESS, "NtUnmapViewOfSection error %#x\n", ret);
2008 CloseHandle(handle);
2009 CloseHandle(process);
2011 handle = GetModuleHandleA("winver.exe");
2012 ok(!handle, "winver.exe shouldn't be loaded yet\n");
2013 SetLastError(0xdeadbeef);
2014 handle = LoadLibraryA("winver.exe");
2015 ok(handle != 0, "LoadLibrary error %d\n", GetLastError());
2016 SetLastError(0xdeadbeef);
2017 ret = FreeLibrary(handle);
2018 ok(ret, "FreeLibrary error %d\n", GetLastError());
2019 handle = GetModuleHandleA("winver.exe");
2020 if (param)
2021 ok(handle != 0, "winver.exe should not be unloaded\n");
2022 else
2023 todo_wine
2024 ok(!handle || broken(handle != 0) /* before win7 */, "winver.exe should be unloaded\n");
2026 SetLastError(0xdeadbeef);
2027 ret = WaitForDebugEvent(&de, 0);
2028 ok(!ret, "WaitForDebugEvent should fail\n");
2029 todo_wine
2030 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
2032 SetLastError(0xdeadbeef);
2033 ret = DebugActiveProcess(GetCurrentProcessId());
2034 ok(!ret, "DebugActiveProcess should fail\n");
2035 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2037 SetLastError(0xdeadbeef);
2038 ret = WaitForDebugEvent(&de, 0);
2039 ok(!ret, "WaitForDebugEvent should fail\n");
2040 ok(GetLastError() == ERROR_SEM_TIMEOUT, "expected ERROR_SEM_TIMEOUT, got %d\n", GetLastError());
2042 if (test_dll_phase == 2)
2044 trace("dll: call ExitProcess()\n");
2045 *child_failures = winetest_get_failures();
2046 ExitProcess(197);
2048 trace("dll: %p, DLL_PROCESS_DETACH, %p => DONE\n", hinst, param);
2049 break;
2051 case DLL_THREAD_ATTACH:
2052 trace("dll: %p, DLL_THREAD_ATTACH, %p\n", hinst, param);
2054 ret = pRtlDllShutdownInProgress();
2055 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2057 if (attached_thread_count < MAX_COUNT)
2059 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &attached_thread[attached_thread_count],
2060 0, TRUE, DUPLICATE_SAME_ACCESS);
2061 attached_thread_count++;
2064 /* Make sure the FLS slot is empty, if FLS is available */
2065 if (pFlsGetValue)
2067 void* value;
2068 BOOL ret;
2069 SetLastError(0xdeadbeef);
2070 value = pFlsGetValue(fls_index);
2071 ok(!value, "FlsGetValue returned %p, expected NULL\n", value);
2072 todo_wine
2073 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
2074 ret = pFlsSetValue(fls_index, (void*) 0x31415);
2075 ok(ret, "FlsSetValue failed\n");
2076 fls_count++;
2079 break;
2080 case DLL_THREAD_DETACH:
2081 trace("dll: %p, DLL_THREAD_DETACH, %p\n", hinst, param);
2082 thread_detach_count++;
2084 ret = pRtlDllShutdownInProgress();
2085 /* win7 doesn't allow creating a thread during process shutdown but
2086 * earlier Windows versions allow it. In that case DLL_THREAD_DETACH is
2087 * sent on thread exit, but DLL_THREAD_ATTACH is never received.
2089 if (noop_thread_started)
2090 ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
2091 else
2092 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2094 /* FLS data should already be destroyed, if FLS is available.
2095 * Note that this is broken for Win2k3, which runs the callbacks *after* the DLL entry
2096 * point has already run.
2098 if (pFlsGetValue && fls_index != FLS_OUT_OF_INDEXES)
2100 void* value;
2101 SetLastError(0xdeadbeef);
2102 value = pFlsGetValue(fls_index);
2103 todo_wine
2105 ok(broken(value == (void*) 0x31415) || /* Win2k3 */
2106 !value, "FlsGetValue returned %p, expected NULL\n", value);
2108 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
2111 break;
2112 default:
2113 trace("dll: %p, %d, %p\n", hinst, reason, param);
2114 break;
2117 *child_failures = winetest_get_failures();
2119 return TRUE;
2122 static void child_process(const char *dll_name, DWORD target_offset)
2124 void *target;
2125 DWORD ret, dummy, i, code, expected_code;
2126 HANDLE file, thread, process;
2127 HMODULE hmod;
2128 struct PROCESS_BASIC_INFORMATION_PRIVATE pbi;
2129 DWORD_PTR affinity;
2131 trace("phase %d: writing %p at %#x\n", test_dll_phase, dll_entry_point, target_offset);
2133 SetLastError(0xdeadbeef);
2134 mutex = CreateMutexW(NULL, FALSE, NULL);
2135 ok(mutex != 0, "CreateMutex error %d\n", GetLastError());
2137 SetLastError(0xdeadbeef);
2138 semaphore = CreateSemaphoreW(NULL, 1, 1, NULL);
2139 ok(semaphore != 0, "CreateSemaphore error %d\n", GetLastError());
2141 SetLastError(0xdeadbeef);
2142 event = CreateEventW(NULL, TRUE, FALSE, NULL);
2143 ok(event != 0, "CreateEvent error %d\n", GetLastError());
2145 SetLastError(0xdeadbeef);
2146 loader_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2147 ok(loader_lock_event != 0, "CreateEvent error %d\n", GetLastError());
2149 SetLastError(0xdeadbeef);
2150 peb_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2151 ok(peb_lock_event != 0, "CreateEvent error %d\n", GetLastError());
2153 SetLastError(0xdeadbeef);
2154 heap_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2155 ok(heap_lock_event != 0, "CreateEvent error %d\n", GetLastError());
2157 SetLastError(0xdeadbeef);
2158 ack_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2159 ok(ack_event != 0, "CreateEvent error %d\n", GetLastError());
2161 file = CreateFileA(dll_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2162 if (file == INVALID_HANDLE_VALUE)
2164 ok(0, "could not open %s\n", dll_name);
2165 return;
2167 SetFilePointer(file, target_offset, NULL, FILE_BEGIN);
2168 SetLastError(0xdeadbeef);
2169 target = dll_entry_point;
2170 ret = WriteFile(file, &target, sizeof(target), &dummy, NULL);
2171 ok(ret, "WriteFile error %d\n", GetLastError());
2172 CloseHandle(file);
2174 SetLastError(0xdeadbeef);
2175 hmod = LoadLibraryA(dll_name);
2176 ok(hmod != 0, "LoadLibrary error %d\n", GetLastError());
2178 SetLastError(0xdeadbeef);
2179 stop_event = CreateEventW(NULL, TRUE, FALSE, NULL);
2180 ok(stop_event != 0, "CreateEvent error %d\n", GetLastError());
2182 SetLastError(0xdeadbeef);
2183 thread = CreateThread(NULL, 0, mutex_thread_proc, event, 0, &dummy);
2184 ok(thread != 0, "CreateThread error %d\n", GetLastError());
2185 WaitForSingleObject(event, 3000);
2186 CloseHandle(thread);
2188 ResetEvent(event);
2190 SetLastError(0xdeadbeef);
2191 thread = CreateThread(NULL, 0, semaphore_thread_proc, event, 0, &dummy);
2192 ok(thread != 0, "CreateThread error %d\n", GetLastError());
2193 WaitForSingleObject(event, 3000);
2194 CloseHandle(thread);
2196 ResetEvent(event);
2197 Sleep(100);
2199 ok(attached_thread_count == 2, "attached thread count should be 2\n");
2200 for (i = 0; i < attached_thread_count; i++)
2202 ret = GetExitCodeThread(attached_thread[i], &code);
2203 trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
2204 ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
2205 ok(code == STILL_ACTIVE, "expected thread exit code STILL_ACTIVE, got %u\n", code);
2208 ret = WaitForSingleObject(attached_thread[0], 0);
2209 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2210 ret = WaitForSingleObject(attached_thread[1], 0);
2211 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2213 ret = WaitForSingleObject(event, 0);
2214 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2215 ret = WaitForSingleObject(mutex, 0);
2216 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2217 ret = WaitForSingleObject(semaphore, 0);
2218 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2220 ret = pRtlDllShutdownInProgress();
2221 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2223 SetLastError(0xdeadbeef);
2224 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, GetCurrentProcessId());
2225 ok(process != NULL, "OpenProcess error %d\n", GetLastError());
2227 SetLastError(0xdeadbeef);
2228 ret = TerminateProcess(0, 195);
2229 ok(!ret, "TerminateProcess(0) should fail\n");
2230 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
2232 Sleep(100);
2234 affinity = 1;
2235 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
2236 ok(!ret, "NtSetInformationProcess error %#x\n", ret);
2238 switch (test_dll_phase)
2240 case 0:
2241 ret = pRtlDllShutdownInProgress();
2242 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2244 trace("call NtTerminateProcess(0, 195)\n");
2245 ret = pNtTerminateProcess(0, 195);
2246 ok(!ret, "NtTerminateProcess error %#x\n", ret);
2248 memset(&pbi, 0, sizeof(pbi));
2249 ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
2250 ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
2251 ok(pbi.ExitStatus == STILL_ACTIVE || pbi.ExitStatus == 195,
2252 "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus);
2253 affinity = 1;
2254 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
2255 ok(!ret, "NtSetInformationProcess error %#x\n", ret);
2257 ret = pRtlDllShutdownInProgress();
2258 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2260 hmod = GetModuleHandleA(dll_name);
2261 ok(hmod != 0, "DLL should not be unloaded\n");
2263 SetLastError(0xdeadbeef);
2264 thread = CreateThread(NULL, 0, noop_thread_proc, &dummy, 0, &ret);
2265 ok(!thread || broken(thread != 0) /* before win7 */, "CreateThread should fail\n");
2266 if (!thread)
2267 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2268 else
2270 ret = WaitForSingleObject(thread, 1000);
2271 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2272 CloseHandle(thread);
2275 trace("call LdrShutdownProcess()\n");
2276 pLdrShutdownProcess();
2278 ret = pRtlDllShutdownInProgress();
2279 ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
2281 hmod = GetModuleHandleA(dll_name);
2282 ok(hmod != 0, "DLL should not be unloaded\n");
2284 memset(&pbi, 0, sizeof(pbi));
2285 ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
2286 ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
2287 ok(pbi.ExitStatus == STILL_ACTIVE || pbi.ExitStatus == 195,
2288 "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus);
2289 affinity = 1;
2290 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
2291 ok(!ret, "NtSetInformationProcess error %#x\n", ret);
2292 break;
2294 case 1: /* normal ExitProcess */
2295 ret = pRtlDllShutdownInProgress();
2296 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2297 break;
2299 case 2: /* ExitProcess will be called by the PROCESS_DETACH handler */
2300 ret = pRtlDllShutdownInProgress();
2301 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2303 trace("call FreeLibrary(%p)\n", hmod);
2304 SetLastError(0xdeadbeef);
2305 ret = FreeLibrary(hmod);
2306 ok(ret, "FreeLibrary error %d\n", GetLastError());
2307 hmod = GetModuleHandleA(dll_name);
2308 ok(!hmod, "DLL should be unloaded\n");
2310 if (test_dll_phase == 2)
2311 ok(0, "FreeLibrary+ExitProcess should never return\n");
2313 ret = pRtlDllShutdownInProgress();
2314 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2316 break;
2318 case 3:
2319 trace("signalling thread exit\n");
2320 SetEvent(stop_event);
2321 break;
2323 case 4:
2324 trace("setting loader_lock_event\n");
2325 SetEvent(loader_lock_event);
2326 WaitForSingleObject(ack_event, 1000);
2327 ok(inside_loader_lock != 0, "inside_loader_lock is not set\n");
2329 /* calling NtTerminateProcess should not cause a deadlock */
2330 trace("call NtTerminateProcess(0, 198)\n");
2331 ret = pNtTerminateProcess(0, 198);
2332 ok(!ret, "NtTerminateProcess error %#x\n", ret);
2334 *child_failures = winetest_get_failures();
2336 /* Windows fails to release loader lock acquired from another thread,
2337 * so the LdrUnlockLoaderLock call fails here and ExitProcess deadlocks
2338 * later on, so NtTerminateProcess is used instead.
2340 trace("call NtTerminateProcess(GetCurrentProcess(), 198)\n");
2341 pNtTerminateProcess(GetCurrentProcess(), 198);
2342 ok(0, "NtTerminateProcess should not return\n");
2343 break;
2345 case 5:
2346 trace("setting peb_lock_event\n");
2347 SetEvent(peb_lock_event);
2348 WaitForSingleObject(ack_event, 1000);
2349 ok(inside_peb_lock != 0, "inside_peb_lock is not set\n");
2351 *child_failures = winetest_get_failures();
2353 /* calling ExitProcess should cause a deadlock */
2354 trace("call ExitProcess(198)\n");
2355 ExitProcess(198);
2356 ok(0, "ExitProcess should not return\n");
2357 break;
2359 case 6:
2360 trace("setting heap_lock_event\n");
2361 SetEvent(heap_lock_event);
2362 WaitForSingleObject(ack_event, 1000);
2363 ok(inside_heap_lock != 0, "inside_heap_lock is not set\n");
2365 *child_failures = winetest_get_failures();
2367 /* calling ExitProcess should cause a deadlock */
2368 trace("call ExitProcess(1)\n");
2369 ExitProcess(1);
2370 ok(0, "ExitProcess should not return\n");
2371 break;
2373 default:
2374 assert(0);
2375 break;
2378 if (test_dll_phase == 0) expected_code = 195;
2379 else if (test_dll_phase == 3) expected_code = 196;
2380 else if (test_dll_phase == 4) expected_code = 198;
2381 else expected_code = STILL_ACTIVE;
2383 if (expected_code == STILL_ACTIVE)
2385 ret = WaitForSingleObject(attached_thread[0], 100);
2386 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2387 ret = WaitForSingleObject(attached_thread[1], 100);
2388 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2390 else
2392 ret = WaitForSingleObject(attached_thread[0], 2000);
2393 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2394 ret = WaitForSingleObject(attached_thread[1], 2000);
2395 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2398 for (i = 0; i < attached_thread_count; i++)
2400 ret = GetExitCodeThread(attached_thread[i], &code);
2401 trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
2402 ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
2403 ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code);
2406 *child_failures = winetest_get_failures();
2408 trace("call ExitProcess(195)\n");
2409 ExitProcess(195);
2412 static void test_ExitProcess(void)
2414 #include "pshpack1.h"
2415 #ifdef __x86_64__
2416 static struct section_data
2418 BYTE mov_rax[2];
2419 void *target;
2420 BYTE jmp_rax[2];
2421 } section_data = { { 0x48,0xb8 }, dll_entry_point, { 0xff,0xe0 } };
2422 #else
2423 static struct section_data
2425 BYTE mov_eax;
2426 void *target;
2427 BYTE jmp_eax[2];
2428 } section_data = { 0xb8, dll_entry_point, { 0xff,0xe0 } };
2429 #endif
2430 #include "poppack.h"
2431 DWORD dummy, file_align;
2432 HANDLE file, thread, process, hmap, hmap_dup;
2433 char temp_path[MAX_PATH], dll_name[MAX_PATH], cmdline[MAX_PATH * 2];
2434 DWORD ret, target_offset, old_prot;
2435 char **argv, buf[256];
2436 PROCESS_INFORMATION pi;
2437 STARTUPINFOA si = { sizeof(si) };
2438 CONTEXT ctx;
2439 struct PROCESS_BASIC_INFORMATION_PRIVATE pbi;
2440 MEMORY_BASIC_INFORMATION mbi;
2441 DWORD_PTR affinity;
2442 void *addr;
2443 LARGE_INTEGER offset;
2444 SIZE_T size;
2445 IMAGE_NT_HEADERS nt_header;
2447 #if !defined(__i386__) && !defined(__x86_64__)
2448 skip("x86 specific ExitProcess test\n");
2449 return;
2450 #endif
2452 if (!pRtlDllShutdownInProgress)
2454 win_skip("RtlDllShutdownInProgress is not available on this platform (XP+)\n");
2455 return;
2457 if (!pNtQueryInformationProcess || !pNtSetInformationProcess)
2459 win_skip("NtQueryInformationProcess/NtSetInformationProcess are not available on this platform\n");
2460 return;
2462 if (!pNtAllocateVirtualMemory || !pNtFreeVirtualMemory)
2464 win_skip("NtAllocateVirtualMemory/NtFreeVirtualMemory are not available on this platform\n");
2465 return;
2468 /* prevent displaying of the "Unable to load this DLL" message box */
2469 SetErrorMode(SEM_FAILCRITICALERRORS);
2471 GetTempPathA(MAX_PATH, temp_path);
2472 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
2474 /*trace("creating %s\n", dll_name);*/
2475 file = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2476 if (file == INVALID_HANDLE_VALUE)
2478 ok(0, "could not create %s\n", dll_name);
2479 return;
2482 SetLastError(0xdeadbeef);
2483 ret = WriteFile(file, &dos_header, sizeof(dos_header), &dummy, NULL);
2484 ok(ret, "WriteFile error %d\n", GetLastError());
2486 nt_header = nt_header_template;
2487 nt_header.FileHeader.NumberOfSections = 1;
2488 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
2489 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED;
2491 nt_header.OptionalHeader.AddressOfEntryPoint = 0x1000;
2492 nt_header.OptionalHeader.SectionAlignment = 0x1000;
2493 nt_header.OptionalHeader.FileAlignment = 0x200;
2494 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000;
2495 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
2496 SetLastError(0xdeadbeef);
2497 ret = WriteFile(file, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
2498 ok(ret, "WriteFile error %d\n", GetLastError());
2499 SetLastError(0xdeadbeef);
2500 ret = WriteFile(file, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
2501 ok(ret, "WriteFile error %d\n", GetLastError());
2503 section.SizeOfRawData = sizeof(section_data);
2504 section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
2505 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
2506 section.Misc.VirtualSize = sizeof(section_data);
2507 section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
2508 SetLastError(0xdeadbeef);
2509 ret = WriteFile(file, &section, sizeof(section), &dummy, NULL);
2510 ok(ret, "WriteFile error %d\n", GetLastError());
2512 file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
2513 assert(file_align < sizeof(filler));
2514 SetLastError(0xdeadbeef);
2515 ret = WriteFile(file, filler, file_align, &dummy, NULL);
2516 ok(ret, "WriteFile error %d\n", GetLastError());
2518 target_offset = SetFilePointer(file, 0, NULL, FILE_CURRENT) + FIELD_OFFSET(struct section_data, target);
2520 /* section data */
2521 SetLastError(0xdeadbeef);
2522 ret = WriteFile(file, &section_data, sizeof(section_data), &dummy, NULL);
2523 ok(ret, "WriteFile error %d\n", GetLastError());
2525 CloseHandle(file);
2527 winetest_get_mainargs(&argv);
2529 /* phase 0 */
2530 *child_failures = -1;
2531 sprintf(cmdline, "\"%s\" loader %s %u 0", argv[0], dll_name, target_offset);
2532 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2533 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2534 ret = WaitForSingleObject(pi.hProcess, 10000);
2535 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2536 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2537 GetExitCodeProcess(pi.hProcess, &ret);
2538 ok(ret == 195, "expected exit code 195, got %u\n", ret);
2539 if (*child_failures)
2541 trace("%d failures in child process\n", *child_failures);
2542 winetest_add_failures(*child_failures);
2544 CloseHandle(pi.hThread);
2545 CloseHandle(pi.hProcess);
2547 /* phase 1 */
2548 *child_failures = -1;
2549 sprintf(cmdline, "\"%s\" loader %s %u 1", argv[0], dll_name, target_offset);
2550 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2551 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2552 ret = WaitForSingleObject(pi.hProcess, 10000);
2553 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2554 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2555 GetExitCodeProcess(pi.hProcess, &ret);
2556 ok(ret == 195, "expected exit code 195, got %u\n", ret);
2557 if (*child_failures)
2559 trace("%d failures in child process\n", *child_failures);
2560 winetest_add_failures(*child_failures);
2562 CloseHandle(pi.hThread);
2563 CloseHandle(pi.hProcess);
2565 /* phase 2 */
2566 *child_failures = -1;
2567 sprintf(cmdline, "\"%s\" loader %s %u 2", argv[0], dll_name, target_offset);
2568 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2569 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2570 ret = WaitForSingleObject(pi.hProcess, 10000);
2571 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2572 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2573 GetExitCodeProcess(pi.hProcess, &ret);
2574 ok(ret == 197, "expected exit code 197, got %u\n", ret);
2575 if (*child_failures)
2577 trace("%d failures in child process\n", *child_failures);
2578 winetest_add_failures(*child_failures);
2580 CloseHandle(pi.hThread);
2581 CloseHandle(pi.hProcess);
2583 /* phase 3 */
2584 *child_failures = -1;
2585 sprintf(cmdline, "\"%s\" loader %s %u 3", argv[0], dll_name, target_offset);
2586 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2587 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2588 ret = WaitForSingleObject(pi.hProcess, 10000);
2589 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2590 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2591 GetExitCodeProcess(pi.hProcess, &ret);
2592 ok(ret == 195, "expected exit code 195, got %u\n", ret);
2593 if (*child_failures)
2595 trace("%d failures in child process\n", *child_failures);
2596 winetest_add_failures(*child_failures);
2598 CloseHandle(pi.hThread);
2599 CloseHandle(pi.hProcess);
2601 /* phase 4 */
2602 if (pLdrLockLoaderLock && pLdrUnlockLoaderLock)
2604 *child_failures = -1;
2605 sprintf(cmdline, "\"%s\" loader %s %u 4", argv[0], dll_name, target_offset);
2606 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2607 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2608 ret = WaitForSingleObject(pi.hProcess, 10000);
2609 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2610 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2611 GetExitCodeProcess(pi.hProcess, &ret);
2612 ok(ret == 198, "expected exit code 198, got %u\n", ret);
2613 if (*child_failures)
2615 trace("%d failures in child process\n", *child_failures);
2616 winetest_add_failures(*child_failures);
2618 CloseHandle(pi.hThread);
2619 CloseHandle(pi.hProcess);
2621 else
2622 win_skip("LdrLockLoaderLock/LdrUnlockLoaderLock are not available on this platform\n");
2624 /* phase 5 */
2625 if (pRtlAcquirePebLock && pRtlReleasePebLock)
2627 *child_failures = -1;
2628 sprintf(cmdline, "\"%s\" loader %s %u 5", argv[0], dll_name, target_offset);
2629 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2630 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2631 ret = WaitForSingleObject(pi.hProcess, 5000);
2632 ok(ret == WAIT_TIMEOUT, "child process should fail to terminate\n");
2633 if (ret != WAIT_OBJECT_0)
2635 trace("terminating child process\n");
2636 TerminateProcess(pi.hProcess, 199);
2638 ret = WaitForSingleObject(pi.hProcess, 1000);
2639 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2640 GetExitCodeProcess(pi.hProcess, &ret);
2641 ok(ret == 199, "expected exit code 199, got %u\n", ret);
2642 if (*child_failures)
2644 trace("%d failures in child process\n", *child_failures);
2645 winetest_add_failures(*child_failures);
2647 CloseHandle(pi.hThread);
2648 CloseHandle(pi.hProcess);
2650 else
2651 win_skip("RtlAcquirePebLock/RtlReleasePebLock are not available on this platform\n");
2653 /* phase 6 */
2654 *child_failures = -1;
2655 sprintf(cmdline, "\"%s\" loader %s %u 6", argv[0], dll_name, target_offset);
2656 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2657 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2658 ret = WaitForSingleObject(pi.hProcess, 5000);
2659 ok(ret == WAIT_TIMEOUT || broken(ret == WAIT_OBJECT_0) /* XP */, "child process should fail to terminate\n");
2660 if (ret != WAIT_OBJECT_0)
2662 trace("terminating child process\n");
2663 TerminateProcess(pi.hProcess, 201);
2665 ret = WaitForSingleObject(pi.hProcess, 1000);
2666 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2667 GetExitCodeProcess(pi.hProcess, &ret);
2668 ok(ret == 201 || broken(ret == 1) /* XP */, "expected exit code 201, got %u\n", ret);
2669 if (*child_failures)
2671 trace("%d failures in child process\n", *child_failures);
2672 winetest_add_failures(*child_failures);
2674 CloseHandle(pi.hThread);
2675 CloseHandle(pi.hProcess);
2677 /* test remote process termination */
2678 SetLastError(0xdeadbeef);
2679 ret = CreateProcessA(argv[0], NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
2680 ok(ret, "CreateProcess(%s) error %d\n", argv[0], GetLastError());
2682 SetLastError(0xdeadbeef);
2683 addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
2684 ok(addr != NULL, "VirtualAllocEx error %d\n", GetLastError());
2685 SetLastError(0xdeadbeef);
2686 ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READONLY, &old_prot);
2687 ok(ret, "VirtualProtectEx error %d\n", GetLastError());
2688 ok(old_prot == PAGE_READWRITE, "expected PAGE_READWRITE, got %#x\n", old_prot);
2689 SetLastError(0xdeadbeef);
2690 size = VirtualQueryEx(pi.hProcess, NULL, &mbi, sizeof(mbi));
2691 ok(size == sizeof(mbi), "VirtualQueryEx error %d\n", GetLastError());
2693 SetLastError(0xdeadbeef);
2694 ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size);
2695 ok(ret, "ReadProcessMemory error %d\n", GetLastError());
2696 ok(size == 4, "expected 4, got %lu\n", size);
2698 SetLastError(0xdeadbeef);
2699 hmap = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
2700 ok(hmap != 0, "CreateFileMapping error %d\n", GetLastError());
2702 SetLastError(0xdeadbeef);
2703 ret = DuplicateHandle(GetCurrentProcess(), hmap, pi.hProcess, &hmap_dup,
2704 0, FALSE, DUPLICATE_SAME_ACCESS);
2705 ok(ret, "DuplicateHandle error %d\n", GetLastError());
2707 offset.u.LowPart = 0;
2708 offset.u.HighPart = 0;
2709 addr = NULL;
2710 size = 0;
2711 ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset,
2712 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
2713 ok(!ret, "NtMapViewOfSection error %#x\n", ret);
2714 ret = pNtUnmapViewOfSection(pi.hProcess, addr);
2715 ok(!ret, "NtUnmapViewOfSection error %#x\n", ret);
2717 SetLastError(0xdeadbeef);
2718 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2719 ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError());
2720 SetLastError(0xdeadbeef);
2721 ctx.ContextFlags = CONTEXT_INTEGER;
2722 ret = GetThreadContext(thread, &ctx);
2723 ok(ret, "GetThreadContext error %d\n", GetLastError());
2724 SetLastError(0xdeadbeef);
2725 ctx.ContextFlags = CONTEXT_INTEGER;
2726 ret = SetThreadContext(thread, &ctx);
2727 ok(ret, "SetThreadContext error %d\n", GetLastError());
2728 SetLastError(0xdeadbeef);
2729 ret = SetThreadPriority(thread, 0);
2730 ok(ret, "SetThreadPriority error %d\n", GetLastError());
2732 SetLastError(0xdeadbeef);
2733 ret = TerminateThread(thread, 199);
2734 ok(ret, "TerminateThread error %d\n", GetLastError());
2735 /* Calling GetExitCodeThread() without waiting for thread termination
2736 * leads to different results due to a race condition.
2738 ret = WaitForSingleObject(thread, 1000);
2739 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
2740 GetExitCodeThread(thread, &ret);
2741 ok(ret == 199, "expected exit code 199, got %u\n", ret);
2743 SetLastError(0xdeadbeef);
2744 ret = TerminateProcess(pi.hProcess, 198);
2745 ok(ret, "TerminateProcess error %d\n", GetLastError());
2746 /* Checking process state without waiting for process termination
2747 * leads to different results due to a race condition.
2749 ret = WaitForSingleObject(pi.hProcess, 1000);
2750 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
2752 SetLastError(0xdeadbeef);
2753 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pi.dwProcessId);
2754 ok(process != NULL, "OpenProcess error %d\n", GetLastError());
2755 CloseHandle(process);
2757 memset(&pbi, 0, sizeof(pbi));
2758 ret = pNtQueryInformationProcess(pi.hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
2759 ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
2760 ok(pbi.ExitStatus == 198, "expected 198, got %lu\n", pbi.ExitStatus);
2761 affinity = 1;
2762 ret = pNtSetInformationProcess(pi.hProcess, ProcessAffinityMask, &affinity, sizeof(affinity));
2763 ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#x\n", ret);
2765 SetLastError(0xdeadbeef);
2766 ctx.ContextFlags = CONTEXT_INTEGER;
2767 ret = GetThreadContext(thread, &ctx);
2768 ok(!ret || broken(ret) /* XP 64-bit */, "GetThreadContext should fail\n");
2769 if (!ret)
2770 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
2771 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
2772 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
2773 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2774 SetLastError(0xdeadbeef);
2775 ctx.ContextFlags = CONTEXT_INTEGER;
2776 ret = SetThreadContext(thread, &ctx);
2777 ok(!ret || broken(ret) /* XP 64-bit */, "SetThreadContext should fail\n");
2778 if (!ret)
2779 ok(GetLastError() == ERROR_ACCESS_DENIED ||
2780 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
2781 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
2782 "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2783 SetLastError(0xdeadbeef);
2784 ret = SetThreadPriority(thread, 0);
2785 ok(ret, "SetThreadPriority error %d\n", GetLastError());
2786 CloseHandle(thread);
2788 SetLastError(0xdeadbeef);
2789 ctx.ContextFlags = CONTEXT_INTEGER;
2790 ret = GetThreadContext(pi.hThread, &ctx);
2791 ok(!ret || broken(ret) /* XP 64-bit */, "GetThreadContext should fail\n");
2792 if (!ret)
2793 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
2794 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
2795 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
2796 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2797 SetLastError(0xdeadbeef);
2798 ctx.ContextFlags = CONTEXT_INTEGER;
2799 ret = SetThreadContext(pi.hThread, &ctx);
2800 ok(!ret || broken(ret) /* XP 64-bit */, "SetThreadContext should fail\n");
2801 if (!ret)
2802 ok(GetLastError() == ERROR_ACCESS_DENIED ||
2803 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
2804 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
2805 "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2806 SetLastError(0xdeadbeef);
2807 ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READWRITE, &old_prot);
2808 ok(!ret, "VirtualProtectEx should fail\n");
2809 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2810 SetLastError(0xdeadbeef);
2811 size = 0;
2812 ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size);
2813 ok(!ret, "ReadProcessMemory should fail\n");
2814 ok(GetLastError() == ERROR_PARTIAL_COPY || GetLastError() == ERROR_ACCESS_DENIED,
2815 "expected ERROR_PARTIAL_COPY, got %d\n", GetLastError());
2816 ok(!size, "expected 0, got %lu\n", size);
2817 SetLastError(0xdeadbeef);
2818 ret = VirtualFreeEx(pi.hProcess, addr, 0, MEM_RELEASE);
2819 ok(!ret, "VirtualFreeEx should fail\n");
2820 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2821 SetLastError(0xdeadbeef);
2822 addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
2823 ok(!addr, "VirtualAllocEx should fail\n");
2824 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2825 SetLastError(0xdeadbeef);
2826 size = VirtualQueryEx(pi.hProcess, NULL, &mbi, sizeof(mbi));
2827 ok(!size, "VirtualQueryEx should fail\n");
2828 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2830 /* CloseHandle() call below leads to premature process termination
2831 * under some Windows versions.
2833 if (0)
2835 SetLastError(0xdeadbeef);
2836 ret = CloseHandle(hmap_dup);
2837 ok(ret, "CloseHandle should not fail\n");
2840 SetLastError(0xdeadbeef);
2841 ret = DuplicateHandle(GetCurrentProcess(), hmap, pi.hProcess, &hmap_dup,
2842 0, FALSE, DUPLICATE_SAME_ACCESS);
2843 ok(!ret, "DuplicateHandle should fail\n");
2844 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2846 offset.u.LowPart = 0;
2847 offset.u.HighPart = 0;
2848 addr = NULL;
2849 size = 0;
2850 ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset,
2851 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
2852 ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#x\n", ret);
2854 SetLastError(0xdeadbeef);
2855 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2856 ok(!thread, "CreateRemoteThread should fail\n");
2857 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2859 SetLastError(0xdeadbeef);
2860 ret = DebugActiveProcess(pi.dwProcessId);
2861 ok(!ret, "DebugActiveProcess should fail\n");
2862 ok(GetLastError() == ERROR_ACCESS_DENIED /* 64-bit */ || GetLastError() == ERROR_NOT_SUPPORTED /* 32-bit */,
2863 "ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2865 GetExitCodeProcess(pi.hProcess, &ret);
2866 ok(ret == 198 || broken(ret != 198) /* some 32-bit XP version in a VM returns random exit code */,
2867 "expected exit code 198, got %u\n", ret);
2868 CloseHandle(pi.hThread);
2869 CloseHandle(pi.hProcess);
2871 ret = DeleteFileA(dll_name);
2872 ok(ret, "DeleteFile error %d\n", GetLastError());
2875 static PVOID WINAPI failuredllhook(ULONG ul, DELAYLOAD_INFO* pd)
2877 ok(ul == 4, "expected 4, got %u\n", ul);
2878 ok(!!pd, "no delayload info supplied\n");
2879 if (pd)
2881 ok(pd->Size == sizeof(*pd), "got %u\n", pd->Size);
2882 ok(!!pd->DelayloadDescriptor, "no DelayloadDescriptor supplied\n");
2883 if (pd->DelayloadDescriptor)
2885 ok(pd->DelayloadDescriptor->Attributes.AllAttributes == 1,
2886 "expected 1, got %u\n", pd->DelayloadDescriptor->Attributes.AllAttributes);
2887 ok(pd->DelayloadDescriptor->DllNameRVA == 0x2000,
2888 "expected 0x2000, got %x\n", pd->DelayloadDescriptor->DllNameRVA);
2889 ok(pd->DelayloadDescriptor->ModuleHandleRVA == 0x201a,
2890 "expected 0x201a, got %x\n", pd->DelayloadDescriptor->ModuleHandleRVA);
2891 ok(pd->DelayloadDescriptor->ImportAddressTableRVA > pd->DelayloadDescriptor->ModuleHandleRVA,
2892 "expected %x > %x\n", pd->DelayloadDescriptor->ImportAddressTableRVA,
2893 pd->DelayloadDescriptor->ModuleHandleRVA);
2894 ok(pd->DelayloadDescriptor->ImportNameTableRVA > pd->DelayloadDescriptor->ImportAddressTableRVA,
2895 "expected %x > %x\n", pd->DelayloadDescriptor->ImportNameTableRVA,
2896 pd->DelayloadDescriptor->ImportAddressTableRVA);
2897 ok(pd->DelayloadDescriptor->BoundImportAddressTableRVA == 0,
2898 "expected 0, got %x\n", pd->DelayloadDescriptor->BoundImportAddressTableRVA);
2899 ok(pd->DelayloadDescriptor->UnloadInformationTableRVA == 0,
2900 "expected 0, got %x\n", pd->DelayloadDescriptor->UnloadInformationTableRVA);
2901 ok(pd->DelayloadDescriptor->TimeDateStamp == 0,
2902 "expected 0, got %x\n", pd->DelayloadDescriptor->TimeDateStamp);
2905 ok(!!pd->ThunkAddress, "no ThunkAddress supplied\n");
2906 if (pd->ThunkAddress)
2907 ok(pd->ThunkAddress->u1.Ordinal, "no ThunkAddress value supplied\n");
2909 ok(!!pd->TargetDllName, "no TargetDllName supplied\n");
2910 if (pd->TargetDllName)
2911 ok(!strcmp(pd->TargetDllName, "secur32.dll"),
2912 "expected \"secur32.dll\", got \"%s\"\n", pd->TargetDllName);
2914 ok(pd->TargetApiDescriptor.ImportDescribedByName == 0,
2915 "expected 0, got %x\n", pd->TargetApiDescriptor.ImportDescribedByName);
2916 ok(pd->TargetApiDescriptor.Description.Ordinal == 0 ||
2917 pd->TargetApiDescriptor.Description.Ordinal == 999,
2918 "expected 0, got %x\n", pd->TargetApiDescriptor.Description.Ordinal);
2920 ok(!!pd->TargetModuleBase, "no TargetModuleBase supplied\n");
2921 ok(pd->Unused == NULL, "expected NULL, got %p\n", pd->Unused);
2922 ok(pd->LastError, "no LastError supplied\n");
2924 cb_count++;
2925 return (void*)0xdeadbeef;
2928 static void test_ResolveDelayLoadedAPI(void)
2930 static const char test_dll[] = "secur32.dll";
2931 static const char test_func[] = "SealMessage";
2932 char temp_path[MAX_PATH];
2933 char dll_name[MAX_PATH];
2934 IMAGE_DELAYLOAD_DESCRIPTOR idd, *delaydir;
2935 IMAGE_THUNK_DATA itd32;
2936 HANDLE hfile;
2937 HMODULE hlib;
2938 DWORD dummy, file_size, i;
2939 WORD hint = 0;
2940 BOOL ret;
2941 IMAGE_NT_HEADERS nt_header;
2943 static const struct test_data
2945 BOOL func;
2946 UINT_PTR ordinal;
2947 BOOL succeeds;
2948 } td[] =
2951 TRUE, 0, TRUE
2954 FALSE, IMAGE_ORDINAL_FLAG | 2, TRUE
2957 FALSE, IMAGE_ORDINAL_FLAG | 5, TRUE
2960 FALSE, IMAGE_ORDINAL_FLAG | 0, FALSE
2963 FALSE, IMAGE_ORDINAL_FLAG | 999, FALSE
2967 if (!pResolveDelayLoadedAPI)
2969 win_skip("ResolveDelayLoadedAPI is not available\n");
2970 return;
2973 if (0) /* crashes on native */
2975 SetLastError(0xdeadbeef);
2976 ok(!pResolveDelayLoadedAPI(NULL, NULL, NULL, NULL, NULL, 0),
2977 "ResolveDelayLoadedAPI succeeded\n");
2978 ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %x\n", GetLastError());
2980 cb_count = 0;
2981 SetLastError(0xdeadbeef);
2982 ok(!pResolveDelayLoadedAPI(NULL, NULL, failuredllhook, NULL, NULL, 0),
2983 "ResolveDelayLoadedAPI succeeded\n");
2984 ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %x\n", GetLastError());
2985 ok(cb_count == 1, "Wrong callback count: %d\n", cb_count);
2988 GetTempPathA(MAX_PATH, temp_path);
2989 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
2990 trace("creating %s\n", dll_name);
2991 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2992 if (hfile == INVALID_HANDLE_VALUE)
2994 ok(0, "could not create %s\n", dll_name);
2995 return;
2998 SetLastError(0xdeadbeef);
2999 ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
3000 ok(ret, "WriteFile error %d\n", GetLastError());
3002 nt_header = nt_header_template;
3003 nt_header.FileHeader.NumberOfSections = 2;
3004 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
3006 nt_header.OptionalHeader.SectionAlignment = 0x1000;
3007 nt_header.OptionalHeader.FileAlignment = 0x1000;
3008 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x2200;
3009 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + 2 * sizeof(IMAGE_SECTION_HEADER);
3010 nt_header.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
3011 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress = 0x1000;
3012 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size = 0x100;
3014 SetLastError(0xdeadbeef);
3015 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
3016 ok(ret, "WriteFile error %d\n", GetLastError());
3018 SetLastError(0xdeadbeef);
3019 ret = WriteFile(hfile, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
3020 ok(ret, "WriteFile error %d\n", GetLastError());
3022 /* sections */
3023 section.PointerToRawData = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
3024 section.VirtualAddress = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
3025 section.Misc.VirtualSize = 2 * sizeof(idd);
3026 section.SizeOfRawData = section.Misc.VirtualSize;
3027 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
3028 SetLastError(0xdeadbeef);
3029 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
3030 ok(ret, "WriteFile error %d\n", GetLastError());
3032 section.PointerToRawData = 0x2000;
3033 section.VirtualAddress = 0x2000;
3034 i = sizeof(td)/sizeof(td[0]);
3035 section.Misc.VirtualSize = sizeof(test_dll) + sizeof(hint) + sizeof(test_func) + sizeof(HMODULE) +
3036 2 * (i + 1) * sizeof(IMAGE_THUNK_DATA);
3037 ok(section.Misc.VirtualSize <= 0x1000, "Too much tests, add a new section!\n");
3038 section.SizeOfRawData = section.Misc.VirtualSize;
3039 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
3040 SetLastError(0xdeadbeef);
3041 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
3042 ok(ret, "WriteFile error %d\n", GetLastError());
3044 /* fill up to delay data */
3045 SetFilePointer( hfile, nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress, NULL, SEEK_SET );
3047 /* delay data */
3048 idd.Attributes.AllAttributes = 1;
3049 idd.DllNameRVA = 0x2000;
3050 idd.ModuleHandleRVA = idd.DllNameRVA + sizeof(test_dll) + sizeof(hint) + sizeof(test_func);
3051 idd.ImportAddressTableRVA = idd.ModuleHandleRVA + sizeof(HMODULE);
3052 idd.ImportNameTableRVA = idd.ImportAddressTableRVA + (i + 1) * sizeof(IMAGE_THUNK_DATA);
3053 idd.BoundImportAddressTableRVA = 0;
3054 idd.UnloadInformationTableRVA = 0;
3055 idd.TimeDateStamp = 0;
3057 SetLastError(0xdeadbeef);
3058 ret = WriteFile(hfile, &idd, sizeof(idd), &dummy, NULL);
3059 ok(ret, "WriteFile error %d\n", GetLastError());
3061 SetLastError(0xdeadbeef);
3062 ret = WriteFile(hfile, filler, sizeof(idd), &dummy, NULL);
3063 ok(ret, "WriteFile error %d\n", GetLastError());
3065 /* fill up to extended delay data */
3066 SetFilePointer( hfile, idd.DllNameRVA, NULL, SEEK_SET );
3068 /* extended delay data */
3069 SetLastError(0xdeadbeef);
3070 ret = WriteFile(hfile, test_dll, sizeof(test_dll), &dummy, NULL);
3071 ok(ret, "WriteFile error %d\n", GetLastError());
3073 SetLastError(0xdeadbeef);
3074 ret = WriteFile(hfile, &hint, sizeof(hint), &dummy, NULL);
3075 ok(ret, "WriteFile error %d\n", GetLastError());
3077 SetLastError(0xdeadbeef);
3078 ret = WriteFile(hfile, test_func, sizeof(test_func), &dummy, NULL);
3079 ok(ret, "WriteFile error %d\n", GetLastError());
3081 SetFilePointer( hfile, idd.ImportAddressTableRVA, NULL, SEEK_SET );
3083 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
3085 /* 0x1a00 is an empty space between delay data and extended delay data, real thunks are not necessary */
3086 itd32.u1.Function = nt_header.OptionalHeader.ImageBase + 0x1a00 + i * 0x20;
3087 SetLastError(0xdeadbeef);
3088 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
3089 ok(ret, "WriteFile error %d\n", GetLastError());
3092 itd32.u1.Function = 0;
3093 SetLastError(0xdeadbeef);
3094 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
3095 ok(ret, "WriteFile error %d\n", GetLastError());
3097 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
3099 if (td[i].func)
3100 itd32.u1.AddressOfData = idd.DllNameRVA + sizeof(test_dll);
3101 else
3102 itd32.u1.Ordinal = td[i].ordinal;
3103 SetLastError(0xdeadbeef);
3104 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
3105 ok(ret, "WriteFile error %d\n", GetLastError());
3108 itd32.u1.Ordinal = 0;
3109 SetLastError(0xdeadbeef);
3110 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
3111 ok(ret, "WriteFile error %d\n", GetLastError());
3113 /* fill up to eof */
3114 SetFilePointer( hfile, section.VirtualAddress + section.Misc.VirtualSize, NULL, SEEK_SET );
3115 SetEndOfFile( hfile );
3116 CloseHandle(hfile);
3118 SetLastError(0xdeadbeef);
3119 hlib = LoadLibraryA(dll_name);
3120 ok(hlib != NULL, "LoadLibrary error %u\n", GetLastError());
3121 if (!hlib)
3123 skip("couldn't load %s.\n", dll_name);
3124 DeleteFileA(dll_name);
3125 return;
3128 delaydir = pRtlImageDirectoryEntryToData(hlib, TRUE, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, &file_size);
3129 if (!delaydir)
3131 skip("haven't found section for delay import directory.\n");
3132 FreeLibrary(hlib);
3133 DeleteFileA(dll_name);
3134 return;
3137 for (;;)
3139 IMAGE_THUNK_DATA *itdn, *itda;
3140 HMODULE htarget;
3142 if (!delaydir->DllNameRVA ||
3143 !delaydir->ImportAddressTableRVA ||
3144 !delaydir->ImportNameTableRVA) break;
3146 itdn = RVAToAddr(delaydir->ImportNameTableRVA, hlib);
3147 itda = RVAToAddr(delaydir->ImportAddressTableRVA, hlib);
3148 htarget = LoadLibraryA(RVAToAddr(delaydir->DllNameRVA, hlib));
3150 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
3152 void *ret, *load;
3154 if (IMAGE_SNAP_BY_ORDINAL(itdn[i].u1.Ordinal))
3155 load = (void *)GetProcAddress(htarget, (LPSTR)IMAGE_ORDINAL(itdn[i].u1.Ordinal));
3156 else
3158 const IMAGE_IMPORT_BY_NAME* iibn = RVAToAddr(itdn[i].u1.AddressOfData, hlib);
3159 load = (void *)GetProcAddress(htarget, (char*)iibn->Name);
3162 cb_count = 0;
3163 ret = pResolveDelayLoadedAPI(hlib, delaydir, failuredllhook, NULL, &itda[i], 0);
3164 if (td[i].succeeds)
3166 ok(ret != NULL, "Test %u: ResolveDelayLoadedAPI failed\n", i);
3167 ok(ret == load, "Test %u: expected %p, got %p\n", i, load, ret);
3168 ok(ret == (void*)itda[i].u1.AddressOfData, "Test %u: expected %p, got %p\n",
3169 i, ret, (void*)itda[i].u1.AddressOfData);
3170 ok(!cb_count, "Test %u: Wrong callback count: %d\n", i, cb_count);
3172 else
3174 ok(ret == (void*)0xdeadbeef, "Test %u: ResolveDelayLoadedAPI succeeded with %p\n", i, ret);
3175 ok(cb_count, "Test %u: Wrong callback count: %d\n", i, cb_count);
3178 delaydir++;
3181 FreeLibrary(hlib);
3182 trace("deleting %s\n", dll_name);
3183 DeleteFileA(dll_name);
3186 static void test_InMemoryOrderModuleList(void)
3188 PEB_LDR_DATA *ldr = NtCurrentTeb()->Peb->LdrData;
3189 LIST_ENTRY *entry1, *mark1 = &ldr->InLoadOrderModuleList;
3190 LIST_ENTRY *entry2, *mark2 = &ldr->InMemoryOrderModuleList;
3191 LDR_MODULE *module1, *module2;
3193 ok(ldr->Initialized == TRUE, "expected TRUE, got %u\n", ldr->Initialized);
3195 for (entry1 = mark1->Flink, entry2 = mark2->Flink;
3196 entry1 != mark1 && entry2 != mark2;
3197 entry1 = entry1->Flink, entry2 = entry2->Flink)
3199 module1 = CONTAINING_RECORD(entry1, LDR_MODULE, InLoadOrderModuleList);
3200 module2 = CONTAINING_RECORD(entry2, LDR_MODULE, InMemoryOrderModuleList);
3201 ok(module1 == module2, "expected module1 == module2, got %p and %p\n", module1, module2);
3203 ok(entry1 == mark1, "expected entry1 == mark1, got %p and %p\n", entry1, mark1);
3204 ok(entry2 == mark2, "expected entry2 == mark2, got %p and %p\n", entry2, mark2);
3207 START_TEST(loader)
3209 int argc;
3210 char **argv;
3211 HANDLE ntdll, mapping, kernel32;
3212 SYSTEM_INFO si;
3214 ntdll = GetModuleHandleA("ntdll.dll");
3215 kernel32 = GetModuleHandleA("kernel32.dll");
3216 pNtCreateSection = (void *)GetProcAddress(ntdll, "NtCreateSection");
3217 pNtQuerySection = (void *)GetProcAddress(ntdll, "NtQuerySection");
3218 pNtMapViewOfSection = (void *)GetProcAddress(ntdll, "NtMapViewOfSection");
3219 pNtUnmapViewOfSection = (void *)GetProcAddress(ntdll, "NtUnmapViewOfSection");
3220 pNtTerminateProcess = (void *)GetProcAddress(ntdll, "NtTerminateProcess");
3221 pNtQueryInformationProcess = (void *)GetProcAddress(ntdll, "NtQueryInformationProcess");
3222 pNtSetInformationProcess = (void *)GetProcAddress(ntdll, "NtSetInformationProcess");
3223 pLdrShutdownProcess = (void *)GetProcAddress(ntdll, "LdrShutdownProcess");
3224 pRtlDllShutdownInProgress = (void *)GetProcAddress(ntdll, "RtlDllShutdownInProgress");
3225 pNtAllocateVirtualMemory = (void *)GetProcAddress(ntdll, "NtAllocateVirtualMemory");
3226 pNtFreeVirtualMemory = (void *)GetProcAddress(ntdll, "NtFreeVirtualMemory");
3227 pLdrLockLoaderLock = (void *)GetProcAddress(ntdll, "LdrLockLoaderLock");
3228 pLdrUnlockLoaderLock = (void *)GetProcAddress(ntdll, "LdrUnlockLoaderLock");
3229 pRtlAcquirePebLock = (void *)GetProcAddress(ntdll, "RtlAcquirePebLock");
3230 pRtlReleasePebLock = (void *)GetProcAddress(ntdll, "RtlReleasePebLock");
3231 pRtlImageDirectoryEntryToData = (void *)GetProcAddress(ntdll, "RtlImageDirectoryEntryToData");
3232 pFlsAlloc = (void *)GetProcAddress(kernel32, "FlsAlloc");
3233 pFlsSetValue = (void *)GetProcAddress(kernel32, "FlsSetValue");
3234 pFlsGetValue = (void *)GetProcAddress(kernel32, "FlsGetValue");
3235 pFlsFree = (void *)GetProcAddress(kernel32, "FlsFree");
3236 pIsWow64Process = (void *)GetProcAddress(kernel32, "IsWow64Process");
3237 pResolveDelayLoadedAPI = (void *)GetProcAddress(kernel32, "ResolveDelayLoadedAPI");
3239 GetSystemInfo( &si );
3240 page_size = si.dwPageSize;
3241 dos_header.e_magic = IMAGE_DOS_SIGNATURE;
3242 dos_header.e_lfanew = sizeof(dos_header);
3244 mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_loader");
3245 ok(mapping != 0, "CreateFileMapping failed\n");
3246 child_failures = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 4096);
3247 if (*child_failures == -1)
3249 *child_failures = 0;
3251 else
3252 *child_failures = -1;
3254 argc = winetest_get_mainargs(&argv);
3255 if (argc > 4)
3257 test_dll_phase = atoi(argv[4]);
3258 child_process(argv[2], atol(argv[3]));
3259 return;
3262 test_Loader();
3263 test_ResolveDelayLoadedAPI();
3264 test_ImportDescriptors();
3265 test_section_access();
3266 test_import_resolution();
3267 test_ExitProcess();
3268 test_InMemoryOrderModuleList();