kernel32/tests: Fix a dll reference leak.
[wine.git] / dlls / kernel32 / tests / loader.c
blob91a6ff051617ad0a3d9da5a5091dccaed4a73270
1 /*
2 * Unit test suite for the PE loader.
4 * Copyright 2006,2011 Dmitry Timoshkov
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define NONAMELESSUNION
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <assert.h>
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winternl.h"
31 #include "wine/test.h"
32 #include "delayloadhandler.h"
34 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
35 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
37 #define ALIGN_SIZE(size, alignment) (((size) + (alignment - 1)) & ~((alignment - 1)))
39 struct PROCESS_BASIC_INFORMATION_PRIVATE
41 DWORD_PTR ExitStatus;
42 PPEB PebBaseAddress;
43 DWORD_PTR AffinityMask;
44 DWORD_PTR BasePriority;
45 ULONG_PTR UniqueProcessId;
46 ULONG_PTR InheritedFromUniqueProcessId;
49 static LONG *child_failures;
50 static WORD cb_count;
51 static DWORD page_size;
53 static NTSTATUS (WINAPI *pNtCreateSection)(HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *,
54 const LARGE_INTEGER *, ULONG, ULONG, HANDLE );
55 static NTSTATUS (WINAPI *pNtQuerySection)(HANDLE, SECTION_INFORMATION_CLASS, void *, ULONG, ULONG *);
56 static NTSTATUS (WINAPI *pNtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG, SIZE_T, const LARGE_INTEGER *, SIZE_T *, ULONG, ULONG, ULONG);
57 static NTSTATUS (WINAPI *pNtUnmapViewOfSection)(HANDLE, PVOID);
58 static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
59 static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
60 static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE, DWORD);
61 static void (WINAPI *pLdrShutdownProcess)(void);
62 static BOOLEAN (WINAPI *pRtlDllShutdownInProgress)(void);
63 static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG, SIZE_T *, ULONG, ULONG);
64 static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG);
65 static NTSTATUS (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG *, ULONG_PTR *);
66 static NTSTATUS (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG_PTR);
67 static void (WINAPI *pRtlAcquirePebLock)(void);
68 static void (WINAPI *pRtlReleasePebLock)(void);
69 static PVOID (WINAPI *pResolveDelayLoadedAPI)(PVOID, PCIMAGE_DELAYLOAD_DESCRIPTOR,
70 PDELAYLOAD_FAILURE_DLL_CALLBACK, PVOID,
71 PIMAGE_THUNK_DATA ThunkAddress,ULONG);
72 static PVOID (WINAPI *pRtlImageDirectoryEntryToData)(HMODULE,BOOL,WORD,ULONG *);
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);
78 static PVOID RVAToAddr(DWORD_PTR rva, HMODULE module)
80 if (rva == 0)
81 return NULL;
82 return ((char*) module) + rva;
85 static IMAGE_DOS_HEADER dos_header;
87 static const IMAGE_NT_HEADERS nt_header_template =
89 IMAGE_NT_SIGNATURE, /* Signature */
91 #if defined __i386__
92 IMAGE_FILE_MACHINE_I386, /* Machine */
93 #elif defined __x86_64__
94 IMAGE_FILE_MACHINE_AMD64, /* Machine */
95 #elif defined __powerpc__
96 IMAGE_FILE_MACHINE_POWERPC, /* Machine */
97 #elif defined __arm__
98 IMAGE_FILE_MACHINE_ARMNT, /* Machine */
99 #elif defined __aarch64__
100 IMAGE_FILE_MACHINE_ARM64, /* Machine */
101 #else
102 # error You must specify the machine type
103 #endif
104 1, /* NumberOfSections */
105 0, /* TimeDateStamp */
106 0, /* PointerToSymbolTable */
107 0, /* NumberOfSymbols */
108 sizeof(IMAGE_OPTIONAL_HEADER), /* SizeOfOptionalHeader */
109 IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL /* Characteristics */
111 { IMAGE_NT_OPTIONAL_HDR_MAGIC, /* Magic */
112 1, /* MajorLinkerVersion */
113 0, /* MinorLinkerVersion */
114 0, /* SizeOfCode */
115 0, /* SizeOfInitializedData */
116 0, /* SizeOfUninitializedData */
117 0, /* AddressOfEntryPoint */
118 0x10, /* BaseOfCode, also serves as e_lfanew in the truncated MZ header */
119 #ifndef _WIN64
120 0, /* BaseOfData */
121 #endif
122 0x10000000, /* ImageBase */
123 0, /* SectionAlignment */
124 0, /* FileAlignment */
125 4, /* MajorOperatingSystemVersion */
126 0, /* MinorOperatingSystemVersion */
127 1, /* MajorImageVersion */
128 0, /* MinorImageVersion */
129 4, /* MajorSubsystemVersion */
130 0, /* MinorSubsystemVersion */
131 0, /* Win32VersionValue */
132 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000, /* SizeOfImage */
133 sizeof(dos_header) + sizeof(nt_header_template), /* SizeOfHeaders */
134 0, /* CheckSum */
135 IMAGE_SUBSYSTEM_WINDOWS_CUI, /* Subsystem */
136 0, /* DllCharacteristics */
137 0, /* SizeOfStackReserve */
138 0, /* SizeOfStackCommit */
139 0, /* SizeOfHeapReserve */
140 0, /* SizeOfHeapCommit */
141 0, /* LoaderFlags */
142 0, /* NumberOfRvaAndSizes */
143 { { 0 } } /* DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] */
147 static IMAGE_SECTION_HEADER section =
149 ".rodata", /* Name */
150 { 0 }, /* Misc */
151 0, /* VirtualAddress */
152 0, /* SizeOfRawData */
153 0, /* PointerToRawData */
154 0, /* PointerToRelocations */
155 0, /* PointerToLinenumbers */
156 0, /* NumberOfRelocations */
157 0, /* NumberOfLinenumbers */
158 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, /* Characteristics */
162 static const char filler[0x1000];
163 static const char section_data[0x10] = "section data";
165 static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size,
166 const IMAGE_NT_HEADERS *nt_header, const char *dll_name )
168 DWORD dummy, size, file_align;
169 HANDLE hfile;
170 BOOL ret;
172 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
173 if (hfile == INVALID_HANDLE_VALUE) return 0;
175 SetLastError(0xdeadbeef);
176 ret = WriteFile(hfile, dos_header, dos_size, &dummy, NULL);
177 ok(ret, "WriteFile error %d\n", GetLastError());
179 SetLastError(0xdeadbeef);
180 ret = WriteFile(hfile, nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
181 ok(ret, "WriteFile error %d\n", GetLastError());
183 if (nt_header->FileHeader.SizeOfOptionalHeader)
185 SetLastError(0xdeadbeef);
186 ret = WriteFile(hfile, &nt_header->OptionalHeader,
187 min(nt_header->FileHeader.SizeOfOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER)),
188 &dummy, NULL);
189 ok(ret, "WriteFile error %d\n", GetLastError());
190 if (nt_header->FileHeader.SizeOfOptionalHeader > sizeof(IMAGE_OPTIONAL_HEADER))
192 file_align = nt_header->FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER);
193 assert(file_align < sizeof(filler));
194 SetLastError(0xdeadbeef);
195 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
196 ok(ret, "WriteFile error %d\n", GetLastError());
200 assert(nt_header->FileHeader.NumberOfSections <= 1);
201 if (nt_header->FileHeader.NumberOfSections)
203 section.SizeOfRawData = 10;
205 if (nt_header->OptionalHeader.SectionAlignment >= page_size)
207 section.PointerToRawData = dos_size;
208 section.VirtualAddress = nt_header->OptionalHeader.SectionAlignment;
209 section.Misc.VirtualSize = section.SizeOfRawData * 10;
211 else
213 section.PointerToRawData = nt_header->OptionalHeader.SizeOfHeaders;
214 section.VirtualAddress = nt_header->OptionalHeader.SizeOfHeaders;
215 section.Misc.VirtualSize = 5;
218 SetLastError(0xdeadbeef);
219 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
220 ok(ret, "WriteFile error %d\n", GetLastError());
222 /* section data */
223 SetLastError(0xdeadbeef);
224 ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
225 ok(ret, "WriteFile error %d\n", GetLastError());
227 size = GetFileSize(hfile, NULL);
228 CloseHandle(hfile);
229 return size;
232 static void query_image_section( int id, const char *dll_name, const IMAGE_NT_HEADERS *nt_header )
234 SECTION_BASIC_INFORMATION info;
235 SECTION_IMAGE_INFORMATION image;
236 ULONG info_size = 0xdeadbeef;
237 NTSTATUS status;
238 HANDLE file, mapping;
239 ULONG file_size;
240 LARGE_INTEGER map_size;
241 /* truncated header is not handled correctly in windows <= w2k3 */
242 BOOL truncated = nt_header->FileHeader.SizeOfOptionalHeader < sizeof(nt_header->OptionalHeader);
244 file = CreateFileA( dll_name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE,
245 NULL, OPEN_EXISTING, 0, 0 );
246 ok( file != INVALID_HANDLE_VALUE, "%u: CreateFile error %d\n", id, GetLastError() );
247 file_size = GetFileSize( file, NULL );
249 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
250 NULL, NULL, PAGE_READONLY, SEC_IMAGE, file );
251 ok( !status, "%u: NtCreateSection failed err %x\n", id, status );
252 if (status)
254 CloseHandle( file );
255 return;
257 status = pNtQuerySection( mapping, SectionImageInformation, &image, sizeof(image), &info_size );
258 ok( !status, "%u: NtQuerySection failed err %x\n", id, status );
259 ok( info_size == sizeof(image), "%u: NtQuerySection wrong size %u\n", id, info_size );
260 ok( (char *)image.TransferAddress == (char *)nt_header->OptionalHeader.ImageBase + nt_header->OptionalHeader.AddressOfEntryPoint,
261 "%u: TransferAddress wrong %p / %p+%08x\n", id,
262 image.TransferAddress, (char *)nt_header->OptionalHeader.ImageBase,
263 nt_header->OptionalHeader.AddressOfEntryPoint );
264 ok( image.ZeroBits == 0, "%u: ZeroBits wrong %08x\n", id, image.ZeroBits );
265 ok( image.MaximumStackSize == nt_header->OptionalHeader.SizeOfStackReserve || broken(truncated),
266 "%u: MaximumStackSize wrong %lx / %lx\n", id,
267 image.MaximumStackSize, (SIZE_T)nt_header->OptionalHeader.SizeOfStackReserve );
268 ok( image.CommittedStackSize == nt_header->OptionalHeader.SizeOfStackCommit || broken(truncated),
269 "%u: CommittedStackSize wrong %lx / %lx\n", id,
270 image.CommittedStackSize, (SIZE_T)nt_header->OptionalHeader.SizeOfStackCommit );
271 if (truncated)
272 ok( !image.SubSystemType || broken(truncated),
273 "%u: SubSystemType wrong %08x / 00000000\n", id, image.SubSystemType );
274 else
275 ok( image.SubSystemType == nt_header->OptionalHeader.Subsystem,
276 "%u: SubSystemType wrong %08x / %08x\n", id,
277 image.SubSystemType, nt_header->OptionalHeader.Subsystem );
278 ok( image.SubsystemVersionLow == nt_header->OptionalHeader.MinorSubsystemVersion,
279 "%u: SubsystemVersionLow wrong %04x / %04x\n", id,
280 image.SubsystemVersionLow, nt_header->OptionalHeader.MinorSubsystemVersion );
281 ok( image.SubsystemVersionHigh == nt_header->OptionalHeader.MajorSubsystemVersion,
282 "%u: SubsystemVersionHigh wrong %04x / %04x\n", id,
283 image.SubsystemVersionHigh, nt_header->OptionalHeader.MajorSubsystemVersion );
284 ok( image.ImageCharacteristics == nt_header->FileHeader.Characteristics,
285 "%u: ImageCharacteristics wrong %04x / %04x\n", id,
286 image.ImageCharacteristics, nt_header->FileHeader.Characteristics );
287 ok( image.DllCharacteristics == nt_header->OptionalHeader.DllCharacteristics || broken(truncated),
288 "%u: DllCharacteristics wrong %04x / %04x\n", id,
289 image.DllCharacteristics, nt_header->OptionalHeader.DllCharacteristics );
290 ok( image.Machine == nt_header->FileHeader.Machine, "%u: Machine wrong %04x / %04x\n", id,
291 image.Machine, nt_header->FileHeader.Machine );
292 ok( image.LoaderFlags == nt_header->OptionalHeader.LoaderFlags,
293 "%u: LoaderFlags wrong %08x / %08x\n", id,
294 image.LoaderFlags, nt_header->OptionalHeader.LoaderFlags );
295 ok( image.ImageFileSize == file_size || broken(!image.ImageFileSize), /* winxpsp1 */
296 "%u: ImageFileSize wrong %08x / %08x\n", id, image.ImageFileSize, file_size );
297 ok( image.CheckSum == nt_header->OptionalHeader.CheckSum, "%u: CheckSum wrong %08x / %08x\n", id,
298 image.CheckSum, nt_header->OptionalHeader.CheckSum );
299 /* FIXME: needs more work: */
300 /* image.GpValue */
301 /* image.ImageFlags */
302 /* image.ImageContainsCode */
304 map_size.QuadPart = (nt_header->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
305 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
306 ok( !status, "NtQuerySection failed err %x\n", status );
307 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %x%08x / %x%08x\n",
308 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
309 CloseHandle( mapping );
311 map_size.QuadPart = (nt_header->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
312 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
313 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
314 ok( !status, "%u: NtCreateSection failed err %x\n", id, status );
315 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
316 ok( !status, "NtQuerySection failed err %x\n", status );
317 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %x%08x / %x%08x\n",
318 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
319 CloseHandle( mapping );
321 map_size.QuadPart++;
322 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
323 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
324 ok( status == STATUS_SECTION_TOO_BIG, "%u: NtCreateSection failed err %x\n", id, status );
326 SetFilePointerEx( file, map_size, NULL, FILE_BEGIN );
327 SetEndOfFile( file );
328 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
329 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
330 ok( status == STATUS_SECTION_TOO_BIG, "%u: NtCreateSection failed err %x\n", id, status );
332 map_size.QuadPart = 1;
333 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
334 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
335 ok( !status, "%u: NtCreateSection failed err %x\n", id, status );
336 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
337 ok( !status, "NtQuerySection failed err %x\n", status );
338 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %x%08x / %x%08x\n",
339 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
340 CloseHandle( mapping );
342 CloseHandle( file );
345 /* helper to test image section mapping */
346 static NTSTATUS map_image_section( const IMAGE_NT_HEADERS *nt_header )
348 char temp_path[MAX_PATH];
349 char dll_name[MAX_PATH];
350 LARGE_INTEGER size;
351 HANDLE file, map;
352 NTSTATUS status;
353 ULONG file_size;
355 GetTempPathA(MAX_PATH, temp_path);
356 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
358 file_size = create_test_dll( &dos_header, sizeof(dos_header), nt_header, dll_name );
359 ok( file_size, "could not create %s\n", dll_name);
361 file = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
362 ok(file != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError());
364 size.QuadPart = file_size;
365 status = pNtCreateSection(&map, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
366 NULL, &size, PAGE_READONLY, SEC_IMAGE, file );
367 if (!status)
369 SECTION_BASIC_INFORMATION info;
370 ULONG info_size = 0xdeadbeef;
371 NTSTATUS ret = pNtQuerySection( map, SectionBasicInformation, &info, sizeof(info), &info_size );
372 ok( !ret, "NtQuerySection failed err %x\n", ret );
373 ok( info_size == sizeof(info), "NtQuerySection wrong size %u\n", info_size );
374 ok( info.Attributes == (SEC_IMAGE | SEC_FILE), "NtQuerySection wrong attr %x\n", info.Attributes );
375 ok( info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", info.BaseAddress );
376 ok( info.Size.QuadPart == file_size, "NtQuerySection wrong size %x%08x / %08x\n",
377 info.Size.u.HighPart, info.Size.u.LowPart, file_size );
378 query_image_section( 1000, dll_name, nt_header );
380 if (map) CloseHandle( map );
381 CloseHandle( file );
382 DeleteFileA( dll_name );
383 return status;
387 static void test_Loader(void)
389 static const struct test_data
391 DWORD size_of_dos_header;
392 WORD number_of_sections, size_of_optional_header;
393 DWORD section_alignment, file_alignment;
394 DWORD size_of_image, size_of_headers;
395 DWORD errors[4]; /* 0 means LoadLibrary should succeed */
396 } td[] =
398 { sizeof(dos_header),
399 1, 0, 0, 0, 0, 0,
400 { ERROR_BAD_EXE_FORMAT }
402 { sizeof(dos_header),
403 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
404 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0xe00,
405 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
406 { ERROR_BAD_EXE_FORMAT } /* XP doesn't like too small image size */
408 { sizeof(dos_header),
409 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
410 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
411 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
412 { ERROR_SUCCESS }
414 { sizeof(dos_header),
415 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
416 0x1f00,
417 0x1000,
418 { ERROR_SUCCESS }
420 { sizeof(dos_header),
421 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x200,
422 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x200,
423 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
424 { ERROR_SUCCESS, ERROR_INVALID_ADDRESS } /* vista is more strict */
426 { sizeof(dos_header),
427 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x1000,
428 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
429 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
430 { ERROR_BAD_EXE_FORMAT } /* XP doesn't like alignments */
432 { sizeof(dos_header),
433 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
434 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
435 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
436 { ERROR_SUCCESS }
438 { sizeof(dos_header),
439 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
440 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
441 0x200,
442 { ERROR_SUCCESS }
444 /* Mandatory are all fields up to SizeOfHeaders, everything else
445 * is really optional (at least that's true for XP).
447 { sizeof(dos_header),
448 1, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
449 sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER) + 0x10,
450 sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER),
451 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT, ERROR_INVALID_ADDRESS,
452 ERROR_NOACCESS }
454 { sizeof(dos_header),
455 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
456 0xd0, /* beyond of the end of file */
457 0xc0, /* beyond of the end of file */
458 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
460 { sizeof(dos_header),
461 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
462 0x1000,
464 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
466 { sizeof(dos_header),
467 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
470 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
472 #if 0 /* not power of 2 alignments need more test cases */
473 { sizeof(dos_header),
474 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x300, 0x300,
477 { ERROR_BAD_EXE_FORMAT } /* alignment is not power of 2 */
479 #endif
480 { sizeof(dos_header),
481 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 4, 4,
484 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
486 { sizeof(dos_header),
487 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 1, 1,
490 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
492 { sizeof(dos_header),
493 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
496 { ERROR_BAD_EXE_FORMAT } /* image size == 0 -> failure */
498 /* the following data mimics the PE image which upack creates */
499 { 0x10,
500 1, 0x148, 0x1000, 0x200,
501 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
502 0x200,
503 { ERROR_SUCCESS }
505 /* Minimal PE image that XP is able to load: 92 bytes */
506 { 0x04,
507 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum),
508 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
511 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
513 /* Minimal PE image that Windows7 is able to load: 268 bytes */
514 { 0x04,
515 0, 0xf0, /* optional header size just forces 0xf0 bytes to be written,
516 0 or another number don't change the behaviour, what really
517 matters is file size regardless of values in the headers */
518 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
519 0x40, /* minimal image size that Windows7 accepts */
521 { ERROR_SUCCESS }
524 int i;
525 DWORD file_size;
526 HANDLE h;
527 HMODULE hlib, hlib_as_data_file;
528 char temp_path[MAX_PATH];
529 char dll_name[MAX_PATH];
530 SIZE_T size;
531 BOOL ret;
532 NTSTATUS status;
533 WORD orig_machine = nt_header_template.FileHeader.Machine;
534 IMAGE_NT_HEADERS nt_header;
536 /* prevent displaying of the "Unable to load this DLL" message box */
537 SetErrorMode(SEM_FAILCRITICALERRORS);
539 GetTempPathA(MAX_PATH, temp_path);
541 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
543 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
545 nt_header = nt_header_template;
546 nt_header.FileHeader.NumberOfSections = td[i].number_of_sections;
547 nt_header.FileHeader.SizeOfOptionalHeader = td[i].size_of_optional_header;
549 nt_header.OptionalHeader.SectionAlignment = td[i].section_alignment;
550 nt_header.OptionalHeader.FileAlignment = td[i].file_alignment;
551 nt_header.OptionalHeader.SizeOfImage = td[i].size_of_image;
552 nt_header.OptionalHeader.SizeOfHeaders = td[i].size_of_headers;
554 file_size = create_test_dll( &dos_header, td[i].size_of_dos_header, &nt_header, dll_name );
555 if (!file_size)
557 ok(0, "could not create %s\n", dll_name);
558 break;
561 SetLastError(0xdeadbeef);
562 hlib = LoadLibraryA(dll_name);
563 if (hlib)
565 MEMORY_BASIC_INFORMATION info;
566 void *ptr;
568 ok( td[i].errors[0] == ERROR_SUCCESS, "%d: should have failed\n", i );
570 SetLastError(0xdeadbeef);
571 size = VirtualQuery(hlib, &info, sizeof(info));
572 ok(size == sizeof(info),
573 "%d: VirtualQuery error %d\n", i, GetLastError());
574 ok(info.BaseAddress == hlib, "%d: %p != %p\n", i, info.BaseAddress, hlib);
575 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
576 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
577 ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %lx != expected %x\n",
578 i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
579 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
580 if (nt_header.OptionalHeader.SectionAlignment < page_size)
581 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
582 else
583 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
584 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
586 SetLastError(0xdeadbeef);
587 ptr = VirtualAlloc(hlib, page_size, MEM_COMMIT, info.Protect);
588 ok(!ptr, "%d: VirtualAlloc should fail\n", i);
589 /* FIXME: Remove once Wine is fixed */
590 todo_wine_if (info.Protect == PAGE_WRITECOPY || info.Protect == PAGE_EXECUTE_WRITECOPY)
591 ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError());
593 SetLastError(0xdeadbeef);
594 size = VirtualQuery((char *)hlib + info.RegionSize, &info, sizeof(info));
595 ok(size == sizeof(info),
596 "%d: VirtualQuery error %d\n", i, GetLastError());
597 if (nt_header.OptionalHeader.SectionAlignment == page_size ||
598 nt_header.OptionalHeader.SectionAlignment == nt_header.OptionalHeader.FileAlignment)
600 ok(info.BaseAddress == (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %p != expected %p\n",
601 i, info.BaseAddress, (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
602 ok(info.AllocationBase == 0, "%d: %p != 0\n", i, info.AllocationBase);
603 ok(info.AllocationProtect == 0, "%d: %x != 0\n", i, info.AllocationProtect);
604 /*ok(info.RegionSize == not_practical_value, "%d: %lx != not_practical_value\n", i, info.RegionSize);*/
605 ok(info.State == MEM_FREE, "%d: %x != MEM_FREE\n", i, info.State);
606 ok(info.Type == 0, "%d: %x != 0\n", i, info.Type);
607 ok(info.Protect == PAGE_NOACCESS, "%d: %x != PAGE_NOACCESS\n", i, info.Protect);
609 else
611 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
612 ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib);
613 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
614 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
615 ok(info.RegionSize == ALIGN_SIZE(file_size, page_size), "%d: got %lx != expected %x\n",
616 i, info.RegionSize, ALIGN_SIZE(file_size, page_size));
617 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
618 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
619 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
622 /* header: check the zeroing of alignment */
623 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
625 const char *start;
627 start = (const char *)hlib + nt_header.OptionalHeader.SizeOfHeaders;
628 size = ALIGN_SIZE((ULONG_PTR)start, page_size) - (ULONG_PTR)start;
629 ok(!memcmp(start, filler, size), "%d: header alignment is not cleared\n", i);
632 if (nt_header.FileHeader.NumberOfSections)
634 SetLastError(0xdeadbeef);
635 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
636 ok(size == sizeof(info),
637 "%d: VirtualQuery error %d\n", i, GetLastError());
638 if (nt_header.OptionalHeader.SectionAlignment < page_size)
640 ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib);
641 ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %lx != expected %x\n",
642 i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
643 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
645 else
647 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
648 ok(info.RegionSize == ALIGN_SIZE(section.Misc.VirtualSize, page_size), "%d: got %lx != expected %x\n",
649 i, info.RegionSize, ALIGN_SIZE(section.Misc.VirtualSize, page_size));
650 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
652 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
653 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
654 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
655 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
657 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
658 ok(!memcmp((const char *)hlib + section.VirtualAddress + section.PointerToRawData, &nt_header, section.SizeOfRawData), "wrong section data\n");
659 else
660 ok(!memcmp((const char *)hlib + section.PointerToRawData, section_data, section.SizeOfRawData), "wrong section data\n");
662 /* check the zeroing of alignment */
663 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
665 const char *start;
667 start = (const char *)hlib + section.VirtualAddress + section.PointerToRawData + section.SizeOfRawData;
668 size = ALIGN_SIZE((ULONG_PTR)start, page_size) - (ULONG_PTR)start;
669 ok(memcmp(start, filler, size), "%d: alignment should not be cleared\n", i);
672 SetLastError(0xdeadbeef);
673 ptr = VirtualAlloc((char *)hlib + section.VirtualAddress, page_size, MEM_COMMIT, info.Protect);
674 ok(!ptr, "%d: VirtualAlloc should fail\n", i);
675 /* FIXME: Remove once Wine is fixed */
676 todo_wine_if (info.Protect == PAGE_WRITECOPY || info.Protect == PAGE_EXECUTE_WRITECOPY)
677 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_INVALID_ADDRESS,
678 "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError());
681 SetLastError(0xdeadbeef);
682 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
683 ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
684 ok(hlib_as_data_file == hlib, "hlib_as_file and hlib are different\n");
686 SetLastError(0xdeadbeef);
687 ret = FreeLibrary(hlib);
688 ok(ret, "FreeLibrary error %d\n", GetLastError());
690 SetLastError(0xdeadbeef);
691 hlib = GetModuleHandleA(dll_name);
692 ok(hlib != 0, "GetModuleHandle error %u\n", GetLastError());
694 SetLastError(0xdeadbeef);
695 ret = FreeLibrary(hlib_as_data_file);
696 ok(ret, "FreeLibrary error %d\n", GetLastError());
698 hlib = GetModuleHandleA(dll_name);
699 ok(!hlib, "GetModuleHandle should fail\n");
701 SetLastError(0xdeadbeef);
702 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
703 ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
704 ok((ULONG_PTR)hlib_as_data_file & 1, "hlib_as_data_file is even\n");
706 hlib = GetModuleHandleA(dll_name);
707 ok(!hlib, "GetModuleHandle should fail\n");
709 SetLastError(0xdeadbeef);
710 h = CreateFileA( dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
711 ok( h != INVALID_HANDLE_VALUE, "open failed err %u\n", GetLastError() );
712 CloseHandle( h );
714 SetLastError(0xdeadbeef);
715 ret = FreeLibrary(hlib_as_data_file);
716 ok(ret, "FreeLibrary error %d\n", GetLastError());
718 SetLastError(0xdeadbeef);
719 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE);
720 if (!((ULONG_PTR)hlib_as_data_file & 1) || /* winxp */
721 (!hlib_as_data_file && GetLastError() == ERROR_INVALID_PARAMETER)) /* w2k3 */
723 win_skip( "LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE not supported\n" );
724 FreeLibrary(hlib_as_data_file);
726 else
728 ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
730 SetLastError(0xdeadbeef);
731 h = CreateFileA( dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
732 todo_wine ok( h == INVALID_HANDLE_VALUE, "open succeeded\n" );
733 todo_wine ok( GetLastError() == ERROR_SHARING_VIOLATION, "wrong error %u\n", GetLastError() );
734 CloseHandle( h );
736 SetLastError(0xdeadbeef);
737 ret = FreeLibrary(hlib_as_data_file);
738 ok(ret, "FreeLibrary error %d\n", GetLastError());
741 query_image_section( i, dll_name, &nt_header );
743 else
745 BOOL error_match;
746 int error_index;
748 error_match = FALSE;
749 for (error_index = 0;
750 ! error_match && error_index < sizeof(td[i].errors) / sizeof(DWORD);
751 error_index++)
753 error_match = td[i].errors[error_index] == GetLastError();
755 ok(error_match, "%d: unexpected error %d\n", i, GetLastError());
758 SetLastError(0xdeadbeef);
759 ret = DeleteFileA(dll_name);
760 ok(ret, "DeleteFile error %d\n", GetLastError());
763 nt_header = nt_header_template;
764 nt_header.FileHeader.NumberOfSections = 1;
765 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
767 nt_header.OptionalHeader.SectionAlignment = page_size;
768 nt_header.OptionalHeader.AddressOfEntryPoint = 0x1234;
769 nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
770 nt_header.OptionalHeader.FileAlignment = page_size;
771 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
772 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
774 status = map_image_section( &nt_header );
775 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
777 dos_header.e_magic = 0;
778 status = map_image_section( &nt_header );
779 ok( status == STATUS_INVALID_IMAGE_NOT_MZ, "NtCreateSection error %08x\n", status );
781 dos_header.e_magic = IMAGE_DOS_SIGNATURE;
782 nt_header.Signature = IMAGE_OS2_SIGNATURE;
783 status = map_image_section( &nt_header );
784 ok( status == STATUS_INVALID_IMAGE_NE_FORMAT, "NtCreateSection error %08x\n", status );
786 nt_header.Signature = 0xdeadbeef;
787 status = map_image_section( &nt_header );
788 ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection error %08x\n", status );
790 nt_header.Signature = IMAGE_NT_SIGNATURE;
791 nt_header.OptionalHeader.Magic = 0xdead;
792 status = map_image_section( &nt_header );
793 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08x\n", status );
795 nt_header.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC;
796 nt_header.FileHeader.Machine = 0xdead;
797 status = map_image_section( &nt_header );
798 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
799 "NtCreateSection error %08x\n", status );
801 nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_UNKNOWN;
802 status = map_image_section( &nt_header );
803 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
804 "NtCreateSection error %08x\n", status );
806 switch (orig_machine)
808 case IMAGE_FILE_MACHINE_I386: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64; break;
809 case IMAGE_FILE_MACHINE_AMD64: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_I386; break;
810 case IMAGE_FILE_MACHINE_ARMNT: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_ARM64; break;
811 case IMAGE_FILE_MACHINE_ARM64: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_ARMNT; break;
813 status = map_image_section( &nt_header );
814 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
815 "NtCreateSection error %08x\n", status );
817 if (nt_header.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
819 IMAGE_NT_HEADERS64 nt64;
821 memset( &nt64, 0, sizeof(nt64) );
822 nt64.Signature = IMAGE_NT_SIGNATURE;
823 nt64.FileHeader.Machine = orig_machine;
824 nt64.FileHeader.NumberOfSections = 1;
825 nt64.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
826 nt64.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
827 nt64.OptionalHeader.MajorLinkerVersion = 1;
828 nt64.OptionalHeader.ImageBase = 0x10000000;
829 nt64.OptionalHeader.MajorOperatingSystemVersion = 4;
830 nt64.OptionalHeader.MajorImageVersion = 1;
831 nt64.OptionalHeader.MajorSubsystemVersion = 4;
832 nt64.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt64) + sizeof(IMAGE_SECTION_HEADER);
833 nt64.OptionalHeader.SizeOfImage = nt64.OptionalHeader.SizeOfHeaders + 0x1000;
834 nt64.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
835 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64 );
836 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08x\n", status );
838 else
840 IMAGE_NT_HEADERS32 nt32;
842 memset( &nt32, 0, sizeof(nt32) );
843 nt32.Signature = IMAGE_NT_SIGNATURE;
844 nt32.FileHeader.Machine = orig_machine;
845 nt32.FileHeader.NumberOfSections = 1;
846 nt32.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32);
847 nt32.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
848 nt32.OptionalHeader.MajorLinkerVersion = 1;
849 nt32.OptionalHeader.ImageBase = 0x10000000;
850 nt32.OptionalHeader.MajorOperatingSystemVersion = 4;
851 nt32.OptionalHeader.MajorImageVersion = 1;
852 nt32.OptionalHeader.MajorSubsystemVersion = 4;
853 nt32.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt32) + sizeof(IMAGE_SECTION_HEADER);
854 nt32.OptionalHeader.SizeOfImage = nt32.OptionalHeader.SizeOfHeaders + 0x1000;
855 nt32.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
856 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32 );
857 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08x\n", status );
860 nt_header.FileHeader.Machine = orig_machine; /* restore it for the next tests */
863 /* Verify linking style of import descriptors */
864 static void test_ImportDescriptors(void)
866 HMODULE kernel32_module = NULL;
867 PIMAGE_DOS_HEADER d_header;
868 PIMAGE_NT_HEADERS nt_headers;
869 DWORD import_dir_size;
870 DWORD_PTR dir_offset;
871 PIMAGE_IMPORT_DESCRIPTOR import_chunk;
873 /* Load kernel32 module */
874 kernel32_module = GetModuleHandleA("kernel32.dll");
875 assert( kernel32_module != NULL );
877 /* Get PE header info from module image */
878 d_header = (PIMAGE_DOS_HEADER) kernel32_module;
879 nt_headers = (PIMAGE_NT_HEADERS) (((char*) d_header) +
880 d_header->e_lfanew);
882 /* Get size of import entry directory */
883 import_dir_size = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
884 if (!import_dir_size)
886 skip("Unable to continue testing due to missing import directory.\n");
887 return;
890 /* Get address of first import chunk */
891 dir_offset = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
892 import_chunk = RVAToAddr(dir_offset, kernel32_module);
893 ok(import_chunk != 0, "Invalid import_chunk: %p\n", import_chunk);
894 if (!import_chunk) return;
896 /* Iterate through import descriptors and verify set name,
897 * OriginalFirstThunk, and FirstThunk. Core Windows DLLs, such as
898 * kernel32.dll, don't use Borland-style linking, where the table of
899 * imported names is stored directly in FirstThunk and overwritten
900 * by the relocation, instead of being stored in OriginalFirstThunk.
901 * */
902 for (; import_chunk->FirstThunk; import_chunk++)
904 LPCSTR module_name = RVAToAddr(import_chunk->Name, kernel32_module);
905 PIMAGE_THUNK_DATA name_table = RVAToAddr(
906 U(*import_chunk).OriginalFirstThunk, kernel32_module);
907 PIMAGE_THUNK_DATA iat = RVAToAddr(
908 import_chunk->FirstThunk, kernel32_module);
909 ok(module_name != NULL, "Imported module name should not be NULL\n");
910 ok(name_table != NULL,
911 "Name table for imported module %s should not be NULL\n",
912 module_name);
913 ok(iat != NULL, "IAT for imported module %s should not be NULL\n",
914 module_name);
918 static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL is_dll)
920 HANDLE hfile, hmap;
921 NTSTATUS status;
922 LARGE_INTEGER offset;
923 SIZE_T size;
924 void *addr1, *addr2;
925 MEMORY_BASIC_INFORMATION info;
927 if (!pNtMapViewOfSection) return;
929 SetLastError(0xdeadbeef);
930 hfile = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
931 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError());
933 SetLastError(0xdeadbeef);
934 hmap = CreateFileMappingW(hfile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, 0);
935 ok(hmap != 0, "CreateFileMapping error %d\n", GetLastError());
937 offset.u.LowPart = 0;
938 offset.u.HighPart = 0;
940 addr1 = NULL;
941 size = 0;
942 status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr1, 0, 0, &offset,
943 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
944 ok(status == STATUS_SUCCESS, "NtMapViewOfSection error %x\n", status);
945 ok(addr1 != 0, "mapped address should be valid\n");
947 SetLastError(0xdeadbeef);
948 size = VirtualQuery((char *)addr1 + section.VirtualAddress, &info, sizeof(info));
949 ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
950 ok(info.BaseAddress == (char *)addr1 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr1 + section.VirtualAddress);
951 ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size);
952 ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
953 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
954 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
955 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
956 ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
958 addr2 = NULL;
959 size = 0;
960 status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr2, 0, 0, &offset,
961 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
962 ok(status == STATUS_IMAGE_NOT_AT_BASE, "expected STATUS_IMAGE_NOT_AT_BASE, got %x\n", status);
963 ok(addr2 != 0, "mapped address should be valid\n");
964 ok(addr2 != addr1, "mapped addresses should be different\n");
966 SetLastError(0xdeadbeef);
967 size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info));
968 ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
969 ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress);
970 ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size);
971 ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
972 ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2);
973 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
974 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
975 ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
977 status = pNtUnmapViewOfSection(GetCurrentProcess(), addr2);
978 ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status);
980 addr2 = MapViewOfFile(hmap, 0, 0, 0, 0);
981 ok(addr2 != 0, "mapped address should be valid\n");
982 ok(addr2 != addr1, "mapped addresses should be different\n");
984 SetLastError(0xdeadbeef);
985 size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info));
986 ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
987 ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress);
988 ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size);
989 ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
990 ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2);
991 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
992 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
993 ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
995 UnmapViewOfFile(addr2);
997 SetLastError(0xdeadbeef);
998 addr2 = LoadLibraryA(dll_name);
999 if (is_dll)
1001 ok(!addr2, "LoadLibrary should fail, is_dll %d\n", is_dll);
1002 ok(GetLastError() == ERROR_INVALID_ADDRESS, "expected ERROR_INVALID_ADDRESS, got %d\n", GetLastError());
1004 else
1006 BOOL ret;
1007 ok(addr2 != 0, "LoadLibrary error %d, is_dll %d\n", GetLastError(), is_dll);
1008 ok(addr2 != addr1, "mapped addresses should be different\n");
1010 SetLastError(0xdeadbeef);
1011 ret = FreeLibrary(addr2);
1012 ok(ret, "FreeLibrary error %d\n", GetLastError());
1015 status = pNtUnmapViewOfSection(GetCurrentProcess(), addr1);
1016 ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status);
1018 CloseHandle(hmap);
1019 CloseHandle(hfile);
1022 static BOOL is_mem_writable(DWORD prot)
1024 switch (prot & 0xff)
1026 case PAGE_READWRITE:
1027 case PAGE_WRITECOPY:
1028 case PAGE_EXECUTE_READWRITE:
1029 case PAGE_EXECUTE_WRITECOPY:
1030 return TRUE;
1032 default:
1033 return FALSE;
1037 static void test_VirtualProtect(void *base, void *section)
1039 static const struct test_data
1041 DWORD prot_set, prot_get;
1042 } td[] =
1044 { 0, 0 }, /* 0x00 */
1045 { PAGE_NOACCESS, PAGE_NOACCESS }, /* 0x01 */
1046 { PAGE_READONLY, PAGE_READONLY }, /* 0x02 */
1047 { PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x03 */
1048 { PAGE_READWRITE, PAGE_WRITECOPY }, /* 0x04 */
1049 { PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x05 */
1050 { PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x06 */
1051 { PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x07 */
1052 { PAGE_WRITECOPY, PAGE_WRITECOPY }, /* 0x08 */
1053 { PAGE_WRITECOPY | PAGE_NOACCESS, 0 }, /* 0x09 */
1054 { PAGE_WRITECOPY | PAGE_READONLY, 0 }, /* 0x0a */
1055 { PAGE_WRITECOPY | PAGE_NOACCESS | PAGE_READONLY, 0 }, /* 0x0b */
1056 { PAGE_WRITECOPY | PAGE_READWRITE, 0 }, /* 0x0c */
1057 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x0d */
1058 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x0e */
1059 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x0f */
1061 { PAGE_EXECUTE, PAGE_EXECUTE }, /* 0x10 */
1062 { PAGE_EXECUTE_READ, PAGE_EXECUTE_READ }, /* 0x20 */
1063 { PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x30 */
1064 { PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY }, /* 0x40 */
1065 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0x50 */
1066 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0x60 */
1067 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x70 */
1068 { PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_WRITECOPY }, /* 0x80 */
1069 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE, 0 }, /* 0x90 */
1070 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ, 0 }, /* 0xa0 */
1071 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0xb0 */
1072 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE, 0 }, /* 0xc0 */
1073 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0xd0 */
1074 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0xe0 */
1075 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 } /* 0xf0 */
1077 DWORD ret, orig_prot, old_prot, rw_prot, exec_prot, i, j;
1078 MEMORY_BASIC_INFORMATION info;
1080 SetLastError(0xdeadbeef);
1081 ret = VirtualProtect(section, page_size, PAGE_NOACCESS, &old_prot);
1082 ok(ret, "VirtualProtect error %d\n", GetLastError());
1084 orig_prot = old_prot;
1086 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
1088 SetLastError(0xdeadbeef);
1089 ret = VirtualQuery(section, &info, sizeof(info));
1090 ok(ret, "VirtualQuery failed %d\n", GetLastError());
1091 ok(info.BaseAddress == section, "%d: got %p != expected %p\n", i, info.BaseAddress, section);
1092 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1093 ok(info.Protect == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, info.Protect);
1094 ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
1095 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1096 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1097 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1099 old_prot = 0xdeadbeef;
1100 SetLastError(0xdeadbeef);
1101 ret = VirtualProtect(section, page_size, td[i].prot_set, &old_prot);
1102 if (td[i].prot_get)
1104 ok(ret, "%d: VirtualProtect error %d, requested prot %#x\n", i, GetLastError(), td[i].prot_set);
1105 ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
1107 SetLastError(0xdeadbeef);
1108 ret = VirtualQuery(section, &info, sizeof(info));
1109 ok(ret, "VirtualQuery failed %d\n", GetLastError());
1110 ok(info.BaseAddress == section, "%d: got %p != expected %p\n", i, info.BaseAddress, section);
1111 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1112 ok(info.Protect == td[i].prot_get, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_get);
1113 ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
1114 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1115 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1116 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1118 else
1120 ok(!ret, "%d: VirtualProtect should fail\n", i);
1121 ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
1124 old_prot = 0xdeadbeef;
1125 SetLastError(0xdeadbeef);
1126 ret = VirtualProtect(section, page_size, PAGE_NOACCESS, &old_prot);
1127 ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
1128 if (td[i].prot_get)
1129 ok(old_prot == td[i].prot_get, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_get);
1130 else
1131 ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
1134 exec_prot = 0;
1136 for (i = 0; i <= 4; i++)
1138 rw_prot = 0;
1140 for (j = 0; j <= 4; j++)
1142 DWORD prot = exec_prot | rw_prot;
1144 SetLastError(0xdeadbeef);
1145 ret = VirtualProtect(section, page_size, prot, &old_prot);
1146 if ((rw_prot && exec_prot) || (!rw_prot && !exec_prot))
1148 ok(!ret, "VirtualProtect(%02x) should fail\n", prot);
1149 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1151 else
1152 ok(ret, "VirtualProtect(%02x) error %d\n", prot, GetLastError());
1154 rw_prot = 1 << j;
1157 exec_prot = 1 << (i + 4);
1160 SetLastError(0xdeadbeef);
1161 ret = VirtualProtect(section, page_size, orig_prot, &old_prot);
1162 ok(ret, "VirtualProtect error %d\n", GetLastError());
1165 static void test_section_access(void)
1167 static const struct test_data
1169 DWORD scn_file_access, scn_page_access, scn_page_access_after_write;
1170 } td[] =
1172 { 0, PAGE_NOACCESS, 0 },
1173 { IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1174 { IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1175 { IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1176 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1177 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ },
1178 { IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1179 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1181 { IMAGE_SCN_CNT_INITIALIZED_DATA, PAGE_NOACCESS, 0 },
1182 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1183 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1184 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1185 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1186 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
1187 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1188 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1190 { IMAGE_SCN_CNT_UNINITIALIZED_DATA, PAGE_NOACCESS, 0 },
1191 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1192 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1193 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1194 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1195 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
1196 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1197 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE }
1199 char buf[256];
1200 int i;
1201 DWORD dummy, file_align;
1202 HANDLE hfile;
1203 HMODULE hlib;
1204 char temp_path[MAX_PATH];
1205 char dll_name[MAX_PATH];
1206 SIZE_T size;
1207 MEMORY_BASIC_INFORMATION info;
1208 STARTUPINFOA sti;
1209 PROCESS_INFORMATION pi;
1210 DWORD ret;
1212 /* prevent displaying of the "Unable to load this DLL" message box */
1213 SetErrorMode(SEM_FAILCRITICALERRORS);
1215 GetTempPathA(MAX_PATH, temp_path);
1217 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
1219 IMAGE_NT_HEADERS nt_header;
1221 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
1223 /*trace("creating %s\n", dll_name);*/
1224 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
1225 if (hfile == INVALID_HANDLE_VALUE)
1227 ok(0, "could not create %s\n", dll_name);
1228 return;
1231 SetLastError(0xdeadbeef);
1232 ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
1233 ok(ret, "WriteFile error %d\n", GetLastError());
1235 nt_header = nt_header_template;
1236 nt_header.FileHeader.NumberOfSections = 1;
1237 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1238 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED;
1240 nt_header.OptionalHeader.SectionAlignment = page_size;
1241 nt_header.OptionalHeader.FileAlignment = 0x200;
1242 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
1243 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
1244 SetLastError(0xdeadbeef);
1245 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
1246 ok(ret, "WriteFile error %d\n", GetLastError());
1247 SetLastError(0xdeadbeef);
1248 ret = WriteFile(hfile, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
1249 ok(ret, "WriteFile error %d\n", GetLastError());
1251 section.SizeOfRawData = sizeof(section_data);
1252 section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
1253 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
1254 section.Misc.VirtualSize = section.SizeOfRawData;
1255 section.Characteristics = td[i].scn_file_access;
1256 SetLastError(0xdeadbeef);
1257 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
1258 ok(ret, "WriteFile error %d\n", GetLastError());
1260 file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
1261 assert(file_align < sizeof(filler));
1262 SetLastError(0xdeadbeef);
1263 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
1264 ok(ret, "WriteFile error %d\n", GetLastError());
1266 /* section data */
1267 SetLastError(0xdeadbeef);
1268 ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
1269 ok(ret, "WriteFile error %d\n", GetLastError());
1271 CloseHandle(hfile);
1273 SetLastError(0xdeadbeef);
1274 hlib = LoadLibraryA(dll_name);
1275 ok(hlib != 0, "LoadLibrary error %d\n", GetLastError());
1277 SetLastError(0xdeadbeef);
1278 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
1279 ok(size == sizeof(info),
1280 "%d: VirtualQuery error %d\n", i, GetLastError());
1281 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
1282 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1283 ok(info.Protect == td[i].scn_page_access, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access);
1284 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
1285 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1286 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1287 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1288 if (info.Protect != PAGE_NOACCESS)
1289 ok(!memcmp((const char *)info.BaseAddress, section_data, section.SizeOfRawData), "wrong section data\n");
1291 test_VirtualProtect(hlib, (char *)hlib + section.VirtualAddress);
1293 /* Windows changes the WRITECOPY to WRITE protection on an image section write (for a changed page only) */
1294 if (is_mem_writable(info.Protect))
1296 char *p = info.BaseAddress;
1297 *p = 0xfe;
1298 SetLastError(0xdeadbeef);
1299 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
1300 ok(size == sizeof(info), "%d: VirtualQuery error %d\n", i, GetLastError());
1301 /* FIXME: remove the condition below once Wine is fixed */
1302 todo_wine_if (info.Protect == PAGE_WRITECOPY || info.Protect == PAGE_EXECUTE_WRITECOPY)
1303 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);
1306 SetLastError(0xdeadbeef);
1307 ret = FreeLibrary(hlib);
1308 ok(ret, "FreeLibrary error %d\n", GetLastError());
1310 test_image_mapping(dll_name, td[i].scn_page_access, TRUE);
1312 /* reset IMAGE_FILE_DLL otherwise CreateProcess fails */
1313 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_RELOCS_STRIPPED;
1314 SetLastError(0xdeadbeef);
1315 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1316 /* LoadLibrary called on an already memory-mapped file in
1317 * test_image_mapping() above leads to a file handle leak
1318 * under nt4, and inability to overwrite and delete the file
1319 * due to sharing violation error. Ignore it and skip the test,
1320 * but leave a not deletable temporary file.
1322 ok(hfile != INVALID_HANDLE_VALUE || broken(hfile == INVALID_HANDLE_VALUE) /* nt4 */,
1323 "CreateFile error %d\n", GetLastError());
1324 if (hfile == INVALID_HANDLE_VALUE) goto nt4_is_broken;
1325 SetFilePointer(hfile, sizeof(dos_header), NULL, FILE_BEGIN);
1326 SetLastError(0xdeadbeef);
1327 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
1328 ok(ret, "WriteFile error %d\n", GetLastError());
1329 CloseHandle(hfile);
1331 memset(&sti, 0, sizeof(sti));
1332 sti.cb = sizeof(sti);
1333 SetLastError(0xdeadbeef);
1334 ret = CreateProcessA(dll_name, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &sti, &pi);
1335 ok(ret, "CreateProcess() error %d\n", GetLastError());
1337 SetLastError(0xdeadbeef);
1338 size = VirtualQueryEx(pi.hProcess, (char *)hlib + section.VirtualAddress, &info, sizeof(info));
1339 ok(size == sizeof(info),
1340 "%d: VirtualQuery error %d\n", i, GetLastError());
1341 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
1342 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1343 ok(info.Protect == td[i].scn_page_access, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access);
1344 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
1345 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1346 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1347 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1348 if (info.Protect != PAGE_NOACCESS)
1350 SetLastError(0xdeadbeef);
1351 ret = ReadProcessMemory(pi.hProcess, info.BaseAddress, buf, section.SizeOfRawData, NULL);
1352 ok(ret, "ReadProcessMemory() error %d\n", GetLastError());
1353 ok(!memcmp(buf, section_data, section.SizeOfRawData), "wrong section data\n");
1356 SetLastError(0xdeadbeef);
1357 ret = TerminateProcess(pi.hProcess, 0);
1358 ok(ret, "TerminateProcess() error %d\n", GetLastError());
1359 ret = WaitForSingleObject(pi.hProcess, 3000);
1360 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
1362 CloseHandle(pi.hThread);
1363 CloseHandle(pi.hProcess);
1365 test_image_mapping(dll_name, td[i].scn_page_access, FALSE);
1367 nt4_is_broken:
1368 SetLastError(0xdeadbeef);
1369 ret = DeleteFileA(dll_name);
1370 ok(ret || broken(!ret) /* nt4 */, "DeleteFile error %d\n", GetLastError());
1374 static void test_import_resolution(void)
1376 char temp_path[MAX_PATH];
1377 char dll_name[MAX_PATH];
1378 DWORD dummy;
1379 void *expect;
1380 char *str;
1381 HANDLE hfile;
1382 HMODULE mod, mod2;
1383 struct imports
1385 IMAGE_IMPORT_DESCRIPTOR descr[2];
1386 IMAGE_THUNK_DATA original_thunks[2];
1387 IMAGE_THUNK_DATA thunks[2];
1388 char module[16];
1389 struct { WORD hint; char name[32]; } function;
1390 IMAGE_TLS_DIRECTORY tls;
1391 char tls_data[16];
1392 SHORT tls_index;
1393 } data, *ptr;
1394 IMAGE_NT_HEADERS nt;
1395 IMAGE_SECTION_HEADER section;
1396 int test;
1398 for (test = 0; test < 3; test++)
1400 #define DATA_RVA(ptr) (page_size + ((char *)(ptr) - (char *)&data))
1401 nt = nt_header_template;
1402 nt.FileHeader.NumberOfSections = 1;
1403 nt.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1404 nt.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_RELOCS_STRIPPED;
1405 if (test != 2) nt.FileHeader.Characteristics |= IMAGE_FILE_DLL;
1406 nt.OptionalHeader.SectionAlignment = page_size;
1407 nt.OptionalHeader.FileAlignment = 0x200;
1408 nt.OptionalHeader.ImageBase = 0x12340000;
1409 nt.OptionalHeader.SizeOfImage = 2 * page_size;
1410 nt.OptionalHeader.SizeOfHeaders = nt.OptionalHeader.FileAlignment;
1411 nt.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
1412 memset( nt.OptionalHeader.DataDirectory, 0, sizeof(nt.OptionalHeader.DataDirectory) );
1413 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = sizeof(data.descr);
1414 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = DATA_RVA(data.descr);
1415 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = sizeof(data.tls);
1416 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = DATA_RVA(&data.tls);
1418 memset( &data, 0, sizeof(data) );
1419 data.descr[0].u.OriginalFirstThunk = DATA_RVA( data.original_thunks );
1420 data.descr[0].FirstThunk = DATA_RVA( data.thunks );
1421 data.descr[0].Name = DATA_RVA( data.module );
1422 strcpy( data.module, "kernel32.dll" );
1423 strcpy( data.function.name, "CreateEventA" );
1424 data.original_thunks[0].u1.AddressOfData = DATA_RVA( &data.function );
1425 data.thunks[0].u1.AddressOfData = 0xdeadbeef;
1427 data.tls.StartAddressOfRawData = nt.OptionalHeader.ImageBase + DATA_RVA( data.tls_data );
1428 data.tls.EndAddressOfRawData = data.tls.StartAddressOfRawData + sizeof(data.tls_data);
1429 data.tls.AddressOfIndex = nt.OptionalHeader.ImageBase + DATA_RVA( &data.tls_index );
1430 strcpy( data.tls_data, "hello world" );
1431 data.tls_index = 9999;
1433 GetTempPathA(MAX_PATH, temp_path);
1434 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
1436 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
1437 ok( hfile != INVALID_HANDLE_VALUE, "creation failed\n" );
1439 memset( &section, 0, sizeof(section) );
1440 memcpy( section.Name, ".text", sizeof(".text") );
1441 section.PointerToRawData = nt.OptionalHeader.FileAlignment;
1442 section.VirtualAddress = nt.OptionalHeader.SectionAlignment;
1443 section.Misc.VirtualSize = sizeof(data);
1444 section.SizeOfRawData = sizeof(data);
1445 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
1447 WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
1448 WriteFile(hfile, &nt, sizeof(nt), &dummy, NULL);
1449 WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
1451 SetFilePointer( hfile, section.PointerToRawData, NULL, SEEK_SET );
1452 WriteFile(hfile, &data, sizeof(data), &dummy, NULL);
1454 CloseHandle( hfile );
1456 switch (test)
1458 case 0: /* normal load */
1459 mod = LoadLibraryA( dll_name );
1460 ok( mod != NULL, "failed to load err %u\n", GetLastError() );
1461 if (!mod) break;
1462 ptr = (struct imports *)((char *)mod + page_size);
1463 expect = GetProcAddress( GetModuleHandleA( data.module ), data.function.name );
1464 ok( (void *)ptr->thunks[0].u1.Function == expect, "thunk %p instead of %p for %s.%s\n",
1465 (void *)ptr->thunks[0].u1.Function, expect, data.module, data.function.name );
1466 ok( ptr->tls_index < 32 || broken(ptr->tls_index == 9999), /* before vista */
1467 "wrong tls index %d\n", ptr->tls_index );
1468 if (ptr->tls_index != 9999)
1470 str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index];
1471 ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str );
1473 FreeLibrary( mod );
1474 break;
1475 case 1: /* load with DONT_RESOLVE_DLL_REFERENCES doesn't resolve imports */
1476 mod = LoadLibraryExA( dll_name, 0, DONT_RESOLVE_DLL_REFERENCES );
1477 ok( mod != NULL, "failed to load err %u\n", GetLastError() );
1478 if (!mod) break;
1479 ptr = (struct imports *)((char *)mod + page_size);
1480 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
1481 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
1482 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
1484 mod2 = LoadLibraryA( dll_name );
1485 ok( mod2 == mod, "loaded twice %p / %p\n", mod, mod2 );
1486 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
1487 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
1488 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
1489 FreeLibrary( mod2 );
1490 FreeLibrary( mod );
1491 break;
1492 case 2: /* load without IMAGE_FILE_DLL doesn't resolve imports */
1493 mod = LoadLibraryA( dll_name );
1494 ok( mod != NULL, "failed to load err %u\n", GetLastError() );
1495 if (!mod) break;
1496 ptr = (struct imports *)((char *)mod + page_size);
1497 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
1498 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
1499 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
1500 FreeLibrary( mod );
1501 break;
1503 DeleteFileA( dll_name );
1504 #undef DATA_RVA
1508 #define MAX_COUNT 10
1509 static HANDLE attached_thread[MAX_COUNT];
1510 static DWORD attached_thread_count;
1511 HANDLE stop_event, event, mutex, semaphore, loader_lock_event, peb_lock_event, heap_lock_event, ack_event;
1512 static int test_dll_phase, inside_loader_lock, inside_peb_lock, inside_heap_lock;
1513 static LONG fls_callback_count;
1515 static DWORD WINAPI mutex_thread_proc(void *param)
1517 HANDLE wait_list[4];
1518 DWORD ret;
1520 ret = WaitForSingleObject(mutex, 0);
1521 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1523 SetEvent(param);
1525 wait_list[0] = stop_event;
1526 wait_list[1] = loader_lock_event;
1527 wait_list[2] = peb_lock_event;
1528 wait_list[3] = heap_lock_event;
1530 trace("%04u: mutex_thread_proc: starting\n", GetCurrentThreadId());
1531 while (1)
1533 ret = WaitForMultipleObjects(sizeof(wait_list)/sizeof(wait_list[0]), wait_list, FALSE, 50);
1534 if (ret == WAIT_OBJECT_0) break;
1535 else if (ret == WAIT_OBJECT_0 + 1)
1537 ULONG_PTR loader_lock_magic;
1538 trace("%04u: mutex_thread_proc: Entering loader lock\n", GetCurrentThreadId());
1539 ret = pLdrLockLoaderLock(0, NULL, &loader_lock_magic);
1540 ok(!ret, "LdrLockLoaderLock error %#x\n", ret);
1541 inside_loader_lock++;
1542 SetEvent(ack_event);
1544 else if (ret == WAIT_OBJECT_0 + 2)
1546 trace("%04u: mutex_thread_proc: Entering PEB lock\n", GetCurrentThreadId());
1547 pRtlAcquirePebLock();
1548 inside_peb_lock++;
1549 SetEvent(ack_event);
1551 else if (ret == WAIT_OBJECT_0 + 3)
1553 trace("%04u: mutex_thread_proc: Entering heap lock\n", GetCurrentThreadId());
1554 HeapLock(GetProcessHeap());
1555 inside_heap_lock++;
1556 SetEvent(ack_event);
1560 trace("%04u: mutex_thread_proc: exiting\n", GetCurrentThreadId());
1561 return 196;
1564 static DWORD WINAPI semaphore_thread_proc(void *param)
1566 DWORD ret;
1568 ret = WaitForSingleObject(semaphore, 0);
1569 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1571 SetEvent(param);
1573 while (1)
1575 if (winetest_debug > 1)
1576 trace("%04u: semaphore_thread_proc: still alive\n", GetCurrentThreadId());
1577 if (WaitForSingleObject(stop_event, 50) != WAIT_TIMEOUT) break;
1580 trace("%04u: semaphore_thread_proc: exiting\n", GetCurrentThreadId());
1581 return 196;
1584 static DWORD WINAPI noop_thread_proc(void *param)
1586 if (param)
1588 LONG *noop_thread_started = param;
1589 InterlockedIncrement(noop_thread_started);
1592 trace("%04u: noop_thread_proc: exiting\n", GetCurrentThreadId());
1593 return 195;
1596 static VOID WINAPI fls_callback(PVOID lpFlsData)
1598 ok(lpFlsData == (void*) 0x31415, "lpFlsData is %p, expected %p\n", lpFlsData, (void*) 0x31415);
1599 InterlockedIncrement(&fls_callback_count);
1602 static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param)
1604 static LONG noop_thread_started;
1605 static DWORD fls_index = FLS_OUT_OF_INDEXES;
1606 static int fls_count = 0;
1607 static int thread_detach_count = 0;
1608 DWORD ret;
1610 ok(!inside_loader_lock, "inside_loader_lock should not be set\n");
1611 ok(!inside_peb_lock, "inside_peb_lock should not be set\n");
1613 switch (reason)
1615 case DLL_PROCESS_ATTACH:
1616 trace("dll: %p, DLL_PROCESS_ATTACH, %p\n", hinst, param);
1618 ret = pRtlDllShutdownInProgress();
1619 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1621 /* Set up the FLS slot, if FLS is available */
1622 if (pFlsGetValue)
1624 void* value;
1625 BOOL bret;
1626 ret = pFlsAlloc(&fls_callback);
1627 ok(ret != FLS_OUT_OF_INDEXES, "FlsAlloc returned %d\n", ret);
1628 fls_index = ret;
1629 SetLastError(0xdeadbeef);
1630 value = pFlsGetValue(fls_index);
1631 ok(!value, "FlsGetValue returned %p, expected NULL\n", value);
1632 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
1633 bret = pFlsSetValue(fls_index, (void*) 0x31415);
1634 ok(bret, "FlsSetValue failed\n");
1635 fls_count++;
1638 break;
1639 case DLL_PROCESS_DETACH:
1641 DWORD code, expected_code, i;
1642 HANDLE handle, process;
1643 void *addr;
1644 SIZE_T size;
1645 LARGE_INTEGER offset;
1646 DEBUG_EVENT de;
1648 trace("dll: %p, DLL_PROCESS_DETACH, %p\n", hinst, param);
1650 if (test_dll_phase == 4 || test_dll_phase == 5)
1652 ok(0, "dll_entry_point(DLL_PROCESS_DETACH) should not be called\n");
1653 break;
1656 /* The process should already deadlock at this point */
1657 if (test_dll_phase == 6)
1659 /* In reality, code below never gets executed, probably some other
1660 * code tries to access process heap and deadlocks earlier, even XP
1661 * doesn't call the DLL entry point on process detach either.
1663 HeapLock(GetProcessHeap());
1664 ok(0, "dll_entry_point: process should already deadlock\n");
1665 break;
1668 if (test_dll_phase == 0 || test_dll_phase == 1 || test_dll_phase == 3)
1669 ok(param != NULL, "dll: param %p\n", param);
1670 else
1671 ok(!param, "dll: param %p\n", param);
1673 if (test_dll_phase == 0 || test_dll_phase == 1) expected_code = 195;
1674 else if (test_dll_phase == 3) expected_code = 196;
1675 else expected_code = STILL_ACTIVE;
1677 if (test_dll_phase == 3)
1679 ret = pRtlDllShutdownInProgress();
1680 ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
1682 else
1684 ret = pRtlDllShutdownInProgress();
1686 /* FIXME: remove once Wine is fixed */
1687 todo_wine_if (!(expected_code == STILL_ACTIVE || expected_code == 196))
1688 ok(!ret || broken(ret) /* before Vista */, "RtlDllShutdownInProgress returned %d\n", ret);
1691 /* In the case that the process is terminating, FLS slots should still be accessible, but
1692 * the callback should be already run for this thread and the contents already NULL.
1693 * Note that this is broken for Win2k3, which runs the callbacks *after* the DLL entry
1694 * point has already run.
1696 if (param && pFlsGetValue)
1698 void* value;
1699 SetLastError(0xdeadbeef);
1700 value = pFlsGetValue(fls_index);
1701 todo_wine
1703 ok(broken(value == (void*) 0x31415) || /* Win2k3 */
1704 value == NULL, "FlsGetValue returned %p, expected NULL\n", value);
1706 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
1707 todo_wine
1709 ok(broken(fls_callback_count == thread_detach_count) || /* Win2k3 */
1710 fls_callback_count == thread_detach_count + 1,
1711 "wrong FLS callback count %d, expected %d\n", fls_callback_count, thread_detach_count + 1);
1714 if (pFlsFree)
1716 BOOL ret;
1717 /* Call FlsFree now and run the remaining callbacks from uncleanly terminated threads */
1718 ret = pFlsFree(fls_index);
1719 ok(ret, "FlsFree failed with error %u\n", GetLastError());
1720 fls_index = FLS_OUT_OF_INDEXES;
1721 todo_wine
1723 ok(fls_callback_count == fls_count,
1724 "wrong FLS callback count %d, expected %d\n", fls_callback_count, fls_count);
1728 ok(attached_thread_count >= 2, "attached thread count should be >= 2\n");
1730 for (i = 0; i < attached_thread_count; i++)
1732 /* Calling GetExitCodeThread() without waiting for thread termination
1733 * leads to different results due to a race condition.
1735 if (expected_code != STILL_ACTIVE)
1737 ret = WaitForSingleObject(attached_thread[i], 1000);
1738 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1740 ret = GetExitCodeThread(attached_thread[i], &code);
1741 trace("dll: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
1742 ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
1743 ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code);
1746 ret = WaitForSingleObject(event, 0);
1747 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1749 ret = WaitForSingleObject(mutex, 0);
1750 if (expected_code == STILL_ACTIVE)
1751 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1752 else
1753 ok(ret == WAIT_ABANDONED, "expected WAIT_ABANDONED, got %#x\n", ret);
1755 /* semaphore is not abandoned on thread termination */
1756 ret = WaitForSingleObject(semaphore, 0);
1757 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1759 if (expected_code == STILL_ACTIVE)
1761 ret = WaitForSingleObject(attached_thread[0], 0);
1762 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1763 ret = WaitForSingleObject(attached_thread[1], 0);
1764 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1766 else
1768 ret = WaitForSingleObject(attached_thread[0], 0);
1769 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1770 ret = WaitForSingleObject(attached_thread[1], 0);
1771 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1774 /* win7 doesn't allow creating a thread during process shutdown but
1775 * earlier Windows versions allow it.
1777 noop_thread_started = 0;
1778 SetLastError(0xdeadbeef);
1779 handle = CreateThread(NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
1780 if (param)
1782 ok(!handle || broken(handle != 0) /* before win7 */, "CreateThread should fail\n");
1783 if (!handle)
1784 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1785 else
1787 ret = WaitForSingleObject(handle, 1000);
1788 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1789 CloseHandle(handle);
1792 else
1794 ok(handle != 0, "CreateThread error %d\n", GetLastError());
1795 ret = WaitForSingleObject(handle, 1000);
1796 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1797 ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n");
1798 CloseHandle(handle);
1801 SetLastError(0xdeadbeef);
1802 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, GetCurrentProcessId());
1803 ok(process != NULL, "OpenProcess error %d\n", GetLastError());
1805 noop_thread_started = 0;
1806 SetLastError(0xdeadbeef);
1807 handle = CreateRemoteThread(process, NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
1808 if (param)
1810 ok(!handle || broken(handle != 0) /* before win7 */, "CreateRemoteThread should fail\n");
1811 if (!handle)
1812 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1813 else
1815 ret = WaitForSingleObject(handle, 1000);
1816 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1817 CloseHandle(handle);
1820 else
1822 ok(handle != 0, "CreateRemoteThread error %d\n", GetLastError());
1823 ret = WaitForSingleObject(handle, 1000);
1824 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1825 ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n");
1826 CloseHandle(handle);
1829 SetLastError(0xdeadbeef);
1830 handle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
1831 ok(handle != 0, "CreateFileMapping error %d\n", GetLastError());
1833 offset.u.LowPart = 0;
1834 offset.u.HighPart = 0;
1835 addr = NULL;
1836 size = 0;
1837 ret = pNtMapViewOfSection(handle, process, &addr, 0, 0, &offset,
1838 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1839 ok(ret == STATUS_SUCCESS, "NtMapViewOfSection error %#x\n", ret);
1840 ret = pNtUnmapViewOfSection(process, addr);
1841 ok(ret == STATUS_SUCCESS, "NtUnmapViewOfSection error %#x\n", ret);
1843 CloseHandle(handle);
1844 CloseHandle(process);
1846 handle = GetModuleHandleA("winver.exe");
1847 ok(!handle, "winver.exe shouldn't be loaded yet\n");
1848 SetLastError(0xdeadbeef);
1849 handle = LoadLibraryA("winver.exe");
1850 ok(handle != 0, "LoadLibrary error %d\n", GetLastError());
1851 SetLastError(0xdeadbeef);
1852 ret = FreeLibrary(handle);
1853 ok(ret, "FreeLibrary error %d\n", GetLastError());
1854 handle = GetModuleHandleA("winver.exe");
1855 if (param)
1856 ok(handle != 0, "winver.exe should not be unloaded\n");
1857 else
1858 todo_wine
1859 ok(!handle || broken(handle != 0) /* before win7 */, "winver.exe should be unloaded\n");
1861 SetLastError(0xdeadbeef);
1862 ret = WaitForDebugEvent(&de, 0);
1863 ok(!ret, "WaitForDebugEvent should fail\n");
1864 todo_wine
1865 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
1867 SetLastError(0xdeadbeef);
1868 ret = DebugActiveProcess(GetCurrentProcessId());
1869 ok(!ret, "DebugActiveProcess should fail\n");
1870 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1872 SetLastError(0xdeadbeef);
1873 ret = WaitForDebugEvent(&de, 0);
1874 ok(!ret, "WaitForDebugEvent should fail\n");
1875 ok(GetLastError() == ERROR_SEM_TIMEOUT, "expected ERROR_SEM_TIMEOUT, got %d\n", GetLastError());
1877 if (test_dll_phase == 2)
1879 trace("dll: call ExitProcess()\n");
1880 *child_failures = winetest_get_failures();
1881 ExitProcess(197);
1883 trace("dll: %p, DLL_PROCESS_DETACH, %p => DONE\n", hinst, param);
1884 break;
1886 case DLL_THREAD_ATTACH:
1887 trace("dll: %p, DLL_THREAD_ATTACH, %p\n", hinst, param);
1889 ret = pRtlDllShutdownInProgress();
1890 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1892 if (attached_thread_count < MAX_COUNT)
1894 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &attached_thread[attached_thread_count],
1895 0, TRUE, DUPLICATE_SAME_ACCESS);
1896 attached_thread_count++;
1899 /* Make sure the FLS slot is empty, if FLS is available */
1900 if (pFlsGetValue)
1902 void* value;
1903 BOOL ret;
1904 SetLastError(0xdeadbeef);
1905 value = pFlsGetValue(fls_index);
1906 ok(!value, "FlsGetValue returned %p, expected NULL\n", value);
1907 todo_wine
1908 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
1909 ret = pFlsSetValue(fls_index, (void*) 0x31415);
1910 ok(ret, "FlsSetValue failed\n");
1911 fls_count++;
1914 break;
1915 case DLL_THREAD_DETACH:
1916 trace("dll: %p, DLL_THREAD_DETACH, %p\n", hinst, param);
1917 thread_detach_count++;
1919 ret = pRtlDllShutdownInProgress();
1920 /* win7 doesn't allow creating a thread during process shutdown but
1921 * earlier Windows versions allow it. In that case DLL_THREAD_DETACH is
1922 * sent on thread exit, but DLL_THREAD_ATTACH is never received.
1924 if (noop_thread_started)
1925 ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
1926 else
1927 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1929 /* FLS data should already be destroyed, if FLS is available.
1930 * Note that this is broken for Win2k3, which runs the callbacks *after* the DLL entry
1931 * point has already run.
1933 if (pFlsGetValue && fls_index != FLS_OUT_OF_INDEXES)
1935 void* value;
1936 SetLastError(0xdeadbeef);
1937 value = pFlsGetValue(fls_index);
1938 todo_wine
1940 ok(broken(value == (void*) 0x31415) || /* Win2k3 */
1941 !value, "FlsGetValue returned %p, expected NULL\n", value);
1943 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
1946 break;
1947 default:
1948 trace("dll: %p, %d, %p\n", hinst, reason, param);
1949 break;
1952 *child_failures = winetest_get_failures();
1954 return TRUE;
1957 static void child_process(const char *dll_name, DWORD target_offset)
1959 void *target;
1960 DWORD ret, dummy, i, code, expected_code;
1961 HANDLE file, thread, process;
1962 HMODULE hmod;
1963 struct PROCESS_BASIC_INFORMATION_PRIVATE pbi;
1964 DWORD_PTR affinity;
1966 trace("phase %d: writing %p at %#x\n", test_dll_phase, dll_entry_point, target_offset);
1968 SetLastError(0xdeadbeef);
1969 mutex = CreateMutexW(NULL, FALSE, NULL);
1970 ok(mutex != 0, "CreateMutex error %d\n", GetLastError());
1972 SetLastError(0xdeadbeef);
1973 semaphore = CreateSemaphoreW(NULL, 1, 1, NULL);
1974 ok(semaphore != 0, "CreateSemaphore error %d\n", GetLastError());
1976 SetLastError(0xdeadbeef);
1977 event = CreateEventW(NULL, TRUE, FALSE, NULL);
1978 ok(event != 0, "CreateEvent error %d\n", GetLastError());
1980 SetLastError(0xdeadbeef);
1981 loader_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1982 ok(loader_lock_event != 0, "CreateEvent error %d\n", GetLastError());
1984 SetLastError(0xdeadbeef);
1985 peb_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1986 ok(peb_lock_event != 0, "CreateEvent error %d\n", GetLastError());
1988 SetLastError(0xdeadbeef);
1989 heap_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1990 ok(heap_lock_event != 0, "CreateEvent error %d\n", GetLastError());
1992 SetLastError(0xdeadbeef);
1993 ack_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1994 ok(ack_event != 0, "CreateEvent error %d\n", GetLastError());
1996 file = CreateFileA(dll_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1997 if (file == INVALID_HANDLE_VALUE)
1999 ok(0, "could not open %s\n", dll_name);
2000 return;
2002 SetFilePointer(file, target_offset, NULL, FILE_BEGIN);
2003 SetLastError(0xdeadbeef);
2004 target = dll_entry_point;
2005 ret = WriteFile(file, &target, sizeof(target), &dummy, NULL);
2006 ok(ret, "WriteFile error %d\n", GetLastError());
2007 CloseHandle(file);
2009 SetLastError(0xdeadbeef);
2010 hmod = LoadLibraryA(dll_name);
2011 ok(hmod != 0, "LoadLibrary error %d\n", GetLastError());
2013 SetLastError(0xdeadbeef);
2014 stop_event = CreateEventW(NULL, TRUE, FALSE, NULL);
2015 ok(stop_event != 0, "CreateEvent error %d\n", GetLastError());
2017 SetLastError(0xdeadbeef);
2018 thread = CreateThread(NULL, 0, mutex_thread_proc, event, 0, &dummy);
2019 ok(thread != 0, "CreateThread error %d\n", GetLastError());
2020 WaitForSingleObject(event, 3000);
2021 CloseHandle(thread);
2023 ResetEvent(event);
2025 SetLastError(0xdeadbeef);
2026 thread = CreateThread(NULL, 0, semaphore_thread_proc, event, 0, &dummy);
2027 ok(thread != 0, "CreateThread error %d\n", GetLastError());
2028 WaitForSingleObject(event, 3000);
2029 CloseHandle(thread);
2031 ResetEvent(event);
2032 Sleep(100);
2034 ok(attached_thread_count == 2, "attached thread count should be 2\n");
2035 for (i = 0; i < attached_thread_count; i++)
2037 ret = GetExitCodeThread(attached_thread[i], &code);
2038 trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
2039 ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
2040 ok(code == STILL_ACTIVE, "expected thread exit code STILL_ACTIVE, got %u\n", code);
2043 ret = WaitForSingleObject(attached_thread[0], 0);
2044 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2045 ret = WaitForSingleObject(attached_thread[1], 0);
2046 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2048 ret = WaitForSingleObject(event, 0);
2049 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2050 ret = WaitForSingleObject(mutex, 0);
2051 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2052 ret = WaitForSingleObject(semaphore, 0);
2053 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2055 ret = pRtlDllShutdownInProgress();
2056 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2058 SetLastError(0xdeadbeef);
2059 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, GetCurrentProcessId());
2060 ok(process != NULL, "OpenProcess error %d\n", GetLastError());
2062 SetLastError(0xdeadbeef);
2063 ret = TerminateProcess(0, 195);
2064 ok(!ret, "TerminateProcess(0) should fail\n");
2065 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
2067 Sleep(100);
2069 affinity = 1;
2070 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
2071 ok(!ret, "NtSetInformationProcess error %#x\n", ret);
2073 switch (test_dll_phase)
2075 case 0:
2076 ret = pRtlDllShutdownInProgress();
2077 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2079 trace("call NtTerminateProcess(0, 195)\n");
2080 ret = pNtTerminateProcess(0, 195);
2081 ok(!ret, "NtTerminateProcess error %#x\n", ret);
2083 memset(&pbi, 0, sizeof(pbi));
2084 ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
2085 ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
2086 ok(pbi.ExitStatus == STILL_ACTIVE || pbi.ExitStatus == 195,
2087 "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus);
2088 affinity = 1;
2089 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
2090 ok(!ret, "NtSetInformationProcess error %#x\n", ret);
2092 ret = pRtlDllShutdownInProgress();
2093 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2095 hmod = GetModuleHandleA(dll_name);
2096 ok(hmod != 0, "DLL should not be unloaded\n");
2098 SetLastError(0xdeadbeef);
2099 thread = CreateThread(NULL, 0, noop_thread_proc, &dummy, 0, &ret);
2100 ok(!thread || broken(thread != 0) /* before win7 */, "CreateThread should fail\n");
2101 if (!thread)
2102 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2103 else
2105 ret = WaitForSingleObject(thread, 1000);
2106 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2107 CloseHandle(thread);
2110 trace("call LdrShutdownProcess()\n");
2111 pLdrShutdownProcess();
2113 ret = pRtlDllShutdownInProgress();
2114 ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
2116 hmod = GetModuleHandleA(dll_name);
2117 ok(hmod != 0, "DLL should not be unloaded\n");
2119 memset(&pbi, 0, sizeof(pbi));
2120 ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
2121 ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
2122 ok(pbi.ExitStatus == STILL_ACTIVE || pbi.ExitStatus == 195,
2123 "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus);
2124 affinity = 1;
2125 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
2126 ok(!ret, "NtSetInformationProcess error %#x\n", ret);
2127 break;
2129 case 1: /* normal ExitProcess */
2130 ret = pRtlDllShutdownInProgress();
2131 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2132 break;
2134 case 2: /* ExitProcess will be called by the PROCESS_DETACH handler */
2135 ret = pRtlDllShutdownInProgress();
2136 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2138 trace("call FreeLibrary(%p)\n", hmod);
2139 SetLastError(0xdeadbeef);
2140 ret = FreeLibrary(hmod);
2141 ok(ret, "FreeLibrary error %d\n", GetLastError());
2142 hmod = GetModuleHandleA(dll_name);
2143 ok(!hmod, "DLL should be unloaded\n");
2145 if (test_dll_phase == 2)
2146 ok(0, "FreeLibrary+ExitProcess should never return\n");
2148 ret = pRtlDllShutdownInProgress();
2149 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2151 break;
2153 case 3:
2154 trace("signalling thread exit\n");
2155 SetEvent(stop_event);
2156 CloseHandle(stop_event);
2157 break;
2159 case 4:
2160 trace("setting loader_lock_event\n");
2161 SetEvent(loader_lock_event);
2162 WaitForSingleObject(ack_event, 1000);
2163 ok(inside_loader_lock != 0, "inside_loader_lock is not set\n");
2165 /* calling NtTerminateProcess should not cause a deadlock */
2166 trace("call NtTerminateProcess(0, 198)\n");
2167 ret = pNtTerminateProcess(0, 198);
2168 ok(!ret, "NtTerminateProcess error %#x\n", ret);
2170 *child_failures = winetest_get_failures();
2172 /* Windows fails to release loader lock acquired from another thread,
2173 * so the LdrUnlockLoaderLock call fails here and ExitProcess deadlocks
2174 * later on, so NtTerminateProcess is used instead.
2176 trace("call NtTerminateProcess(GetCurrentProcess(), 198)\n");
2177 pNtTerminateProcess(GetCurrentProcess(), 198);
2178 ok(0, "NtTerminateProcess should not return\n");
2179 break;
2181 case 5:
2182 trace("setting peb_lock_event\n");
2183 SetEvent(peb_lock_event);
2184 WaitForSingleObject(ack_event, 1000);
2185 ok(inside_peb_lock != 0, "inside_peb_lock is not set\n");
2187 *child_failures = winetest_get_failures();
2189 /* calling ExitProcess should cause a deadlock */
2190 trace("call ExitProcess(198)\n");
2191 ExitProcess(198);
2192 ok(0, "ExitProcess should not return\n");
2193 break;
2195 case 6:
2196 trace("setting heap_lock_event\n");
2197 SetEvent(heap_lock_event);
2198 WaitForSingleObject(ack_event, 1000);
2199 ok(inside_heap_lock != 0, "inside_heap_lock is not set\n");
2201 *child_failures = winetest_get_failures();
2203 /* calling ExitProcess should cause a deadlock */
2204 trace("call ExitProcess(1)\n");
2205 ExitProcess(1);
2206 ok(0, "ExitProcess should not return\n");
2207 break;
2209 default:
2210 assert(0);
2211 break;
2214 if (test_dll_phase == 0) expected_code = 195;
2215 else if (test_dll_phase == 3) expected_code = 196;
2216 else if (test_dll_phase == 4) expected_code = 198;
2217 else expected_code = STILL_ACTIVE;
2219 if (expected_code == STILL_ACTIVE)
2221 ret = WaitForSingleObject(attached_thread[0], 100);
2222 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2223 ret = WaitForSingleObject(attached_thread[1], 100);
2224 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2226 else
2228 ret = WaitForSingleObject(attached_thread[0], 2000);
2229 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2230 ret = WaitForSingleObject(attached_thread[1], 2000);
2231 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2234 for (i = 0; i < attached_thread_count; i++)
2236 ret = GetExitCodeThread(attached_thread[i], &code);
2237 trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
2238 ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
2239 ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code);
2242 *child_failures = winetest_get_failures();
2244 trace("call ExitProcess(195)\n");
2245 ExitProcess(195);
2248 static void test_ExitProcess(void)
2250 #include "pshpack1.h"
2251 #ifdef __x86_64__
2252 static struct section_data
2254 BYTE mov_rax[2];
2255 void *target;
2256 BYTE jmp_rax[2];
2257 } section_data = { { 0x48,0xb8 }, dll_entry_point, { 0xff,0xe0 } };
2258 #else
2259 static struct section_data
2261 BYTE mov_eax;
2262 void *target;
2263 BYTE jmp_eax[2];
2264 } section_data = { 0xb8, dll_entry_point, { 0xff,0xe0 } };
2265 #endif
2266 #include "poppack.h"
2267 DWORD dummy, file_align;
2268 HANDLE file, thread, process, hmap, hmap_dup;
2269 char temp_path[MAX_PATH], dll_name[MAX_PATH], cmdline[MAX_PATH * 2];
2270 DWORD ret, target_offset, old_prot;
2271 char **argv, buf[256];
2272 PROCESS_INFORMATION pi;
2273 STARTUPINFOA si = { sizeof(si) };
2274 CONTEXT ctx;
2275 struct PROCESS_BASIC_INFORMATION_PRIVATE pbi;
2276 MEMORY_BASIC_INFORMATION mbi;
2277 DWORD_PTR affinity;
2278 void *addr;
2279 LARGE_INTEGER offset;
2280 SIZE_T size;
2281 IMAGE_NT_HEADERS nt_header;
2283 #if !defined(__i386__) && !defined(__x86_64__)
2284 skip("x86 specific ExitProcess test\n");
2285 return;
2286 #endif
2288 if (!pRtlDllShutdownInProgress)
2290 win_skip("RtlDllShutdownInProgress is not available on this platform (XP+)\n");
2291 return;
2293 if (!pNtQueryInformationProcess || !pNtSetInformationProcess)
2295 win_skip("NtQueryInformationProcess/NtSetInformationProcess are not available on this platform\n");
2296 return;
2298 if (!pNtAllocateVirtualMemory || !pNtFreeVirtualMemory)
2300 win_skip("NtAllocateVirtualMemory/NtFreeVirtualMemory are not available on this platform\n");
2301 return;
2304 /* prevent displaying of the "Unable to load this DLL" message box */
2305 SetErrorMode(SEM_FAILCRITICALERRORS);
2307 GetTempPathA(MAX_PATH, temp_path);
2308 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
2310 /*trace("creating %s\n", dll_name);*/
2311 file = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2312 if (file == INVALID_HANDLE_VALUE)
2314 ok(0, "could not create %s\n", dll_name);
2315 return;
2318 SetLastError(0xdeadbeef);
2319 ret = WriteFile(file, &dos_header, sizeof(dos_header), &dummy, NULL);
2320 ok(ret, "WriteFile error %d\n", GetLastError());
2322 nt_header = nt_header_template;
2323 nt_header.FileHeader.NumberOfSections = 1;
2324 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
2325 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED;
2327 nt_header.OptionalHeader.AddressOfEntryPoint = 0x1000;
2328 nt_header.OptionalHeader.SectionAlignment = 0x1000;
2329 nt_header.OptionalHeader.FileAlignment = 0x200;
2330 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000;
2331 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
2332 SetLastError(0xdeadbeef);
2333 ret = WriteFile(file, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
2334 ok(ret, "WriteFile error %d\n", GetLastError());
2335 SetLastError(0xdeadbeef);
2336 ret = WriteFile(file, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
2337 ok(ret, "WriteFile error %d\n", GetLastError());
2339 section.SizeOfRawData = sizeof(section_data);
2340 section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
2341 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
2342 section.Misc.VirtualSize = sizeof(section_data);
2343 section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
2344 SetLastError(0xdeadbeef);
2345 ret = WriteFile(file, &section, sizeof(section), &dummy, NULL);
2346 ok(ret, "WriteFile error %d\n", GetLastError());
2348 file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
2349 assert(file_align < sizeof(filler));
2350 SetLastError(0xdeadbeef);
2351 ret = WriteFile(file, filler, file_align, &dummy, NULL);
2352 ok(ret, "WriteFile error %d\n", GetLastError());
2354 target_offset = SetFilePointer(file, 0, NULL, FILE_CURRENT) + FIELD_OFFSET(struct section_data, target);
2356 /* section data */
2357 SetLastError(0xdeadbeef);
2358 ret = WriteFile(file, &section_data, sizeof(section_data), &dummy, NULL);
2359 ok(ret, "WriteFile error %d\n", GetLastError());
2361 CloseHandle(file);
2363 winetest_get_mainargs(&argv);
2365 /* phase 0 */
2366 *child_failures = -1;
2367 sprintf(cmdline, "\"%s\" loader %s %u 0", argv[0], dll_name, target_offset);
2368 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2369 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2370 ret = WaitForSingleObject(pi.hProcess, 10000);
2371 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2372 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2373 GetExitCodeProcess(pi.hProcess, &ret);
2374 ok(ret == 195, "expected exit code 195, got %u\n", ret);
2375 if (*child_failures)
2377 trace("%d failures in child process\n", *child_failures);
2378 winetest_add_failures(*child_failures);
2380 CloseHandle(pi.hThread);
2381 CloseHandle(pi.hProcess);
2383 /* phase 1 */
2384 *child_failures = -1;
2385 sprintf(cmdline, "\"%s\" loader %s %u 1", argv[0], dll_name, target_offset);
2386 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2387 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2388 ret = WaitForSingleObject(pi.hProcess, 10000);
2389 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2390 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2391 GetExitCodeProcess(pi.hProcess, &ret);
2392 ok(ret == 195, "expected exit code 195, got %u\n", ret);
2393 if (*child_failures)
2395 trace("%d failures in child process\n", *child_failures);
2396 winetest_add_failures(*child_failures);
2398 CloseHandle(pi.hThread);
2399 CloseHandle(pi.hProcess);
2401 /* phase 2 */
2402 *child_failures = -1;
2403 sprintf(cmdline, "\"%s\" loader %s %u 2", argv[0], dll_name, target_offset);
2404 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2405 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2406 ret = WaitForSingleObject(pi.hProcess, 10000);
2407 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2408 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2409 GetExitCodeProcess(pi.hProcess, &ret);
2410 ok(ret == 197, "expected exit code 197, got %u\n", ret);
2411 if (*child_failures)
2413 trace("%d failures in child process\n", *child_failures);
2414 winetest_add_failures(*child_failures);
2416 CloseHandle(pi.hThread);
2417 CloseHandle(pi.hProcess);
2419 /* phase 3 */
2420 *child_failures = -1;
2421 sprintf(cmdline, "\"%s\" loader %s %u 3", argv[0], dll_name, target_offset);
2422 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2423 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2424 ret = WaitForSingleObject(pi.hProcess, 10000);
2425 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2426 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2427 GetExitCodeProcess(pi.hProcess, &ret);
2428 ok(ret == 195, "expected exit code 195, got %u\n", ret);
2429 if (*child_failures)
2431 trace("%d failures in child process\n", *child_failures);
2432 winetest_add_failures(*child_failures);
2434 CloseHandle(pi.hThread);
2435 CloseHandle(pi.hProcess);
2437 /* phase 4 */
2438 if (pLdrLockLoaderLock && pLdrUnlockLoaderLock)
2440 *child_failures = -1;
2441 sprintf(cmdline, "\"%s\" loader %s %u 4", argv[0], dll_name, target_offset);
2442 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2443 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2444 ret = WaitForSingleObject(pi.hProcess, 10000);
2445 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2446 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2447 GetExitCodeProcess(pi.hProcess, &ret);
2448 ok(ret == 198, "expected exit code 198, got %u\n", ret);
2449 if (*child_failures)
2451 trace("%d failures in child process\n", *child_failures);
2452 winetest_add_failures(*child_failures);
2454 CloseHandle(pi.hThread);
2455 CloseHandle(pi.hProcess);
2457 else
2458 win_skip("LdrLockLoaderLock/LdrUnlockLoaderLock are not available on this platform\n");
2460 /* phase 5 */
2461 if (pRtlAcquirePebLock && pRtlReleasePebLock)
2463 *child_failures = -1;
2464 sprintf(cmdline, "\"%s\" loader %s %u 5", argv[0], dll_name, target_offset);
2465 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2466 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2467 ret = WaitForSingleObject(pi.hProcess, 5000);
2468 ok(ret == WAIT_TIMEOUT, "child process should fail to terminate\n");
2469 if (ret != WAIT_OBJECT_0)
2471 trace("terminating child process\n");
2472 TerminateProcess(pi.hProcess, 199);
2474 ret = WaitForSingleObject(pi.hProcess, 1000);
2475 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2476 GetExitCodeProcess(pi.hProcess, &ret);
2477 ok(ret == 199, "expected exit code 199, got %u\n", ret);
2478 if (*child_failures)
2480 trace("%d failures in child process\n", *child_failures);
2481 winetest_add_failures(*child_failures);
2483 CloseHandle(pi.hThread);
2484 CloseHandle(pi.hProcess);
2486 else
2487 win_skip("RtlAcquirePebLock/RtlReleasePebLock are not available on this platform\n");
2489 /* phase 6 */
2490 *child_failures = -1;
2491 sprintf(cmdline, "\"%s\" loader %s %u 6", argv[0], dll_name, target_offset);
2492 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2493 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2494 ret = WaitForSingleObject(pi.hProcess, 5000);
2495 ok(ret == WAIT_TIMEOUT || broken(ret == WAIT_OBJECT_0) /* XP */, "child process should fail to terminate\n");
2496 if (ret != WAIT_OBJECT_0)
2498 trace("terminating child process\n");
2499 TerminateProcess(pi.hProcess, 201);
2501 ret = WaitForSingleObject(pi.hProcess, 1000);
2502 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2503 GetExitCodeProcess(pi.hProcess, &ret);
2504 ok(ret == 201 || broken(ret == 1) /* XP */, "expected exit code 201, got %u\n", ret);
2505 if (*child_failures)
2507 trace("%d failures in child process\n", *child_failures);
2508 winetest_add_failures(*child_failures);
2510 CloseHandle(pi.hThread);
2511 CloseHandle(pi.hProcess);
2513 /* test remote process termination */
2514 SetLastError(0xdeadbeef);
2515 ret = CreateProcessA(argv[0], NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
2516 ok(ret, "CreateProcess(%s) error %d\n", argv[0], GetLastError());
2518 SetLastError(0xdeadbeef);
2519 addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
2520 ok(addr != NULL, "VirtualAllocEx error %d\n", GetLastError());
2521 SetLastError(0xdeadbeef);
2522 ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READONLY, &old_prot);
2523 ok(ret, "VirtualProtectEx error %d\n", GetLastError());
2524 ok(old_prot == PAGE_READWRITE, "expected PAGE_READWRITE, got %#x\n", old_prot);
2525 SetLastError(0xdeadbeef);
2526 size = VirtualQueryEx(pi.hProcess, NULL, &mbi, sizeof(mbi));
2527 ok(size == sizeof(mbi), "VirtualQueryEx error %d\n", GetLastError());
2529 SetLastError(0xdeadbeef);
2530 ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size);
2531 ok(ret, "ReadProcessMemory error %d\n", GetLastError());
2532 ok(size == 4, "expected 4, got %lu\n", size);
2534 SetLastError(0xdeadbeef);
2535 hmap = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
2536 ok(hmap != 0, "CreateFileMapping error %d\n", GetLastError());
2538 SetLastError(0xdeadbeef);
2539 ret = DuplicateHandle(GetCurrentProcess(), hmap, pi.hProcess, &hmap_dup,
2540 0, FALSE, DUPLICATE_SAME_ACCESS);
2541 ok(ret, "DuplicateHandle error %d\n", GetLastError());
2543 offset.u.LowPart = 0;
2544 offset.u.HighPart = 0;
2545 addr = NULL;
2546 size = 0;
2547 ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset,
2548 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
2549 ok(!ret, "NtMapViewOfSection error %#x\n", ret);
2550 ret = pNtUnmapViewOfSection(pi.hProcess, addr);
2551 ok(!ret, "NtUnmapViewOfSection error %#x\n", ret);
2553 SetLastError(0xdeadbeef);
2554 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2555 ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError());
2556 SetLastError(0xdeadbeef);
2557 ctx.ContextFlags = CONTEXT_INTEGER;
2558 ret = GetThreadContext(thread, &ctx);
2559 ok(ret, "GetThreadContext error %d\n", GetLastError());
2560 SetLastError(0xdeadbeef);
2561 ctx.ContextFlags = CONTEXT_INTEGER;
2562 ret = SetThreadContext(thread, &ctx);
2563 ok(ret, "SetThreadContext error %d\n", GetLastError());
2564 SetLastError(0xdeadbeef);
2565 ret = SetThreadPriority(thread, 0);
2566 ok(ret, "SetThreadPriority error %d\n", GetLastError());
2568 SetLastError(0xdeadbeef);
2569 ret = TerminateThread(thread, 199);
2570 ok(ret, "TerminateThread error %d\n", GetLastError());
2571 /* Calling GetExitCodeThread() without waiting for thread termination
2572 * leads to different results due to a race condition.
2574 ret = WaitForSingleObject(thread, 1000);
2575 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
2576 GetExitCodeThread(thread, &ret);
2577 ok(ret == 199, "expected exit code 199, got %u\n", ret);
2579 SetLastError(0xdeadbeef);
2580 ret = TerminateProcess(pi.hProcess, 198);
2581 ok(ret, "TerminateProcess error %d\n", GetLastError());
2582 /* Checking process state without waiting for process termination
2583 * leads to different results due to a race condition.
2585 ret = WaitForSingleObject(pi.hProcess, 1000);
2586 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
2588 SetLastError(0xdeadbeef);
2589 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pi.dwProcessId);
2590 ok(process != NULL, "OpenProcess error %d\n", GetLastError());
2591 CloseHandle(process);
2593 memset(&pbi, 0, sizeof(pbi));
2594 ret = pNtQueryInformationProcess(pi.hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
2595 ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
2596 ok(pbi.ExitStatus == 198, "expected 198, got %lu\n", pbi.ExitStatus);
2597 affinity = 1;
2598 ret = pNtSetInformationProcess(pi.hProcess, ProcessAffinityMask, &affinity, sizeof(affinity));
2599 ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#x\n", ret);
2601 SetLastError(0xdeadbeef);
2602 ctx.ContextFlags = CONTEXT_INTEGER;
2603 ret = GetThreadContext(thread, &ctx);
2604 ok(!ret || broken(ret) /* XP 64-bit */, "GetThreadContext should fail\n");
2605 if (!ret)
2606 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
2607 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
2608 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
2609 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2610 SetLastError(0xdeadbeef);
2611 ctx.ContextFlags = CONTEXT_INTEGER;
2612 ret = SetThreadContext(thread, &ctx);
2613 ok(!ret || broken(ret) /* XP 64-bit */, "SetThreadContext should fail\n");
2614 if (!ret)
2615 ok(GetLastError() == ERROR_ACCESS_DENIED ||
2616 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
2617 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
2618 "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2619 SetLastError(0xdeadbeef);
2620 ret = SetThreadPriority(thread, 0);
2621 ok(ret, "SetThreadPriority error %d\n", GetLastError());
2622 CloseHandle(thread);
2624 SetLastError(0xdeadbeef);
2625 ctx.ContextFlags = CONTEXT_INTEGER;
2626 ret = GetThreadContext(pi.hThread, &ctx);
2627 ok(!ret || broken(ret) /* XP 64-bit */, "GetThreadContext should fail\n");
2628 if (!ret)
2629 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
2630 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
2631 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
2632 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2633 SetLastError(0xdeadbeef);
2634 ctx.ContextFlags = CONTEXT_INTEGER;
2635 ret = SetThreadContext(pi.hThread, &ctx);
2636 ok(!ret || broken(ret) /* XP 64-bit */, "SetThreadContext should fail\n");
2637 if (!ret)
2638 ok(GetLastError() == ERROR_ACCESS_DENIED ||
2639 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
2640 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
2641 "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2642 SetLastError(0xdeadbeef);
2643 ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READWRITE, &old_prot);
2644 ok(!ret, "VirtualProtectEx should fail\n");
2645 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2646 SetLastError(0xdeadbeef);
2647 size = 0;
2648 ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size);
2649 ok(!ret, "ReadProcessMemory should fail\n");
2650 ok(GetLastError() == ERROR_PARTIAL_COPY || GetLastError() == ERROR_ACCESS_DENIED,
2651 "expected ERROR_PARTIAL_COPY, got %d\n", GetLastError());
2652 ok(!size, "expected 0, got %lu\n", size);
2653 SetLastError(0xdeadbeef);
2654 ret = VirtualFreeEx(pi.hProcess, addr, 0, MEM_RELEASE);
2655 ok(!ret, "VirtualFreeEx should fail\n");
2656 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2657 SetLastError(0xdeadbeef);
2658 addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
2659 ok(!addr, "VirtualAllocEx should fail\n");
2660 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2661 SetLastError(0xdeadbeef);
2662 size = VirtualQueryEx(pi.hProcess, NULL, &mbi, sizeof(mbi));
2663 ok(!size, "VirtualQueryEx should fail\n");
2664 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2666 /* CloseHandle() call below leads to premature process termination
2667 * under some Windows versions.
2669 if (0)
2671 SetLastError(0xdeadbeef);
2672 ret = CloseHandle(hmap_dup);
2673 ok(ret, "CloseHandle should not fail\n");
2676 SetLastError(0xdeadbeef);
2677 ret = DuplicateHandle(GetCurrentProcess(), hmap, pi.hProcess, &hmap_dup,
2678 0, FALSE, DUPLICATE_SAME_ACCESS);
2679 ok(!ret, "DuplicateHandle should fail\n");
2680 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2682 offset.u.LowPart = 0;
2683 offset.u.HighPart = 0;
2684 addr = NULL;
2685 size = 0;
2686 ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset,
2687 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
2688 ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#x\n", ret);
2690 SetLastError(0xdeadbeef);
2691 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2692 ok(!thread, "CreateRemoteThread should fail\n");
2693 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2695 SetLastError(0xdeadbeef);
2696 ret = DebugActiveProcess(pi.dwProcessId);
2697 ok(!ret, "DebugActiveProcess should fail\n");
2698 ok(GetLastError() == ERROR_ACCESS_DENIED /* 64-bit */ || GetLastError() == ERROR_NOT_SUPPORTED /* 32-bit */,
2699 "ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2701 GetExitCodeProcess(pi.hProcess, &ret);
2702 ok(ret == 198 || broken(ret != 198) /* some 32-bit XP version in a VM returns random exit code */,
2703 "expected exit code 198, got %u\n", ret);
2704 CloseHandle(pi.hThread);
2705 CloseHandle(pi.hProcess);
2707 ret = DeleteFileA(dll_name);
2708 ok(ret, "DeleteFile error %d\n", GetLastError());
2711 static PVOID WINAPI failuredllhook(ULONG ul, DELAYLOAD_INFO* pd)
2713 ok(ul == 4, "expected 4, got %u\n", ul);
2714 ok(!!pd, "no delayload info supplied\n");
2715 if (pd)
2717 ok(pd->Size == sizeof(*pd), "got %u\n", pd->Size);
2718 ok(!!pd->DelayloadDescriptor, "no DelayloadDescriptor supplied\n");
2719 if (pd->DelayloadDescriptor)
2721 ok(pd->DelayloadDescriptor->Attributes.AllAttributes == 1,
2722 "expected 1, got %u\n", pd->DelayloadDescriptor->Attributes.AllAttributes);
2723 ok(pd->DelayloadDescriptor->DllNameRVA == 0x2000,
2724 "expected 0x2000, got %x\n", pd->DelayloadDescriptor->DllNameRVA);
2725 ok(pd->DelayloadDescriptor->ModuleHandleRVA == 0x201a,
2726 "expected 0x201a, got %x\n", pd->DelayloadDescriptor->ModuleHandleRVA);
2727 ok(pd->DelayloadDescriptor->ImportAddressTableRVA > pd->DelayloadDescriptor->ModuleHandleRVA,
2728 "expected %x > %x\n", pd->DelayloadDescriptor->ImportAddressTableRVA,
2729 pd->DelayloadDescriptor->ModuleHandleRVA);
2730 ok(pd->DelayloadDescriptor->ImportNameTableRVA > pd->DelayloadDescriptor->ImportAddressTableRVA,
2731 "expected %x > %x\n", pd->DelayloadDescriptor->ImportNameTableRVA,
2732 pd->DelayloadDescriptor->ImportAddressTableRVA);
2733 ok(pd->DelayloadDescriptor->BoundImportAddressTableRVA == 0,
2734 "expected 0, got %x\n", pd->DelayloadDescriptor->BoundImportAddressTableRVA);
2735 ok(pd->DelayloadDescriptor->UnloadInformationTableRVA == 0,
2736 "expected 0, got %x\n", pd->DelayloadDescriptor->UnloadInformationTableRVA);
2737 ok(pd->DelayloadDescriptor->TimeDateStamp == 0,
2738 "expected 0, got %x\n", pd->DelayloadDescriptor->TimeDateStamp);
2741 ok(!!pd->ThunkAddress, "no ThunkAddress supplied\n");
2742 if (pd->ThunkAddress)
2743 ok(pd->ThunkAddress->u1.Ordinal, "no ThunkAddress value supplied\n");
2745 ok(!!pd->TargetDllName, "no TargetDllName supplied\n");
2746 if (pd->TargetDllName)
2747 ok(!strcmp(pd->TargetDllName, "secur32.dll"),
2748 "expected \"secur32.dll\", got \"%s\"\n", pd->TargetDllName);
2750 ok(pd->TargetApiDescriptor.ImportDescribedByName == 0,
2751 "expected 0, got %x\n", pd->TargetApiDescriptor.ImportDescribedByName);
2752 ok(pd->TargetApiDescriptor.Description.Ordinal == 0 ||
2753 pd->TargetApiDescriptor.Description.Ordinal == 999,
2754 "expected 0, got %x\n", pd->TargetApiDescriptor.Description.Ordinal);
2756 ok(!!pd->TargetModuleBase, "no TargetModuleBase supplied\n");
2757 ok(pd->Unused == NULL, "expected NULL, got %p\n", pd->Unused);
2758 ok(pd->LastError, "no LastError supplied\n");
2760 cb_count++;
2761 return (void*)0xdeadbeef;
2764 static void test_ResolveDelayLoadedAPI(void)
2766 static const char test_dll[] = "secur32.dll";
2767 static const char test_func[] = "SealMessage";
2768 char temp_path[MAX_PATH];
2769 char dll_name[MAX_PATH];
2770 IMAGE_DELAYLOAD_DESCRIPTOR idd, *delaydir;
2771 IMAGE_THUNK_DATA itd32;
2772 HANDLE hfile;
2773 HMODULE hlib;
2774 DWORD dummy, file_size, i;
2775 WORD hint = 0;
2776 BOOL ret;
2777 IMAGE_NT_HEADERS nt_header;
2779 static const struct test_data
2781 BOOL func;
2782 UINT_PTR ordinal;
2783 BOOL succeeds;
2784 } td[] =
2787 TRUE, 0, TRUE
2790 FALSE, IMAGE_ORDINAL_FLAG | 2, TRUE
2793 FALSE, IMAGE_ORDINAL_FLAG | 5, TRUE
2796 FALSE, IMAGE_ORDINAL_FLAG | 0, FALSE
2799 FALSE, IMAGE_ORDINAL_FLAG | 999, FALSE
2803 if (!pResolveDelayLoadedAPI)
2805 win_skip("ResolveDelayLoadedAPI is not available\n");
2806 return;
2809 if (0) /* crashes on native */
2811 SetLastError(0xdeadbeef);
2812 ok(!pResolveDelayLoadedAPI(NULL, NULL, NULL, NULL, NULL, 0),
2813 "ResolveDelayLoadedAPI succeeded\n");
2814 ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %x\n", GetLastError());
2816 cb_count = 0;
2817 SetLastError(0xdeadbeef);
2818 ok(!pResolveDelayLoadedAPI(NULL, NULL, failuredllhook, NULL, NULL, 0),
2819 "ResolveDelayLoadedAPI succeeded\n");
2820 ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %x\n", GetLastError());
2821 ok(cb_count == 1, "Wrong callback count: %d\n", cb_count);
2824 GetTempPathA(MAX_PATH, temp_path);
2825 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
2826 trace("creating %s\n", dll_name);
2827 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2828 if (hfile == INVALID_HANDLE_VALUE)
2830 ok(0, "could not create %s\n", dll_name);
2831 return;
2834 SetLastError(0xdeadbeef);
2835 ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
2836 ok(ret, "WriteFile error %d\n", GetLastError());
2838 nt_header = nt_header_template;
2839 nt_header.FileHeader.NumberOfSections = 2;
2840 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
2842 nt_header.OptionalHeader.SectionAlignment = 0x1000;
2843 nt_header.OptionalHeader.FileAlignment = 0x1000;
2844 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x2200;
2845 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + 2 * sizeof(IMAGE_SECTION_HEADER);
2846 nt_header.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
2847 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress = 0x1000;
2848 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size = 0x100;
2850 SetLastError(0xdeadbeef);
2851 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
2852 ok(ret, "WriteFile error %d\n", GetLastError());
2854 SetLastError(0xdeadbeef);
2855 ret = WriteFile(hfile, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
2856 ok(ret, "WriteFile error %d\n", GetLastError());
2858 /* sections */
2859 section.PointerToRawData = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
2860 section.VirtualAddress = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
2861 section.Misc.VirtualSize = 2 * sizeof(idd);
2862 section.SizeOfRawData = section.Misc.VirtualSize;
2863 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
2864 SetLastError(0xdeadbeef);
2865 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
2866 ok(ret, "WriteFile error %d\n", GetLastError());
2868 section.PointerToRawData = 0x2000;
2869 section.VirtualAddress = 0x2000;
2870 i = sizeof(td)/sizeof(td[0]);
2871 section.Misc.VirtualSize = sizeof(test_dll) + sizeof(hint) + sizeof(test_func) + sizeof(HMODULE) +
2872 2 * (i + 1) * sizeof(IMAGE_THUNK_DATA);
2873 ok(section.Misc.VirtualSize <= 0x1000, "Too much tests, add a new section!\n");
2874 section.SizeOfRawData = section.Misc.VirtualSize;
2875 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
2876 SetLastError(0xdeadbeef);
2877 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
2878 ok(ret, "WriteFile error %d\n", GetLastError());
2880 /* fill up to delay data */
2881 SetFilePointer( hfile, nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress, NULL, SEEK_SET );
2883 /* delay data */
2884 idd.Attributes.AllAttributes = 1;
2885 idd.DllNameRVA = 0x2000;
2886 idd.ModuleHandleRVA = idd.DllNameRVA + sizeof(test_dll) + sizeof(hint) + sizeof(test_func);
2887 idd.ImportAddressTableRVA = idd.ModuleHandleRVA + sizeof(HMODULE);
2888 idd.ImportNameTableRVA = idd.ImportAddressTableRVA + (i + 1) * sizeof(IMAGE_THUNK_DATA);
2889 idd.BoundImportAddressTableRVA = 0;
2890 idd.UnloadInformationTableRVA = 0;
2891 idd.TimeDateStamp = 0;
2893 SetLastError(0xdeadbeef);
2894 ret = WriteFile(hfile, &idd, sizeof(idd), &dummy, NULL);
2895 ok(ret, "WriteFile error %d\n", GetLastError());
2897 SetLastError(0xdeadbeef);
2898 ret = WriteFile(hfile, filler, sizeof(idd), &dummy, NULL);
2899 ok(ret, "WriteFile error %d\n", GetLastError());
2901 /* fill up to extended delay data */
2902 SetFilePointer( hfile, idd.DllNameRVA, NULL, SEEK_SET );
2904 /* extended delay data */
2905 SetLastError(0xdeadbeef);
2906 ret = WriteFile(hfile, test_dll, sizeof(test_dll), &dummy, NULL);
2907 ok(ret, "WriteFile error %d\n", GetLastError());
2909 SetLastError(0xdeadbeef);
2910 ret = WriteFile(hfile, &hint, sizeof(hint), &dummy, NULL);
2911 ok(ret, "WriteFile error %d\n", GetLastError());
2913 SetLastError(0xdeadbeef);
2914 ret = WriteFile(hfile, test_func, sizeof(test_func), &dummy, NULL);
2915 ok(ret, "WriteFile error %d\n", GetLastError());
2917 SetFilePointer( hfile, idd.ImportAddressTableRVA, NULL, SEEK_SET );
2919 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
2921 /* 0x1a00 is an empty space between delay data and extended delay data, real thunks are not necessary */
2922 itd32.u1.Function = nt_header.OptionalHeader.ImageBase + 0x1a00 + i * 0x20;
2923 SetLastError(0xdeadbeef);
2924 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
2925 ok(ret, "WriteFile error %d\n", GetLastError());
2928 itd32.u1.Function = 0;
2929 SetLastError(0xdeadbeef);
2930 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
2931 ok(ret, "WriteFile error %d\n", GetLastError());
2933 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
2935 if (td[i].func)
2936 itd32.u1.AddressOfData = idd.DllNameRVA + sizeof(test_dll);
2937 else
2938 itd32.u1.Ordinal = td[i].ordinal;
2939 SetLastError(0xdeadbeef);
2940 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
2941 ok(ret, "WriteFile error %d\n", GetLastError());
2944 itd32.u1.Ordinal = 0;
2945 SetLastError(0xdeadbeef);
2946 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
2947 ok(ret, "WriteFile error %d\n", GetLastError());
2949 /* fill up to eof */
2950 SetFilePointer( hfile, section.VirtualAddress + section.Misc.VirtualSize, NULL, SEEK_SET );
2951 SetEndOfFile( hfile );
2952 CloseHandle(hfile);
2954 SetLastError(0xdeadbeef);
2955 hlib = LoadLibraryA(dll_name);
2956 ok(hlib != NULL, "LoadLibrary error %u\n", GetLastError());
2957 if (!hlib)
2959 skip("couldn't load %s.\n", dll_name);
2960 DeleteFileA(dll_name);
2961 return;
2964 delaydir = pRtlImageDirectoryEntryToData(hlib, TRUE, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, &file_size);
2965 if (!delaydir)
2967 skip("haven't found section for delay import directory.\n");
2968 FreeLibrary(hlib);
2969 DeleteFileA(dll_name);
2970 return;
2973 for (;;)
2975 IMAGE_THUNK_DATA *itdn, *itda;
2976 HMODULE htarget;
2978 if (!delaydir->DllNameRVA ||
2979 !delaydir->ImportAddressTableRVA ||
2980 !delaydir->ImportNameTableRVA) break;
2982 itdn = RVAToAddr(delaydir->ImportNameTableRVA, hlib);
2983 itda = RVAToAddr(delaydir->ImportAddressTableRVA, hlib);
2984 htarget = LoadLibraryA(RVAToAddr(delaydir->DllNameRVA, hlib));
2986 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
2988 void *ret, *load;
2990 if (IMAGE_SNAP_BY_ORDINAL(itdn[i].u1.Ordinal))
2991 load = (void *)GetProcAddress(htarget, (LPSTR)IMAGE_ORDINAL(itdn[i].u1.Ordinal));
2992 else
2994 const IMAGE_IMPORT_BY_NAME* iibn = RVAToAddr(itdn[i].u1.AddressOfData, hlib);
2995 load = (void *)GetProcAddress(htarget, (char*)iibn->Name);
2998 cb_count = 0;
2999 ret = pResolveDelayLoadedAPI(hlib, delaydir, failuredllhook, NULL, &itda[i], 0);
3000 if (td[i].succeeds)
3002 ok(ret != NULL, "Test %u: ResolveDelayLoadedAPI failed\n", i);
3003 ok(ret == load, "Test %u: expected %p, got %p\n", i, load, ret);
3004 ok(ret == (void*)itda[i].u1.AddressOfData, "Test %u: expected %p, got %p\n",
3005 i, ret, (void*)itda[i].u1.AddressOfData);
3006 ok(!cb_count, "Test %u: Wrong callback count: %d\n", i, cb_count);
3008 else
3010 ok(ret == (void*)0xdeadbeef, "Test %u: ResolveDelayLoadedAPI succeeded with %p\n", i, ret);
3011 ok(cb_count, "Test %u: Wrong callback count: %d\n", i, cb_count);
3014 delaydir++;
3017 FreeLibrary(hlib);
3018 trace("deleting %s\n", dll_name);
3019 DeleteFileA(dll_name);
3022 static void test_InMemoryOrderModuleList(void)
3024 PEB_LDR_DATA *ldr = NtCurrentTeb()->Peb->LdrData;
3025 LIST_ENTRY *entry1, *mark1 = &ldr->InLoadOrderModuleList;
3026 LIST_ENTRY *entry2, *mark2 = &ldr->InMemoryOrderModuleList;
3027 LDR_MODULE *module1, *module2;
3029 ok(ldr->Initialized == TRUE, "expected TRUE, got %u\n", ldr->Initialized);
3031 for (entry1 = mark1->Flink, entry2 = mark2->Flink;
3032 entry1 != mark1 && entry2 != mark2;
3033 entry1 = entry1->Flink, entry2 = entry2->Flink)
3035 module1 = CONTAINING_RECORD(entry1, LDR_MODULE, InLoadOrderModuleList);
3036 module2 = CONTAINING_RECORD(entry2, LDR_MODULE, InMemoryOrderModuleList);
3037 ok(module1 == module2, "expected module1 == module2, got %p and %p\n", module1, module2);
3039 ok(entry1 == mark1, "expected entry1 == mark1, got %p and %p\n", entry1, mark1);
3040 ok(entry2 == mark2, "expected entry2 == mark2, got %p and %p\n", entry2, mark2);
3043 START_TEST(loader)
3045 int argc;
3046 char **argv;
3047 HANDLE ntdll, mapping, kernel32;
3048 SYSTEM_INFO si;
3050 ntdll = GetModuleHandleA("ntdll.dll");
3051 kernel32 = GetModuleHandleA("kernel32.dll");
3052 pNtCreateSection = (void *)GetProcAddress(ntdll, "NtCreateSection");
3053 pNtQuerySection = (void *)GetProcAddress(ntdll, "NtQuerySection");
3054 pNtMapViewOfSection = (void *)GetProcAddress(ntdll, "NtMapViewOfSection");
3055 pNtUnmapViewOfSection = (void *)GetProcAddress(ntdll, "NtUnmapViewOfSection");
3056 pNtTerminateProcess = (void *)GetProcAddress(ntdll, "NtTerminateProcess");
3057 pNtQueryInformationProcess = (void *)GetProcAddress(ntdll, "NtQueryInformationProcess");
3058 pNtSetInformationProcess = (void *)GetProcAddress(ntdll, "NtSetInformationProcess");
3059 pLdrShutdownProcess = (void *)GetProcAddress(ntdll, "LdrShutdownProcess");
3060 pRtlDllShutdownInProgress = (void *)GetProcAddress(ntdll, "RtlDllShutdownInProgress");
3061 pNtAllocateVirtualMemory = (void *)GetProcAddress(ntdll, "NtAllocateVirtualMemory");
3062 pNtFreeVirtualMemory = (void *)GetProcAddress(ntdll, "NtFreeVirtualMemory");
3063 pLdrLockLoaderLock = (void *)GetProcAddress(ntdll, "LdrLockLoaderLock");
3064 pLdrUnlockLoaderLock = (void *)GetProcAddress(ntdll, "LdrUnlockLoaderLock");
3065 pRtlAcquirePebLock = (void *)GetProcAddress(ntdll, "RtlAcquirePebLock");
3066 pRtlReleasePebLock = (void *)GetProcAddress(ntdll, "RtlReleasePebLock");
3067 pRtlImageDirectoryEntryToData = (void *)GetProcAddress(ntdll, "RtlImageDirectoryEntryToData");
3068 pFlsAlloc = (void *)GetProcAddress(kernel32, "FlsAlloc");
3069 pFlsSetValue = (void *)GetProcAddress(kernel32, "FlsSetValue");
3070 pFlsGetValue = (void *)GetProcAddress(kernel32, "FlsGetValue");
3071 pFlsFree = (void *)GetProcAddress(kernel32, "FlsFree");
3072 pResolveDelayLoadedAPI = (void *)GetProcAddress(kernel32, "ResolveDelayLoadedAPI");
3074 GetSystemInfo( &si );
3075 page_size = si.dwPageSize;
3076 dos_header.e_magic = IMAGE_DOS_SIGNATURE;
3077 dos_header.e_lfanew = sizeof(dos_header);
3079 mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_loader");
3080 ok(mapping != 0, "CreateFileMapping failed\n");
3081 child_failures = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 4096);
3082 if (*child_failures == -1)
3084 *child_failures = 0;
3086 else
3087 *child_failures = -1;
3089 argc = winetest_get_mainargs(&argv);
3090 if (argc > 4)
3092 test_dll_phase = atoi(argv[4]);
3093 child_process(argv[2], atol(argv[3]));
3094 return;
3097 test_Loader();
3098 test_ResolveDelayLoadedAPI();
3099 test_ImportDescriptors();
3100 test_section_access();
3101 test_import_resolution();
3102 test_ExitProcess();
3103 test_InMemoryOrderModuleList();