[KERNEL32_WINETEST] Add a PCH.
[reactos.git] / modules / rostests / winetests / kernel32 / loader.c
1 /*
2 * Unit test suite for the PE loader.
3 *
4 * Copyright 2006,2011 Dmitry Timoshkov
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "precomp.h"
22
23 #include <delayloadhandler.h>
24
25 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
26 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
27
28 #define ALIGN_SIZE(size, alignment) (((size) + (alignment - 1)) & ~((alignment - 1)))
29
30 struct PROCESS_BASIC_INFORMATION_PRIVATE
31 {
32 DWORD_PTR ExitStatus;
33 PPEB PebBaseAddress;
34 DWORD_PTR AffinityMask;
35 DWORD_PTR BasePriority;
36 ULONG_PTR UniqueProcessId;
37 ULONG_PTR InheritedFromUniqueProcessId;
38 };
39
40 static LONG *child_failures;
41 static WORD cb_count;
42 static DWORD page_size;
43
44 static NTSTATUS (WINAPI *pNtCreateSection)(HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *,
45 const LARGE_INTEGER *, ULONG, ULONG, HANDLE );
46 static NTSTATUS (WINAPI *pNtQuerySection)(HANDLE, SECTION_INFORMATION_CLASS, void *, ULONG, ULONG *);
47 static NTSTATUS (WINAPI *pNtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG, SIZE_T, const LARGE_INTEGER *, SIZE_T *, ULONG, ULONG, ULONG);
48 static NTSTATUS (WINAPI *pNtUnmapViewOfSection)(HANDLE, PVOID);
49 static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
50 static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
51 static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE, DWORD);
52 static void (WINAPI *pLdrShutdownProcess)(void);
53 static BOOLEAN (WINAPI *pRtlDllShutdownInProgress)(void);
54 static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG, SIZE_T *, ULONG, ULONG);
55 static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG);
56 static NTSTATUS (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG *, ULONG_PTR *);
57 static NTSTATUS (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG_PTR);
58 static void (WINAPI *pRtlAcquirePebLock)(void);
59 static void (WINAPI *pRtlReleasePebLock)(void);
60 static PVOID (WINAPI *pResolveDelayLoadedAPI)(PVOID, PCIMAGE_DELAYLOAD_DESCRIPTOR,
61 PDELAYLOAD_FAILURE_DLL_CALLBACK, PVOID,
62 PIMAGE_THUNK_DATA ThunkAddress,ULONG);
63 static PVOID (WINAPI *pRtlImageDirectoryEntryToData)(HMODULE,BOOL,WORD,ULONG *);
64 static DWORD (WINAPI *pFlsAlloc)(PFLS_CALLBACK_FUNCTION);
65 static BOOL (WINAPI *pFlsSetValue)(DWORD, PVOID);
66 static PVOID (WINAPI *pFlsGetValue)(DWORD);
67 static BOOL (WINAPI *pFlsFree)(DWORD);
68
69 static PVOID RVAToAddr(DWORD_PTR rva, HMODULE module)
70 {
71 if (rva == 0)
72 return NULL;
73 return ((char*) module) + rva;
74 }
75
76 static IMAGE_DOS_HEADER dos_header;
77
78 static const IMAGE_NT_HEADERS nt_header_template =
79 {
80 IMAGE_NT_SIGNATURE, /* Signature */
81 {
82 #if defined __i386__
83 IMAGE_FILE_MACHINE_I386, /* Machine */
84 #elif defined __x86_64__
85 IMAGE_FILE_MACHINE_AMD64, /* Machine */
86 #elif defined __powerpc__
87 IMAGE_FILE_MACHINE_POWERPC, /* Machine */
88 #elif defined __arm__
89 IMAGE_FILE_MACHINE_ARMNT, /* Machine */
90 #elif defined __aarch64__
91 IMAGE_FILE_MACHINE_ARM64, /* Machine */
92 #else
93 # error You must specify the machine type
94 #endif
95 1, /* NumberOfSections */
96 0, /* TimeDateStamp */
97 0, /* PointerToSymbolTable */
98 0, /* NumberOfSymbols */
99 sizeof(IMAGE_OPTIONAL_HEADER), /* SizeOfOptionalHeader */
100 IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL /* Characteristics */
101 },
102 { IMAGE_NT_OPTIONAL_HDR_MAGIC, /* Magic */
103 1, /* MajorLinkerVersion */
104 0, /* MinorLinkerVersion */
105 0, /* SizeOfCode */
106 0, /* SizeOfInitializedData */
107 0, /* SizeOfUninitializedData */
108 0, /* AddressOfEntryPoint */
109 0x10, /* BaseOfCode, also serves as e_lfanew in the truncated MZ header */
110 #ifndef _WIN64
111 0, /* BaseOfData */
112 #endif
113 0x10000000, /* ImageBase */
114 0, /* SectionAlignment */
115 0, /* FileAlignment */
116 4, /* MajorOperatingSystemVersion */
117 0, /* MinorOperatingSystemVersion */
118 1, /* MajorImageVersion */
119 0, /* MinorImageVersion */
120 4, /* MajorSubsystemVersion */
121 0, /* MinorSubsystemVersion */
122 0, /* Win32VersionValue */
123 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000, /* SizeOfImage */
124 sizeof(dos_header) + sizeof(nt_header_template), /* SizeOfHeaders */
125 0, /* CheckSum */
126 IMAGE_SUBSYSTEM_WINDOWS_CUI, /* Subsystem */
127 0, /* DllCharacteristics */
128 0, /* SizeOfStackReserve */
129 0, /* SizeOfStackCommit */
130 0, /* SizeOfHeapReserve */
131 0, /* SizeOfHeapCommit */
132 0, /* LoaderFlags */
133 0, /* NumberOfRvaAndSizes */
134 { { 0 } } /* DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] */
135 }
136 };
137
138 static IMAGE_SECTION_HEADER section =
139 {
140 ".rodata", /* Name */
141 { 0 }, /* Misc */
142 0, /* VirtualAddress */
143 0, /* SizeOfRawData */
144 0, /* PointerToRawData */
145 0, /* PointerToRelocations */
146 0, /* PointerToLinenumbers */
147 0, /* NumberOfRelocations */
148 0, /* NumberOfLinenumbers */
149 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, /* Characteristics */
150 };
151
152
153 static const char filler[0x1000];
154 static const char section_data[0x10] = "section data";
155
156 static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size,
157 const IMAGE_NT_HEADERS *nt_header, const char *dll_name )
158 {
159 DWORD dummy, size, file_align;
160 HANDLE hfile;
161 BOOL ret;
162
163 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
164 if (hfile == INVALID_HANDLE_VALUE) return 0;
165
166 SetLastError(0xdeadbeef);
167 ret = WriteFile(hfile, dos_header, dos_size, &dummy, NULL);
168 ok(ret, "WriteFile error %d\n", GetLastError());
169
170 SetLastError(0xdeadbeef);
171 ret = WriteFile(hfile, nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
172 ok(ret, "WriteFile error %d\n", GetLastError());
173
174 if (nt_header->FileHeader.SizeOfOptionalHeader)
175 {
176 SetLastError(0xdeadbeef);
177 ret = WriteFile(hfile, &nt_header->OptionalHeader,
178 sizeof(IMAGE_OPTIONAL_HEADER),
179 &dummy, NULL);
180 ok(ret, "WriteFile error %d\n", GetLastError());
181 if (nt_header->FileHeader.SizeOfOptionalHeader > sizeof(IMAGE_OPTIONAL_HEADER))
182 {
183 file_align = nt_header->FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER);
184 assert(file_align < sizeof(filler));
185 SetLastError(0xdeadbeef);
186 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
187 ok(ret, "WriteFile error %d\n", GetLastError());
188 }
189 }
190
191 assert(nt_header->FileHeader.NumberOfSections <= 1);
192 if (nt_header->FileHeader.NumberOfSections)
193 {
194 SetFilePointer(hfile, dos_size + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + nt_header->FileHeader.SizeOfOptionalHeader, NULL, FILE_BEGIN);
195
196 section.SizeOfRawData = 10;
197
198 if (nt_header->OptionalHeader.SectionAlignment >= page_size)
199 {
200 section.PointerToRawData = dos_size;
201 section.VirtualAddress = nt_header->OptionalHeader.SectionAlignment;
202 section.Misc.VirtualSize = section.SizeOfRawData * 10;
203 }
204 else
205 {
206 section.PointerToRawData = nt_header->OptionalHeader.SizeOfHeaders;
207 section.VirtualAddress = nt_header->OptionalHeader.SizeOfHeaders;
208 section.Misc.VirtualSize = 5;
209 }
210
211 SetLastError(0xdeadbeef);
212 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
213 ok(ret, "WriteFile error %d\n", GetLastError());
214
215 /* section data */
216 SetLastError(0xdeadbeef);
217 ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
218 ok(ret, "WriteFile error %d\n", GetLastError());
219 }
220
221 /* Minimal PE image that Windows7+ is able to load: 268 bytes */
222 size = GetFileSize(hfile, NULL);
223 if (size < 268)
224 {
225 file_align = 268 - size;
226 SetLastError(0xdeadbeef);
227 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
228 ok(ret, "WriteFile error %d\n", GetLastError());
229 }
230
231 size = GetFileSize(hfile, NULL);
232 CloseHandle(hfile);
233 return size;
234 }
235
236 static void query_image_section( int id, const char *dll_name, const IMAGE_NT_HEADERS *nt_header )
237 {
238 SECTION_BASIC_INFORMATION info;
239 SECTION_IMAGE_INFORMATION image;
240 ULONG info_size = 0xdeadbeef;
241 NTSTATUS status;
242 HANDLE file, mapping;
243 ULONG file_size;
244 LARGE_INTEGER map_size;
245 /* truncated header is not handled correctly in windows <= w2k3 */
246 BOOL truncated = nt_header->FileHeader.SizeOfOptionalHeader < sizeof(nt_header->OptionalHeader);
247
248 file = CreateFileA( dll_name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE,
249 NULL, OPEN_EXISTING, 0, 0 );
250 ok( file != INVALID_HANDLE_VALUE, "%u: CreateFile error %d\n", id, GetLastError() );
251 file_size = GetFileSize( file, NULL );
252
253 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
254 NULL, NULL, PAGE_READONLY, SEC_IMAGE, file );
255 ok( !status, "%u: NtCreateSection failed err %x\n", id, status );
256 if (status)
257 {
258 CloseHandle( file );
259 return;
260 }
261 status = pNtQuerySection( mapping, SectionImageInformation, &image, sizeof(image), &info_size );
262 ok( !status, "%u: NtQuerySection failed err %x\n", id, status );
263 ok( info_size == sizeof(image), "%u: NtQuerySection wrong size %u\n", id, info_size );
264 ok( (char *)image.TransferAddress == (char *)nt_header->OptionalHeader.ImageBase + nt_header->OptionalHeader.AddressOfEntryPoint,
265 "%u: TransferAddress wrong %p / %p+%08x\n", id,
266 image.TransferAddress, (char *)nt_header->OptionalHeader.ImageBase,
267 nt_header->OptionalHeader.AddressOfEntryPoint );
268 ok( image.ZeroBits == 0, "%u: ZeroBits wrong %08x\n", id, image.ZeroBits );
269 ok( image.MaximumStackSize == nt_header->OptionalHeader.SizeOfStackReserve || broken(truncated),
270 "%u: MaximumStackSize wrong %lx / %lx\n", id,
271 image.MaximumStackSize, (SIZE_T)nt_header->OptionalHeader.SizeOfStackReserve );
272 ok( image.CommittedStackSize == nt_header->OptionalHeader.SizeOfStackCommit || broken(truncated),
273 "%u: CommittedStackSize wrong %lx / %lx\n", id,
274 image.CommittedStackSize, (SIZE_T)nt_header->OptionalHeader.SizeOfStackCommit );
275 if (truncated)
276 ok( !image.SubSystemType || broken(truncated),
277 "%u: SubSystemType wrong %08x / 00000000\n", id, image.SubSystemType );
278 else
279 ok( image.SubSystemType == nt_header->OptionalHeader.Subsystem,
280 "%u: SubSystemType wrong %08x / %08x\n", id,
281 image.SubSystemType, nt_header->OptionalHeader.Subsystem );
282 ok( image.SubsystemVersionLow == nt_header->OptionalHeader.MinorSubsystemVersion,
283 "%u: SubsystemVersionLow wrong %04x / %04x\n", id,
284 image.SubsystemVersionLow, nt_header->OptionalHeader.MinorSubsystemVersion );
285 ok( image.SubsystemVersionHigh == nt_header->OptionalHeader.MajorSubsystemVersion,
286 "%u: SubsystemVersionHigh wrong %04x / %04x\n", id,
287 image.SubsystemVersionHigh, nt_header->OptionalHeader.MajorSubsystemVersion );
288 ok( image.ImageCharacteristics == nt_header->FileHeader.Characteristics,
289 "%u: ImageCharacteristics wrong %04x / %04x\n", id,
290 image.ImageCharacteristics, nt_header->FileHeader.Characteristics );
291 ok( image.DllCharacteristics == nt_header->OptionalHeader.DllCharacteristics || broken(truncated),
292 "%u: DllCharacteristics wrong %04x / %04x\n", id,
293 image.DllCharacteristics, nt_header->OptionalHeader.DllCharacteristics );
294 ok( image.Machine == nt_header->FileHeader.Machine, "%u: Machine wrong %04x / %04x\n", id,
295 image.Machine, nt_header->FileHeader.Machine );
296 ok( image.LoaderFlags == nt_header->OptionalHeader.LoaderFlags,
297 "%u: LoaderFlags wrong %08x / %08x\n", id,
298 image.LoaderFlags, nt_header->OptionalHeader.LoaderFlags );
299 ok( image.ImageFileSize == file_size || broken(!image.ImageFileSize), /* winxpsp1 */
300 "%u: ImageFileSize wrong %08x / %08x\n", id, image.ImageFileSize, file_size );
301 ok( image.CheckSum == nt_header->OptionalHeader.CheckSum || broken(truncated),
302 "%u: CheckSum wrong %08x / %08x\n", id,
303 image.CheckSum, nt_header->OptionalHeader.CheckSum );
304 /* FIXME: needs more work: */
305 /* image.GpValue */
306 /* image.ImageFlags */
307 /* image.ImageContainsCode */
308
309 map_size.QuadPart = (nt_header->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
310 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
311 ok( !status, "NtQuerySection failed err %x\n", status );
312 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %x%08x / %x%08x\n",
313 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
314 CloseHandle( mapping );
315
316 map_size.QuadPart = (nt_header->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
317 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
318 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
319 ok( !status, "%u: NtCreateSection failed err %x\n", id, status );
320 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
321 ok( !status, "NtQuerySection failed err %x\n", status );
322 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %x%08x / %x%08x\n",
323 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
324 CloseHandle( mapping );
325
326 map_size.QuadPart++;
327 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
328 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
329 ok( status == STATUS_SECTION_TOO_BIG, "%u: NtCreateSection failed err %x\n", id, status );
330
331 SetFilePointerEx( file, map_size, NULL, FILE_BEGIN );
332 SetEndOfFile( file );
333 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
334 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
335 ok( status == STATUS_SECTION_TOO_BIG, "%u: NtCreateSection failed err %x\n", id, status );
336
337 map_size.QuadPart = 1;
338 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
339 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
340 ok( !status, "%u: NtCreateSection failed err %x\n", id, status );
341 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
342 ok( !status, "NtQuerySection failed err %x\n", status );
343 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %x%08x / %x%08x\n",
344 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
345 CloseHandle( mapping );
346
347 CloseHandle( file );
348 }
349
350 /* helper to test image section mapping */
351 static NTSTATUS map_image_section( const IMAGE_NT_HEADERS *nt_header )
352 {
353 char temp_path[MAX_PATH];
354 char dll_name[MAX_PATH];
355 LARGE_INTEGER size;
356 HANDLE file, map;
357 NTSTATUS status;
358 ULONG file_size;
359
360 GetTempPathA(MAX_PATH, temp_path);
361 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
362
363 file_size = create_test_dll( &dos_header, sizeof(dos_header), nt_header, dll_name );
364 ok( file_size, "could not create %s\n", dll_name);
365
366 file = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
367 ok(file != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError());
368
369 size.QuadPart = file_size;
370 status = pNtCreateSection(&map, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
371 NULL, &size, PAGE_READONLY, SEC_IMAGE, file );
372 if (!status)
373 {
374 SECTION_BASIC_INFORMATION info;
375 ULONG info_size = 0xdeadbeef;
376 NTSTATUS ret = pNtQuerySection( map, SectionBasicInformation, &info, sizeof(info), &info_size );
377 ok( !ret, "NtQuerySection failed err %x\n", ret );
378 ok( info_size == sizeof(info), "NtQuerySection wrong size %u\n", info_size );
379 ok( info.Attributes == (SEC_IMAGE | SEC_FILE), "NtQuerySection wrong attr %x\n", info.Attributes );
380 ok( info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", info.BaseAddress );
381 ok( info.Size.QuadPart == file_size, "NtQuerySection wrong size %x%08x / %08x\n",
382 info.Size.u.HighPart, info.Size.u.LowPart, file_size );
383 query_image_section( 1000, dll_name, nt_header );
384 }
385 if (map) CloseHandle( map );
386 CloseHandle( file );
387 DeleteFileA( dll_name );
388 return status;
389 }
390
391
392 static void test_Loader(void)
393 {
394 static const struct test_data
395 {
396 DWORD size_of_dos_header;
397 WORD number_of_sections, size_of_optional_header;
398 DWORD section_alignment, file_alignment;
399 DWORD size_of_image, size_of_headers;
400 DWORD errors[4]; /* 0 means LoadLibrary should succeed */
401 } td[] =
402 {
403 { sizeof(dos_header),
404 1, 0, 0, 0, 0, 0,
405 { ERROR_BAD_EXE_FORMAT }
406 },
407 { sizeof(dos_header),
408 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
409 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0xe00,
410 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
411 { ERROR_BAD_EXE_FORMAT } /* XP doesn't like too small image size */
412 },
413 { sizeof(dos_header),
414 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
415 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
416 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
417 { ERROR_SUCCESS }
418 },
419 { sizeof(dos_header),
420 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
421 0x1f00,
422 0x1000,
423 { ERROR_SUCCESS }
424 },
425 { sizeof(dos_header),
426 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x200,
427 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x200,
428 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
429 { ERROR_SUCCESS, ERROR_INVALID_ADDRESS } /* vista is more strict */
430 },
431 { sizeof(dos_header),
432 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x1000,
433 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
434 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
435 { ERROR_BAD_EXE_FORMAT } /* XP doesn't like alignments */
436 },
437 { sizeof(dos_header),
438 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
439 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
440 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
441 { ERROR_SUCCESS }
442 },
443 { sizeof(dos_header),
444 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
445 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
446 0x200,
447 { ERROR_SUCCESS }
448 },
449 /* Mandatory are all fields up to SizeOfHeaders, everything else
450 * is really optional (at least that's true for XP).
451 */
452 #if 0 /* 32-bit Windows 8 crashes inside of LoadLibrary */
453 { sizeof(dos_header),
454 1, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
455 sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER) + 0x10,
456 sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER),
457 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT, ERROR_INVALID_ADDRESS,
458 ERROR_NOACCESS }
459 },
460 #endif
461 { sizeof(dos_header),
462 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
463 0xd0, /* beyond of the end of file */
464 0xc0, /* beyond of the end of file */
465 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
466 },
467 { sizeof(dos_header),
468 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
469 0x1000,
470 0,
471 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
472 },
473 { sizeof(dos_header),
474 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
475 1,
476 0,
477 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
478 },
479 #if 0 /* not power of 2 alignments need more test cases */
480 { sizeof(dos_header),
481 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x300, 0x300,
482 1,
483 0,
484 { ERROR_BAD_EXE_FORMAT } /* alignment is not power of 2 */
485 },
486 #endif
487 { sizeof(dos_header),
488 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 4, 4,
489 1,
490 0,
491 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
492 },
493 { sizeof(dos_header),
494 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 1, 1,
495 1,
496 0,
497 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
498 },
499 { sizeof(dos_header),
500 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
501 0,
502 0,
503 { ERROR_BAD_EXE_FORMAT } /* image size == 0 -> failure */
504 },
505 /* the following data mimics the PE image which upack creates */
506 { 0x10,
507 1, 0x148, 0x1000, 0x200,
508 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
509 0x200,
510 { ERROR_SUCCESS }
511 },
512 /* Minimal PE image that XP is able to load: 92 bytes */
513 { 0x04,
514 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum),
515 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
516 1,
517 0,
518 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
519 },
520 /* Minimal PE image that Windows7 is able to load: 268 bytes */
521 { 0x04,
522 0, 0xf0, /* optional header size just forces 0xf0 bytes to be written,
523 0 or another number don't change the behaviour, what really
524 matters is file size regardless of values in the headers */
525 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
526 0x40, /* minimal image size that Windows7 accepts */
527 0,
528 { ERROR_SUCCESS }
529 },
530 /* the following data mimics the PE image which 8k demos have */
531 { 0x04,
532 0, 0x08,
533 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
534 0x200000,
535 0x40,
536 { ERROR_SUCCESS }
537 }
538 };
539 int i;
540 DWORD file_size;
541 HANDLE h;
542 HMODULE hlib, hlib_as_data_file;
543 char temp_path[MAX_PATH];
544 char dll_name[MAX_PATH];
545 SIZE_T size;
546 BOOL ret;
547 NTSTATUS status;
548 WORD orig_machine = nt_header_template.FileHeader.Machine;
549 IMAGE_NT_HEADERS nt_header;
550
551 /* prevent displaying of the "Unable to load this DLL" message box */
552 SetErrorMode(SEM_FAILCRITICALERRORS);
553
554 GetTempPathA(MAX_PATH, temp_path);
555
556 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
557 {
558 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
559
560 nt_header = nt_header_template;
561 nt_header.FileHeader.NumberOfSections = td[i].number_of_sections;
562 nt_header.FileHeader.SizeOfOptionalHeader = td[i].size_of_optional_header;
563
564 nt_header.OptionalHeader.SectionAlignment = td[i].section_alignment;
565 nt_header.OptionalHeader.FileAlignment = td[i].file_alignment;
566 nt_header.OptionalHeader.SizeOfImage = td[i].size_of_image;
567 nt_header.OptionalHeader.SizeOfHeaders = td[i].size_of_headers;
568
569 file_size = create_test_dll( &dos_header, td[i].size_of_dos_header, &nt_header, dll_name );
570 if (!file_size)
571 {
572 ok(0, "could not create %s\n", dll_name);
573 break;
574 }
575
576 SetLastError(0xdeadbeef);
577 hlib = LoadLibraryA(dll_name);
578 if (hlib)
579 {
580 MEMORY_BASIC_INFORMATION info;
581 void *ptr;
582
583 ok( td[i].errors[0] == ERROR_SUCCESS, "%d: should have failed\n", i );
584
585 SetLastError(0xdeadbeef);
586 size = VirtualQuery(hlib, &info, sizeof(info));
587 ok(size == sizeof(info),
588 "%d: VirtualQuery error %d\n", i, GetLastError());
589 ok(info.BaseAddress == hlib, "%d: %p != %p\n", i, info.BaseAddress, hlib);
590 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
591 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
592 ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %lx != expected %x\n",
593 i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
594 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
595 if (nt_header.OptionalHeader.SectionAlignment < page_size)
596 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
597 else
598 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
599 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
600
601 SetLastError(0xdeadbeef);
602 ptr = VirtualAlloc(hlib, page_size, MEM_COMMIT, info.Protect);
603 ok(!ptr, "%d: VirtualAlloc should fail\n", i);
604 /* FIXME: Remove once Wine is fixed */
605 todo_wine_if (info.Protect == PAGE_WRITECOPY || info.Protect == PAGE_EXECUTE_WRITECOPY)
606 ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError());
607
608 SetLastError(0xdeadbeef);
609 size = VirtualQuery((char *)hlib + info.RegionSize, &info, sizeof(info));
610 ok(size == sizeof(info),
611 "%d: VirtualQuery error %d\n", i, GetLastError());
612 if (nt_header.OptionalHeader.SectionAlignment == page_size ||
613 nt_header.OptionalHeader.SectionAlignment == nt_header.OptionalHeader.FileAlignment)
614 {
615 ok(info.BaseAddress == (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %p != expected %p\n",
616 i, info.BaseAddress, (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
617 ok(info.AllocationBase == 0, "%d: %p != 0\n", i, info.AllocationBase);
618 ok(info.AllocationProtect == 0, "%d: %x != 0\n", i, info.AllocationProtect);
619 /*ok(info.RegionSize == not_practical_value, "%d: %lx != not_practical_value\n", i, info.RegionSize);*/
620 ok(info.State == MEM_FREE, "%d: %x != MEM_FREE\n", i, info.State);
621 ok(info.Type == 0, "%d: %x != 0\n", i, info.Type);
622 ok(info.Protect == PAGE_NOACCESS, "%d: %x != PAGE_NOACCESS\n", i, info.Protect);
623 }
624 else
625 {
626 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
627 ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib);
628 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
629 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
630 ok(info.RegionSize == ALIGN_SIZE(file_size, page_size), "%d: got %lx != expected %x\n",
631 i, info.RegionSize, ALIGN_SIZE(file_size, page_size));
632 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
633 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
634 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
635 }
636
637 /* header: check the zeroing of alignment */
638 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
639 {
640 const char *start;
641
642 start = (const char *)hlib + nt_header.OptionalHeader.SizeOfHeaders;
643 size = ALIGN_SIZE((ULONG_PTR)start, page_size) - (ULONG_PTR)start;
644 ok(!memcmp(start, filler, size), "%d: header alignment is not cleared\n", i);
645 }
646
647 if (nt_header.FileHeader.NumberOfSections)
648 {
649 SetLastError(0xdeadbeef);
650 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
651 ok(size == sizeof(info),
652 "%d: VirtualQuery error %d\n", i, GetLastError());
653 if (nt_header.OptionalHeader.SectionAlignment < page_size)
654 {
655 ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib);
656 ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "%d: got %lx != expected %x\n",
657 i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
658 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect);
659 }
660 else
661 {
662 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
663 ok(info.RegionSize == ALIGN_SIZE(section.Misc.VirtualSize, page_size), "%d: got %lx != expected %x\n",
664 i, info.RegionSize, ALIGN_SIZE(section.Misc.VirtualSize, page_size));
665 ok(info.Protect == PAGE_READONLY, "%d: %x != PAGE_READONLY\n", i, info.Protect);
666 }
667 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
668 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
669 ok(info.State == MEM_COMMIT, "%d: %x != MEM_COMMIT\n", i, info.State);
670 ok(info.Type == SEC_IMAGE, "%d: %x != SEC_IMAGE\n", i, info.Type);
671
672 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
673 ok(!memcmp((const char *)hlib + section.VirtualAddress + section.PointerToRawData, &nt_header, section.SizeOfRawData), "wrong section data\n");
674 else
675 ok(!memcmp((const char *)hlib + section.PointerToRawData, section_data, section.SizeOfRawData), "wrong section data\n");
676
677 /* check the zeroing of alignment */
678 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
679 {
680 const char *start;
681
682 start = (const char *)hlib + section.VirtualAddress + section.PointerToRawData + section.SizeOfRawData;
683 size = ALIGN_SIZE((ULONG_PTR)start, page_size) - (ULONG_PTR)start;
684 ok(memcmp(start, filler, size), "%d: alignment should not be cleared\n", i);
685 }
686
687 SetLastError(0xdeadbeef);
688 ptr = VirtualAlloc((char *)hlib + section.VirtualAddress, page_size, MEM_COMMIT, info.Protect);
689 ok(!ptr, "%d: VirtualAlloc should fail\n", i);
690 /* FIXME: Remove once Wine is fixed */
691 todo_wine_if (info.Protect == PAGE_WRITECOPY || info.Protect == PAGE_EXECUTE_WRITECOPY)
692 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_INVALID_ADDRESS,
693 "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError());
694 }
695
696 SetLastError(0xdeadbeef);
697 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
698 ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
699 ok(hlib_as_data_file == hlib, "hlib_as_file and hlib are different\n");
700
701 SetLastError(0xdeadbeef);
702 ret = FreeLibrary(hlib);
703 ok(ret, "FreeLibrary error %d\n", GetLastError());
704
705 SetLastError(0xdeadbeef);
706 hlib = GetModuleHandleA(dll_name);
707 ok(hlib != 0, "GetModuleHandle error %u\n", GetLastError());
708
709 SetLastError(0xdeadbeef);
710 ret = FreeLibrary(hlib_as_data_file);
711 ok(ret, "FreeLibrary error %d\n", GetLastError());
712
713 hlib = GetModuleHandleA(dll_name);
714 ok(!hlib, "GetModuleHandle should fail\n");
715
716 SetLastError(0xdeadbeef);
717 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
718 ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
719 ok((ULONG_PTR)hlib_as_data_file & 1, "hlib_as_data_file is even\n");
720
721 hlib = GetModuleHandleA(dll_name);
722 ok(!hlib, "GetModuleHandle should fail\n");
723
724 SetLastError(0xdeadbeef);
725 h = CreateFileA( dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
726 ok( h != INVALID_HANDLE_VALUE, "open failed err %u\n", GetLastError() );
727 CloseHandle( h );
728
729 SetLastError(0xdeadbeef);
730 ret = FreeLibrary(hlib_as_data_file);
731 ok(ret, "FreeLibrary error %d\n", GetLastError());
732
733 SetLastError(0xdeadbeef);
734 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE);
735 if (!((ULONG_PTR)hlib_as_data_file & 1) || /* winxp */
736 (!hlib_as_data_file && GetLastError() == ERROR_INVALID_PARAMETER)) /* w2k3 */
737 {
738 win_skip( "LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE not supported\n" );
739 FreeLibrary(hlib_as_data_file);
740 }
741 else
742 {
743 ok(hlib_as_data_file != 0, "LoadLibraryEx error %u\n", GetLastError());
744
745 SetLastError(0xdeadbeef);
746 h = CreateFileA( dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
747 todo_wine ok( h == INVALID_HANDLE_VALUE, "open succeeded\n" );
748 todo_wine ok( GetLastError() == ERROR_SHARING_VIOLATION, "wrong error %u\n", GetLastError() );
749 CloseHandle( h );
750
751 SetLastError(0xdeadbeef);
752 ret = FreeLibrary(hlib_as_data_file);
753 ok(ret, "FreeLibrary error %d\n", GetLastError());
754 }
755
756 SetLastError(0xdeadbeef);
757 ret = DeleteFileA(dll_name);
758 ok(ret, "DeleteFile error %d\n", GetLastError());
759
760 nt_header.OptionalHeader.AddressOfEntryPoint = 0x12345678;
761 file_size = create_test_dll( &dos_header, td[i].size_of_dos_header, &nt_header, dll_name );
762 if (!file_size)
763 {
764 ok(0, "could not create %s\n", dll_name);
765 break;
766 }
767 query_image_section( i, dll_name, &nt_header );
768 }
769 else
770 {
771 BOOL error_match;
772 int error_index;
773
774 error_match = FALSE;
775 for (error_index = 0;
776 ! error_match && error_index < sizeof(td[i].errors) / sizeof(DWORD);
777 error_index++)
778 {
779 error_match = td[i].errors[error_index] == GetLastError();
780 }
781 ok(error_match, "%d: unexpected error %d\n", i, GetLastError());
782 }
783
784 SetLastError(0xdeadbeef);
785 ret = DeleteFileA(dll_name);
786 ok(ret, "DeleteFile error %d\n", GetLastError());
787 }
788
789 nt_header = nt_header_template;
790 nt_header.FileHeader.NumberOfSections = 1;
791 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
792
793 nt_header.OptionalHeader.SectionAlignment = page_size;
794 nt_header.OptionalHeader.AddressOfEntryPoint = 0x1234;
795 nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
796 nt_header.OptionalHeader.FileAlignment = page_size;
797 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
798 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
799
800 status = map_image_section( &nt_header );
801 ok( status == STATUS_SUCCESS, "NtCreateSection error %08x\n", status );
802
803 dos_header.e_magic = 0;
804 status = map_image_section( &nt_header );
805 ok( status == STATUS_INVALID_IMAGE_NOT_MZ, "NtCreateSection error %08x\n", status );
806
807 dos_header.e_magic = IMAGE_DOS_SIGNATURE;
808 nt_header.Signature = IMAGE_OS2_SIGNATURE;
809 status = map_image_section( &nt_header );
810 ok( status == STATUS_INVALID_IMAGE_NE_FORMAT, "NtCreateSection error %08x\n", status );
811
812 nt_header.Signature = 0xdeadbeef;
813 status = map_image_section( &nt_header );
814 ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection error %08x\n", status );
815
816 nt_header.Signature = IMAGE_NT_SIGNATURE;
817 nt_header.OptionalHeader.Magic = 0xdead;
818 status = map_image_section( &nt_header );
819 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08x\n", status );
820
821 nt_header.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC;
822 nt_header.FileHeader.Machine = 0xdead;
823 status = map_image_section( &nt_header );
824 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
825 "NtCreateSection error %08x\n", status );
826
827 nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_UNKNOWN;
828 status = map_image_section( &nt_header );
829 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
830 "NtCreateSection error %08x\n", status );
831
832 switch (orig_machine)
833 {
834 case IMAGE_FILE_MACHINE_I386: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64; break;
835 case IMAGE_FILE_MACHINE_AMD64: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_I386; break;
836 case IMAGE_FILE_MACHINE_ARMNT: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_ARM64; break;
837 case IMAGE_FILE_MACHINE_ARM64: nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_ARMNT; break;
838 }
839 status = map_image_section( &nt_header );
840 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(status == STATUS_SUCCESS), /* win2k */
841 "NtCreateSection error %08x\n", status );
842
843 if (nt_header.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
844 {
845 IMAGE_NT_HEADERS64 nt64;
846
847 memset( &nt64, 0, sizeof(nt64) );
848 nt64.Signature = IMAGE_NT_SIGNATURE;
849 nt64.FileHeader.Machine = orig_machine;
850 nt64.FileHeader.NumberOfSections = 1;
851 nt64.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
852 nt64.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
853 nt64.OptionalHeader.MajorLinkerVersion = 1;
854 nt64.OptionalHeader.ImageBase = 0x10000000;
855 nt64.OptionalHeader.MajorOperatingSystemVersion = 4;
856 nt64.OptionalHeader.MajorImageVersion = 1;
857 nt64.OptionalHeader.MajorSubsystemVersion = 4;
858 nt64.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt64) + sizeof(IMAGE_SECTION_HEADER);
859 nt64.OptionalHeader.SizeOfImage = nt64.OptionalHeader.SizeOfHeaders + 0x1000;
860 nt64.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
861 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64 );
862 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08x\n", status );
863 }
864 else
865 {
866 IMAGE_NT_HEADERS32 nt32;
867
868 memset( &nt32, 0, sizeof(nt32) );
869 nt32.Signature = IMAGE_NT_SIGNATURE;
870 nt32.FileHeader.Machine = orig_machine;
871 nt32.FileHeader.NumberOfSections = 1;
872 nt32.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32);
873 nt32.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
874 nt32.OptionalHeader.MajorLinkerVersion = 1;
875 nt32.OptionalHeader.ImageBase = 0x10000000;
876 nt32.OptionalHeader.MajorOperatingSystemVersion = 4;
877 nt32.OptionalHeader.MajorImageVersion = 1;
878 nt32.OptionalHeader.MajorSubsystemVersion = 4;
879 nt32.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt32) + sizeof(IMAGE_SECTION_HEADER);
880 nt32.OptionalHeader.SizeOfImage = nt32.OptionalHeader.SizeOfHeaders + 0x1000;
881 nt32.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
882 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32 );
883 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08x\n", status );
884 }
885
886 nt_header.FileHeader.Machine = orig_machine; /* restore it for the next tests */
887 }
888
889 static void test_FakeDLL(void)
890 {
891 #if defined(__i386__) || defined(__x86_64__)
892 NTSTATUS (WINAPI *pNtSetEvent)(HANDLE, ULONG *) = NULL;
893 IMAGE_EXPORT_DIRECTORY *dir;
894 HMODULE module = GetModuleHandleA("ntdll.dll");
895 HANDLE file, map, event;
896 WCHAR path[MAX_PATH];
897 DWORD *names, *funcs;
898 WORD *ordinals;
899 ULONG size;
900 void *ptr;
901 int i;
902
903 GetModuleFileNameW(module, path, MAX_PATH);
904
905 file = CreateFileW(path, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
906 ok(file != INVALID_HANDLE_VALUE, "Failed to open %s (error %u)\n", wine_dbgstr_w(path), GetLastError());
907
908 map = CreateFileMappingW(file, NULL, PAGE_EXECUTE_READ | SEC_IMAGE, 0, 0, NULL);
909 ok(map != NULL, "CreateFileMapping failed with error %u\n", GetLastError());
910 ptr = MapViewOfFile(map, FILE_MAP_READ | FILE_MAP_EXECUTE, 0, 0, 0);
911 ok(ptr != NULL, "MapViewOfFile failed with error %u\n", GetLastError());
912
913 dir = RtlImageDirectoryEntryToData(ptr, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size);
914 ok(dir != NULL, "RtlImageDirectoryEntryToData failed\n");
915
916 names = RVAToAddr(dir->AddressOfNames, ptr);
917 ordinals = RVAToAddr(dir->AddressOfNameOrdinals, ptr);
918 funcs = RVAToAddr(dir->AddressOfFunctions, ptr);
919 ok(dir->NumberOfNames > 0, "Could not find any exported functions\n");
920
921 for (i = 0; i < dir->NumberOfNames; i++)
922 {
923 DWORD map_rva, dll_rva, map_offset, dll_offset;
924 char *func_name = RVAToAddr(names[i], ptr);
925 BYTE *dll_func, *map_func;
926
927 /* check only Nt functions for now */
928 if (strncmp(func_name, "Zw", 2) && strncmp(func_name, "Nt", 2))
929 continue;
930
931 dll_func = (BYTE *)GetProcAddress(module, func_name);
932 ok(dll_func != NULL, "%s: GetProcAddress returned NULL\n", func_name);
933 #if defined(__i386__)
934 if (dll_func[0] == 0x90 && dll_func[1] == 0x90 &&
935 dll_func[2] == 0x90 && dll_func[3] == 0x90)
936 #elif defined(__x86_64__)
937 if (dll_func[0] == 0x48 && dll_func[1] == 0x83 &&
938 dll_func[2] == 0xec && dll_func[3] == 0x08)
939 #endif
940 {
941 todo_wine ok(0, "%s: Export is a stub-function, skipping\n", func_name);
942 continue;
943 }
944
945 /* check position in memory */
946 dll_rva = (DWORD_PTR)dll_func - (DWORD_PTR)module;
947 map_rva = funcs[ordinals[i]];
948 ok(map_rva == dll_rva, "%s: Rva of mapped function (0x%x) does not match dll (0x%x)\n",
949 func_name, dll_rva, map_rva);
950
951 /* check position in file */
952 map_offset = (DWORD_PTR)RtlImageRvaToVa(RtlImageNtHeader(ptr), ptr, map_rva, NULL) - (DWORD_PTR)ptr;
953 dll_offset = (DWORD_PTR)RtlImageRvaToVa(RtlImageNtHeader(module), module, dll_rva, NULL) - (DWORD_PTR)module;
954 ok(map_offset == dll_offset, "%s: File offset of mapped function (0x%x) does not match dll (0x%x)\n",
955 func_name, map_offset, dll_offset);
956
957 /* check function content */
958 map_func = RVAToAddr(map_rva, ptr);
959 ok(!memcmp(map_func, dll_func, 0x20), "%s: Function content does not match!\n", func_name);
960
961 if (!strcmp(func_name, "NtSetEvent"))
962 pNtSetEvent = (void *)map_func;
963 }
964
965 ok(pNtSetEvent != NULL, "Could not find NtSetEvent export\n");
966 if (pNtSetEvent)
967 {
968 event = CreateEventA(NULL, TRUE, FALSE, NULL);
969 ok(event != NULL, "CreateEvent failed with error %u\n", GetLastError());
970 pNtSetEvent(event, 0);
971 ok(WaitForSingleObject(event, 0) == WAIT_OBJECT_0, "Event was not signaled\n");
972 pNtSetEvent(event, 0);
973 ok(WaitForSingleObject(event, 0) == WAIT_OBJECT_0, "Event was not signaled\n");
974 CloseHandle(event);
975 }
976
977 UnmapViewOfFile(ptr);
978 CloseHandle(map);
979 CloseHandle(file);
980 #endif
981 }
982
983 /* Verify linking style of import descriptors */
984 static void test_ImportDescriptors(void)
985 {
986 HMODULE kernel32_module = NULL;
987 PIMAGE_DOS_HEADER d_header;
988 PIMAGE_NT_HEADERS nt_headers;
989 DWORD import_dir_size;
990 DWORD_PTR dir_offset;
991 PIMAGE_IMPORT_DESCRIPTOR import_chunk;
992
993 /* Load kernel32 module */
994 kernel32_module = GetModuleHandleA("kernel32.dll");
995 assert( kernel32_module != NULL );
996
997 /* Get PE header info from module image */
998 d_header = (PIMAGE_DOS_HEADER) kernel32_module;
999 nt_headers = (PIMAGE_NT_HEADERS) (((char*) d_header) +
1000 d_header->e_lfanew);
1001
1002 /* Get size of import entry directory */
1003 import_dir_size = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
1004 if (!import_dir_size)
1005 {
1006 skip("Unable to continue testing due to missing import directory.\n");
1007 return;
1008 }
1009
1010 /* Get address of first import chunk */
1011 dir_offset = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
1012 import_chunk = RVAToAddr(dir_offset, kernel32_module);
1013 ok(import_chunk != 0, "Invalid import_chunk: %p\n", import_chunk);
1014 if (!import_chunk) return;
1015
1016 /* Iterate through import descriptors and verify set name,
1017 * OriginalFirstThunk, and FirstThunk. Core Windows DLLs, such as
1018 * kernel32.dll, don't use Borland-style linking, where the table of
1019 * imported names is stored directly in FirstThunk and overwritten
1020 * by the relocation, instead of being stored in OriginalFirstThunk.
1021 * */
1022 for (; import_chunk->FirstThunk; import_chunk++)
1023 {
1024 LPCSTR module_name = RVAToAddr(import_chunk->Name, kernel32_module);
1025 PIMAGE_THUNK_DATA name_table = RVAToAddr(
1026 U(*import_chunk).OriginalFirstThunk, kernel32_module);
1027 PIMAGE_THUNK_DATA iat = RVAToAddr(
1028 import_chunk->FirstThunk, kernel32_module);
1029 ok(module_name != NULL, "Imported module name should not be NULL\n");
1030 ok(name_table != NULL,
1031 "Name table for imported module %s should not be NULL\n",
1032 module_name);
1033 ok(iat != NULL, "IAT for imported module %s should not be NULL\n",
1034 module_name);
1035 }
1036 }
1037
1038 static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL is_dll)
1039 {
1040 HANDLE hfile, hmap;
1041 NTSTATUS status;
1042 LARGE_INTEGER offset;
1043 SIZE_T size;
1044 void *addr1, *addr2;
1045 MEMORY_BASIC_INFORMATION info;
1046
1047 if (!pNtMapViewOfSection) return;
1048
1049 SetLastError(0xdeadbeef);
1050 hfile = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
1051 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError());
1052
1053 SetLastError(0xdeadbeef);
1054 hmap = CreateFileMappingW(hfile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, 0);
1055 ok(hmap != 0, "CreateFileMapping error %d\n", GetLastError());
1056
1057 offset.u.LowPart = 0;
1058 offset.u.HighPart = 0;
1059
1060 addr1 = NULL;
1061 size = 0;
1062 status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr1, 0, 0, &offset,
1063 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1064 ok(status == STATUS_SUCCESS, "NtMapViewOfSection error %x\n", status);
1065 ok(addr1 != 0, "mapped address should be valid\n");
1066
1067 SetLastError(0xdeadbeef);
1068 size = VirtualQuery((char *)addr1 + section.VirtualAddress, &info, sizeof(info));
1069 ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
1070 ok(info.BaseAddress == (char *)addr1 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr1 + section.VirtualAddress);
1071 ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size);
1072 ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
1073 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1074 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1075 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
1076 ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
1077
1078 addr2 = NULL;
1079 size = 0;
1080 status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr2, 0, 0, &offset,
1081 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1082 ok(status == STATUS_IMAGE_NOT_AT_BASE, "expected STATUS_IMAGE_NOT_AT_BASE, got %x\n", status);
1083 ok(addr2 != 0, "mapped address should be valid\n");
1084 ok(addr2 != addr1, "mapped addresses should be different\n");
1085
1086 SetLastError(0xdeadbeef);
1087 size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info));
1088 ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
1089 ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress);
1090 ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size);
1091 ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
1092 ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2);
1093 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1094 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
1095 ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
1096
1097 status = pNtUnmapViewOfSection(GetCurrentProcess(), addr2);
1098 ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status);
1099
1100 addr2 = MapViewOfFile(hmap, 0, 0, 0, 0);
1101 ok(addr2 != 0, "mapped address should be valid\n");
1102 ok(addr2 != addr1, "mapped addresses should be different\n");
1103
1104 SetLastError(0xdeadbeef);
1105 size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info));
1106 ok(size == sizeof(info), "VirtualQuery error %d\n", GetLastError());
1107 ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress);
1108 ok(info.RegionSize == page_size, "got %#lx != expected %#x\n", info.RegionSize, page_size);
1109 ok(info.Protect == scn_page_access, "got %#x != expected %#x\n", info.Protect, scn_page_access);
1110 ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2);
1111 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#x != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1112 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
1113 ok(info.Type == SEC_IMAGE, "%#x != SEC_IMAGE\n", info.Type);
1114
1115 UnmapViewOfFile(addr2);
1116
1117 SetLastError(0xdeadbeef);
1118 addr2 = LoadLibraryA(dll_name);
1119 if (is_dll)
1120 {
1121 ok(!addr2, "LoadLibrary should fail, is_dll %d\n", is_dll);
1122 ok(GetLastError() == ERROR_INVALID_ADDRESS, "expected ERROR_INVALID_ADDRESS, got %d\n", GetLastError());
1123 }
1124 else
1125 {
1126 BOOL ret;
1127 ok(addr2 != 0, "LoadLibrary error %d, is_dll %d\n", GetLastError(), is_dll);
1128 ok(addr2 != addr1, "mapped addresses should be different\n");
1129
1130 SetLastError(0xdeadbeef);
1131 ret = FreeLibrary(addr2);
1132 ok(ret, "FreeLibrary error %d\n", GetLastError());
1133 }
1134
1135 status = pNtUnmapViewOfSection(GetCurrentProcess(), addr1);
1136 ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status);
1137
1138 CloseHandle(hmap);
1139 CloseHandle(hfile);
1140 }
1141
1142 static BOOL is_mem_writable(DWORD prot)
1143 {
1144 switch (prot & 0xff)
1145 {
1146 case PAGE_READWRITE:
1147 case PAGE_WRITECOPY:
1148 case PAGE_EXECUTE_READWRITE:
1149 case PAGE_EXECUTE_WRITECOPY:
1150 return TRUE;
1151
1152 default:
1153 return FALSE;
1154 }
1155 }
1156
1157 static void test_VirtualProtect(void *base, void *section)
1158 {
1159 static const struct test_data
1160 {
1161 DWORD prot_set, prot_get;
1162 } td[] =
1163 {
1164 { 0, 0 }, /* 0x00 */
1165 { PAGE_NOACCESS, PAGE_NOACCESS }, /* 0x01 */
1166 { PAGE_READONLY, PAGE_READONLY }, /* 0x02 */
1167 { PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x03 */
1168 { PAGE_READWRITE, PAGE_WRITECOPY }, /* 0x04 */
1169 { PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x05 */
1170 { PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x06 */
1171 { PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x07 */
1172 { PAGE_WRITECOPY, PAGE_WRITECOPY }, /* 0x08 */
1173 { PAGE_WRITECOPY | PAGE_NOACCESS, 0 }, /* 0x09 */
1174 { PAGE_WRITECOPY | PAGE_READONLY, 0 }, /* 0x0a */
1175 { PAGE_WRITECOPY | PAGE_NOACCESS | PAGE_READONLY, 0 }, /* 0x0b */
1176 { PAGE_WRITECOPY | PAGE_READWRITE, 0 }, /* 0x0c */
1177 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x0d */
1178 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x0e */
1179 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x0f */
1180
1181 { PAGE_EXECUTE, PAGE_EXECUTE }, /* 0x10 */
1182 { PAGE_EXECUTE_READ, PAGE_EXECUTE_READ }, /* 0x20 */
1183 { PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x30 */
1184 { PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY }, /* 0x40 */
1185 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0x50 */
1186 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0x60 */
1187 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x70 */
1188 { PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_WRITECOPY }, /* 0x80 */
1189 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE, 0 }, /* 0x90 */
1190 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ, 0 }, /* 0xa0 */
1191 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0xb0 */
1192 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE, 0 }, /* 0xc0 */
1193 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0xd0 */
1194 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0xe0 */
1195 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 } /* 0xf0 */
1196 };
1197 DWORD ret, orig_prot, old_prot, rw_prot, exec_prot, i, j;
1198 MEMORY_BASIC_INFORMATION info;
1199
1200 SetLastError(0xdeadbeef);
1201 ret = VirtualProtect(section, page_size, PAGE_NOACCESS, &old_prot);
1202 ok(ret, "VirtualProtect error %d\n", GetLastError());
1203
1204 orig_prot = old_prot;
1205
1206 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
1207 {
1208 SetLastError(0xdeadbeef);
1209 ret = VirtualQuery(section, &info, sizeof(info));
1210 ok(ret, "VirtualQuery failed %d\n", GetLastError());
1211 ok(info.BaseAddress == section, "%d: got %p != expected %p\n", i, info.BaseAddress, section);
1212 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1213 ok(info.Protect == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, info.Protect);
1214 ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
1215 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1216 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1217 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1218
1219 old_prot = 0xdeadbeef;
1220 SetLastError(0xdeadbeef);
1221 ret = VirtualProtect(section, page_size, td[i].prot_set, &old_prot);
1222 if (td[i].prot_get)
1223 {
1224 ok(ret, "%d: VirtualProtect error %d, requested prot %#x\n", i, GetLastError(), td[i].prot_set);
1225 ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
1226
1227 SetLastError(0xdeadbeef);
1228 ret = VirtualQuery(section, &info, sizeof(info));
1229 ok(ret, "VirtualQuery failed %d\n", GetLastError());
1230 ok(info.BaseAddress == section, "%d: got %p != expected %p\n", i, info.BaseAddress, section);
1231 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1232 ok(info.Protect == td[i].prot_get, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_get);
1233 ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
1234 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1235 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1236 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1237 }
1238 else
1239 {
1240 ok(!ret, "%d: VirtualProtect should fail\n", i);
1241 ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
1242 }
1243
1244 old_prot = 0xdeadbeef;
1245 SetLastError(0xdeadbeef);
1246 ret = VirtualProtect(section, page_size, PAGE_NOACCESS, &old_prot);
1247 ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
1248 if (td[i].prot_get)
1249 ok(old_prot == td[i].prot_get, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_get);
1250 else
1251 ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
1252 }
1253
1254 exec_prot = 0;
1255
1256 for (i = 0; i <= 4; i++)
1257 {
1258 rw_prot = 0;
1259
1260 for (j = 0; j <= 4; j++)
1261 {
1262 DWORD prot = exec_prot | rw_prot;
1263
1264 SetLastError(0xdeadbeef);
1265 ret = VirtualProtect(section, page_size, prot, &old_prot);
1266 if ((rw_prot && exec_prot) || (!rw_prot && !exec_prot))
1267 {
1268 ok(!ret, "VirtualProtect(%02x) should fail\n", prot);
1269 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1270 }
1271 else
1272 ok(ret, "VirtualProtect(%02x) error %d\n", prot, GetLastError());
1273
1274 rw_prot = 1 << j;
1275 }
1276
1277 exec_prot = 1 << (i + 4);
1278 }
1279
1280 SetLastError(0xdeadbeef);
1281 ret = VirtualProtect(section, page_size, orig_prot, &old_prot);
1282 ok(ret, "VirtualProtect error %d\n", GetLastError());
1283 }
1284
1285 static void test_section_access(void)
1286 {
1287 static const struct test_data
1288 {
1289 DWORD scn_file_access, scn_page_access, scn_page_access_after_write;
1290 } td[] =
1291 {
1292 { 0, PAGE_NOACCESS, 0 },
1293 { IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1294 { IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1295 { IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1296 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1297 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ },
1298 { IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1299 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1300
1301 { IMAGE_SCN_CNT_INITIALIZED_DATA, PAGE_NOACCESS, 0 },
1302 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1303 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1304 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1305 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1306 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
1307 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1308 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1309
1310 { IMAGE_SCN_CNT_UNINITIALIZED_DATA, PAGE_NOACCESS, 0 },
1311 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1312 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1313 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1314 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1315 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
1316 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1317 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE }
1318 };
1319 char buf[256];
1320 int i;
1321 DWORD dummy, file_align;
1322 HANDLE hfile;
1323 HMODULE hlib;
1324 char temp_path[MAX_PATH];
1325 char dll_name[MAX_PATH];
1326 SIZE_T size;
1327 MEMORY_BASIC_INFORMATION info;
1328 STARTUPINFOA sti;
1329 PROCESS_INFORMATION pi;
1330 DWORD ret;
1331
1332 /* prevent displaying of the "Unable to load this DLL" message box */
1333 SetErrorMode(SEM_FAILCRITICALERRORS);
1334
1335 GetTempPathA(MAX_PATH, temp_path);
1336
1337 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
1338 {
1339 IMAGE_NT_HEADERS nt_header;
1340
1341 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
1342
1343 /*trace("creating %s\n", dll_name);*/
1344 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
1345 if (hfile == INVALID_HANDLE_VALUE)
1346 {
1347 ok(0, "could not create %s\n", dll_name);
1348 return;
1349 }
1350
1351 SetLastError(0xdeadbeef);
1352 ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
1353 ok(ret, "WriteFile error %d\n", GetLastError());
1354
1355 nt_header = nt_header_template;
1356 nt_header.FileHeader.NumberOfSections = 1;
1357 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1358 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED;
1359
1360 nt_header.OptionalHeader.SectionAlignment = page_size;
1361 nt_header.OptionalHeader.FileAlignment = 0x200;
1362 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
1363 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
1364 SetLastError(0xdeadbeef);
1365 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
1366 ok(ret, "WriteFile error %d\n", GetLastError());
1367 SetLastError(0xdeadbeef);
1368 ret = WriteFile(hfile, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
1369 ok(ret, "WriteFile error %d\n", GetLastError());
1370
1371 section.SizeOfRawData = sizeof(section_data);
1372 section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
1373 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
1374 section.Misc.VirtualSize = section.SizeOfRawData;
1375 section.Characteristics = td[i].scn_file_access;
1376 SetLastError(0xdeadbeef);
1377 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
1378 ok(ret, "WriteFile error %d\n", GetLastError());
1379
1380 file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
1381 assert(file_align < sizeof(filler));
1382 SetLastError(0xdeadbeef);
1383 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
1384 ok(ret, "WriteFile error %d\n", GetLastError());
1385
1386 /* section data */
1387 SetLastError(0xdeadbeef);
1388 ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
1389 ok(ret, "WriteFile error %d\n", GetLastError());
1390
1391 CloseHandle(hfile);
1392
1393 SetLastError(0xdeadbeef);
1394 hlib = LoadLibraryA(dll_name);
1395 ok(hlib != 0, "LoadLibrary error %d\n", GetLastError());
1396
1397 SetLastError(0xdeadbeef);
1398 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
1399 ok(size == sizeof(info),
1400 "%d: VirtualQuery error %d\n", i, GetLastError());
1401 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
1402 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1403 ok(info.Protect == td[i].scn_page_access, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access);
1404 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
1405 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1406 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1407 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1408 if (info.Protect != PAGE_NOACCESS)
1409 ok(!memcmp((const char *)info.BaseAddress, section_data, section.SizeOfRawData), "wrong section data\n");
1410
1411 test_VirtualProtect(hlib, (char *)hlib + section.VirtualAddress);
1412
1413 /* Windows changes the WRITECOPY to WRITE protection on an image section write (for a changed page only) */
1414 if (is_mem_writable(info.Protect))
1415 {
1416 char *p = info.BaseAddress;
1417 *p = 0xfe;
1418 SetLastError(0xdeadbeef);
1419 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
1420 ok(size == sizeof(info), "%d: VirtualQuery error %d\n", i, GetLastError());
1421 /* FIXME: remove the condition below once Wine is fixed */
1422 todo_wine_if (info.Protect == PAGE_WRITECOPY || info.Protect == PAGE_EXECUTE_WRITECOPY)
1423 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);
1424 }
1425
1426 SetLastError(0xdeadbeef);
1427 ret = FreeLibrary(hlib);
1428 ok(ret, "FreeLibrary error %d\n", GetLastError());
1429
1430 test_image_mapping(dll_name, td[i].scn_page_access, TRUE);
1431
1432 /* reset IMAGE_FILE_DLL otherwise CreateProcess fails */
1433 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_RELOCS_STRIPPED;
1434 SetLastError(0xdeadbeef);
1435 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1436 /* LoadLibrary called on an already memory-mapped file in
1437 * test_image_mapping() above leads to a file handle leak
1438 * under nt4, and inability to overwrite and delete the file
1439 * due to sharing violation error. Ignore it and skip the test,
1440 * but leave a not deletable temporary file.
1441 */
1442 ok(hfile != INVALID_HANDLE_VALUE || broken(hfile == INVALID_HANDLE_VALUE) /* nt4 */,
1443 "CreateFile error %d\n", GetLastError());
1444 if (hfile == INVALID_HANDLE_VALUE) goto nt4_is_broken;
1445 SetFilePointer(hfile, sizeof(dos_header), NULL, FILE_BEGIN);
1446 SetLastError(0xdeadbeef);
1447 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
1448 ok(ret, "WriteFile error %d\n", GetLastError());
1449 CloseHandle(hfile);
1450
1451 memset(&sti, 0, sizeof(sti));
1452 sti.cb = sizeof(sti);
1453 SetLastError(0xdeadbeef);
1454 ret = CreateProcessA(dll_name, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &sti, &pi);
1455 ok(ret, "CreateProcess() error %d\n", GetLastError());
1456
1457 SetLastError(0xdeadbeef);
1458 size = VirtualQueryEx(pi.hProcess, (char *)hlib + section.VirtualAddress, &info, sizeof(info));
1459 ok(size == sizeof(info),
1460 "%d: VirtualQuery error %d\n", i, GetLastError());
1461 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
1462 ok(info.RegionSize == page_size, "%d: got %#lx != expected %#x\n", i, info.RegionSize, page_size);
1463 ok(info.Protect == td[i].scn_page_access, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].scn_page_access);
1464 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
1465 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#x != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1466 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
1467 ok(info.Type == SEC_IMAGE, "%d: %#x != SEC_IMAGE\n", i, info.Type);
1468 if (info.Protect != PAGE_NOACCESS)
1469 {
1470 SetLastError(0xdeadbeef);
1471 ret = ReadProcessMemory(pi.hProcess, info.BaseAddress, buf, section.SizeOfRawData, NULL);
1472 ok(ret, "ReadProcessMemory() error %d\n", GetLastError());
1473 ok(!memcmp(buf, section_data, section.SizeOfRawData), "wrong section data\n");
1474 }
1475
1476 SetLastError(0xdeadbeef);
1477 ret = TerminateProcess(pi.hProcess, 0);
1478 ok(ret, "TerminateProcess() error %d\n", GetLastError());
1479 ret = WaitForSingleObject(pi.hProcess, 3000);
1480 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
1481
1482 CloseHandle(pi.hThread);
1483 CloseHandle(pi.hProcess);
1484
1485 test_image_mapping(dll_name, td[i].scn_page_access, FALSE);
1486
1487 nt4_is_broken:
1488 SetLastError(0xdeadbeef);
1489 ret = DeleteFileA(dll_name);
1490 ok(ret || broken(!ret) /* nt4 */, "DeleteFile error %d\n", GetLastError());
1491 }
1492 }
1493
1494 static void test_import_resolution(void)
1495 {
1496 char temp_path[MAX_PATH];
1497 char dll_name[MAX_PATH];
1498 DWORD dummy;
1499 void *expect;
1500 char *str;
1501 HANDLE hfile;
1502 HMODULE mod, mod2;
1503 struct imports
1504 {
1505 IMAGE_IMPORT_DESCRIPTOR descr[2];
1506 IMAGE_THUNK_DATA original_thunks[2];
1507 IMAGE_THUNK_DATA thunks[2];
1508 char module[16];
1509 struct { WORD hint; char name[32]; } function;
1510 IMAGE_TLS_DIRECTORY tls;
1511 char tls_data[16];
1512 SHORT tls_index;
1513 } data, *ptr;
1514 IMAGE_NT_HEADERS nt;
1515 IMAGE_SECTION_HEADER section;
1516 int test;
1517
1518 for (test = 0; test < 3; test++)
1519 {
1520 #define DATA_RVA(ptr) (page_size + ((char *)(ptr) - (char *)&data))
1521 nt = nt_header_template;
1522 nt.FileHeader.NumberOfSections = 1;
1523 nt.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1524 nt.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_RELOCS_STRIPPED;
1525 if (test != 2) nt.FileHeader.Characteristics |= IMAGE_FILE_DLL;
1526 nt.OptionalHeader.SectionAlignment = page_size;
1527 nt.OptionalHeader.FileAlignment = 0x200;
1528 nt.OptionalHeader.ImageBase = 0x12340000;
1529 nt.OptionalHeader.SizeOfImage = 2 * page_size;
1530 nt.OptionalHeader.SizeOfHeaders = nt.OptionalHeader.FileAlignment;
1531 nt.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
1532 memset( nt.OptionalHeader.DataDirectory, 0, sizeof(nt.OptionalHeader.DataDirectory) );
1533 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = sizeof(data.descr);
1534 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = DATA_RVA(data.descr);
1535 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = sizeof(data.tls);
1536 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = DATA_RVA(&data.tls);
1537
1538 memset( &data, 0, sizeof(data) );
1539 data.descr[0].OriginalFirstThunk = DATA_RVA( data.original_thunks );
1540 data.descr[0].FirstThunk = DATA_RVA( data.thunks );
1541 data.descr[0].Name = DATA_RVA( data.module );
1542 strcpy( data.module, "kernel32.dll" );
1543 strcpy( data.function.name, "CreateEventA" );
1544 data.original_thunks[0].u1.AddressOfData = DATA_RVA( &data.function );
1545 data.thunks[0].u1.AddressOfData = 0xdeadbeef;
1546
1547 data.tls.StartAddressOfRawData = nt.OptionalHeader.ImageBase + DATA_RVA( data.tls_data );
1548 data.tls.EndAddressOfRawData = data.tls.StartAddressOfRawData + sizeof(data.tls_data);
1549 data.tls.AddressOfIndex = nt.OptionalHeader.ImageBase + DATA_RVA( &data.tls_index );
1550 strcpy( data.tls_data, "hello world" );
1551 data.tls_index = 9999;
1552
1553 GetTempPathA(MAX_PATH, temp_path);
1554 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
1555
1556 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
1557 ok( hfile != INVALID_HANDLE_VALUE, "creation failed\n" );
1558
1559 memset( &section, 0, sizeof(section) );
1560 memcpy( section.Name, ".text", sizeof(".text") );
1561 section.PointerToRawData = nt.OptionalHeader.FileAlignment;
1562 section.VirtualAddress = nt.OptionalHeader.SectionAlignment;
1563 section.Misc.VirtualSize = sizeof(data);
1564 section.SizeOfRawData = sizeof(data);
1565 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
1566
1567 WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
1568 WriteFile(hfile, &nt, sizeof(nt), &dummy, NULL);
1569 WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
1570
1571 SetFilePointer( hfile, section.PointerToRawData, NULL, SEEK_SET );
1572 WriteFile(hfile, &data, sizeof(data), &dummy, NULL);
1573
1574 CloseHandle( hfile );
1575
1576 switch (test)
1577 {
1578 case 0: /* normal load */
1579 mod = LoadLibraryA( dll_name );
1580 ok( mod != NULL, "failed to load err %u\n", GetLastError() );
1581 if (!mod) break;
1582 ptr = (struct imports *)((char *)mod + page_size);
1583 expect = GetProcAddress( GetModuleHandleA( data.module ), data.function.name );
1584 ok( (void *)ptr->thunks[0].u1.Function == expect, "thunk %p instead of %p for %s.%s\n",
1585 (void *)ptr->thunks[0].u1.Function, expect, data.module, data.function.name );
1586 ok( ptr->tls_index < 32 || broken(ptr->tls_index == 9999), /* before vista */
1587 "wrong tls index %d\n", ptr->tls_index );
1588 if (ptr->tls_index != 9999)
1589 {
1590 str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index];
1591 ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str );
1592 }
1593 FreeLibrary( mod );
1594 break;
1595 case 1: /* load with DONT_RESOLVE_DLL_REFERENCES doesn't resolve imports */
1596 mod = LoadLibraryExA( dll_name, 0, DONT_RESOLVE_DLL_REFERENCES );
1597 ok( mod != NULL, "failed to load err %u\n", GetLastError() );
1598 if (!mod) break;
1599 ptr = (struct imports *)((char *)mod + page_size);
1600 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
1601 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
1602 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
1603
1604 mod2 = LoadLibraryA( dll_name );
1605 ok( mod2 == mod, "loaded twice %p / %p\n", mod, mod2 );
1606 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
1607 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
1608 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
1609 FreeLibrary( mod2 );
1610 FreeLibrary( mod );
1611 break;
1612 case 2: /* load without IMAGE_FILE_DLL doesn't resolve imports */
1613 mod = LoadLibraryA( dll_name );
1614 ok( mod != NULL, "failed to load err %u\n", GetLastError() );
1615 if (!mod) break;
1616 ptr = (struct imports *)((char *)mod + page_size);
1617 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
1618 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
1619 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
1620 FreeLibrary( mod );
1621 break;
1622 }
1623 DeleteFileA( dll_name );
1624 #undef DATA_RVA
1625 }
1626 }
1627
1628 #define MAX_COUNT 10
1629 static HANDLE attached_thread[MAX_COUNT];
1630 static DWORD attached_thread_count;
1631 HANDLE stop_event, event, mutex, semaphore, loader_lock_event, peb_lock_event, heap_lock_event, ack_event;
1632 static int test_dll_phase, inside_loader_lock, inside_peb_lock, inside_heap_lock;
1633 static LONG fls_callback_count;
1634
1635 static DWORD WINAPI mutex_thread_proc(void *param)
1636 {
1637 HANDLE wait_list[4];
1638 DWORD ret;
1639
1640 ret = WaitForSingleObject(mutex, 0);
1641 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1642
1643 SetEvent(param);
1644
1645 wait_list[0] = stop_event;
1646 wait_list[1] = loader_lock_event;
1647 wait_list[2] = peb_lock_event;
1648 wait_list[3] = heap_lock_event;
1649
1650 trace("%04u: mutex_thread_proc: starting\n", GetCurrentThreadId());
1651 while (1)
1652 {
1653 ret = WaitForMultipleObjects(sizeof(wait_list)/sizeof(wait_list[0]), wait_list, FALSE, 50);
1654 if (ret == WAIT_OBJECT_0) break;
1655 else if (ret == WAIT_OBJECT_0 + 1)
1656 {
1657 ULONG_PTR loader_lock_magic;
1658 trace("%04u: mutex_thread_proc: Entering loader lock\n", GetCurrentThreadId());
1659 ret = pLdrLockLoaderLock(0, NULL, &loader_lock_magic);
1660 ok(!ret, "LdrLockLoaderLock error %#x\n", ret);
1661 inside_loader_lock++;
1662 SetEvent(ack_event);
1663 }
1664 else if (ret == WAIT_OBJECT_0 + 2)
1665 {
1666 trace("%04u: mutex_thread_proc: Entering PEB lock\n", GetCurrentThreadId());
1667 pRtlAcquirePebLock();
1668 inside_peb_lock++;
1669 SetEvent(ack_event);
1670 }
1671 else if (ret == WAIT_OBJECT_0 + 3)
1672 {
1673 trace("%04u: mutex_thread_proc: Entering heap lock\n", GetCurrentThreadId());
1674 HeapLock(GetProcessHeap());
1675 inside_heap_lock++;
1676 SetEvent(ack_event);
1677 }
1678 }
1679
1680 trace("%04u: mutex_thread_proc: exiting\n", GetCurrentThreadId());
1681 return 196;
1682 }
1683
1684 static DWORD WINAPI semaphore_thread_proc(void *param)
1685 {
1686 DWORD ret;
1687
1688 ret = WaitForSingleObject(semaphore, 0);
1689 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1690
1691 SetEvent(param);
1692
1693 while (1)
1694 {
1695 if (winetest_debug > 1)
1696 trace("%04u: semaphore_thread_proc: still alive\n", GetCurrentThreadId());
1697 if (WaitForSingleObject(stop_event, 50) != WAIT_TIMEOUT) break;
1698 }
1699
1700 trace("%04u: semaphore_thread_proc: exiting\n", GetCurrentThreadId());
1701 return 196;
1702 }
1703
1704 static DWORD WINAPI noop_thread_proc(void *param)
1705 {
1706 if (param)
1707 {
1708 LONG *noop_thread_started = param;
1709 InterlockedIncrement(noop_thread_started);
1710 }
1711
1712 trace("%04u: noop_thread_proc: exiting\n", GetCurrentThreadId());
1713 return 195;
1714 }
1715
1716 static VOID WINAPI fls_callback(PVOID lpFlsData)
1717 {
1718 ok(lpFlsData == (void*) 0x31415, "lpFlsData is %p, expected %p\n", lpFlsData, (void*) 0x31415);
1719 InterlockedIncrement(&fls_callback_count);
1720 }
1721
1722 static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param)
1723 {
1724 static LONG noop_thread_started;
1725 static DWORD fls_index = FLS_OUT_OF_INDEXES;
1726 static int fls_count = 0;
1727 static int thread_detach_count = 0;
1728 DWORD ret;
1729
1730 ok(!inside_loader_lock, "inside_loader_lock should not be set\n");
1731 ok(!inside_peb_lock, "inside_peb_lock should not be set\n");
1732
1733 switch (reason)
1734 {
1735 case DLL_PROCESS_ATTACH:
1736 trace("dll: %p, DLL_PROCESS_ATTACH, %p\n", hinst, param);
1737
1738 ret = pRtlDllShutdownInProgress();
1739 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
1740
1741 /* Set up the FLS slot, if FLS is available */
1742 if (pFlsGetValue)
1743 {
1744 void* value;
1745 BOOL bret;
1746 ret = pFlsAlloc(&fls_callback);
1747 ok(ret != FLS_OUT_OF_INDEXES, "FlsAlloc returned %d\n", ret);
1748 fls_index = ret;
1749 SetLastError(0xdeadbeef);
1750 value = pFlsGetValue(fls_index);
1751 ok(!value, "FlsGetValue returned %p, expected NULL\n", value);
1752 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
1753 bret = pFlsSetValue(fls_index, (void*) 0x31415);
1754 ok(bret, "FlsSetValue failed\n");
1755 fls_count++;
1756 }
1757
1758 break;
1759 case DLL_PROCESS_DETACH:
1760 {
1761 DWORD code, expected_code, i;
1762 HANDLE handle, process;
1763 void *addr;
1764 SIZE_T size;
1765 LARGE_INTEGER offset;
1766 DEBUG_EVENT de;
1767
1768 trace("dll: %p, DLL_PROCESS_DETACH, %p\n", hinst, param);
1769
1770 if (test_dll_phase == 4 || test_dll_phase == 5)
1771 {
1772 ok(0, "dll_entry_point(DLL_PROCESS_DETACH) should not be called\n");
1773 break;
1774 }
1775
1776 /* The process should already deadlock at this point */
1777 if (test_dll_phase == 6)
1778 {
1779 /* In reality, code below never gets executed, probably some other
1780 * code tries to access process heap and deadlocks earlier, even XP
1781 * doesn't call the DLL entry point on process detach either.
1782 */
1783 HeapLock(GetProcessHeap());
1784 ok(0, "dll_entry_point: process should already deadlock\n");
1785 break;
1786 }
1787
1788 if (test_dll_phase == 0 || test_dll_phase == 1 || test_dll_phase == 3)
1789 ok(param != NULL, "dll: param %p\n", param);
1790 else
1791 ok(!param, "dll: param %p\n", param);
1792
1793 if (test_dll_phase == 0 || test_dll_phase == 1) expected_code = 195;
1794 else if (test_dll_phase == 3) expected_code = 196;
1795 else expected_code = STILL_ACTIVE;
1796
1797 if (test_dll_phase == 3)
1798 {
1799 ret = pRtlDllShutdownInProgress();
1800 ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
1801 }
1802 else
1803 {
1804 ret = pRtlDllShutdownInProgress();
1805
1806 /* FIXME: remove once Wine is fixed */
1807 todo_wine_if (!(expected_code == STILL_ACTIVE || expected_code == 196))
1808 ok(!ret || broken(ret) /* before Vista */, "RtlDllShutdownInProgress returned %d\n", ret);
1809 }
1810
1811 /* In the case that the process is terminating, FLS slots should still be accessible, but
1812 * the callback should be already run for this thread and the contents already NULL.
1813 * Note that this is broken for Win2k3, which runs the callbacks *after* the DLL entry
1814 * point has already run.
1815 */
1816 if (param && pFlsGetValue)
1817 {
1818 void* value;
1819 SetLastError(0xdeadbeef);
1820 value = pFlsGetValue(fls_index);
1821 todo_wine
1822 {
1823 ok(broken(value == (void*) 0x31415) || /* Win2k3 */
1824 value == NULL, "FlsGetValue returned %p, expected NULL\n", value);
1825 }
1826 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
1827 todo_wine
1828 {
1829 ok(broken(fls_callback_count == thread_detach_count) || /* Win2k3 */
1830 fls_callback_count == thread_detach_count + 1,
1831 "wrong FLS callback count %d, expected %d\n", fls_callback_count, thread_detach_count + 1);
1832 }
1833 }
1834 if (pFlsFree)
1835 {
1836 BOOL ret;
1837 /* Call FlsFree now and run the remaining callbacks from uncleanly terminated threads */
1838 ret = pFlsFree(fls_index);
1839 ok(ret, "FlsFree failed with error %u\n", GetLastError());
1840 fls_index = FLS_OUT_OF_INDEXES;
1841 todo_wine
1842 {
1843 ok(fls_callback_count == fls_count,
1844 "wrong FLS callback count %d, expected %d\n", fls_callback_count, fls_count);
1845 }
1846 }
1847
1848 ok(attached_thread_count >= 2, "attached thread count should be >= 2\n");
1849
1850 for (i = 0; i < attached_thread_count; i++)
1851 {
1852 /* Calling GetExitCodeThread() without waiting for thread termination
1853 * leads to different results due to a race condition.
1854 */
1855 if (expected_code != STILL_ACTIVE)
1856 {
1857 ret = WaitForSingleObject(attached_thread[i], 1000);
1858 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1859 }
1860 ret = GetExitCodeThread(attached_thread[i], &code);
1861 trace("dll: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
1862 ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
1863 ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code);
1864 }
1865
1866 ret = WaitForSingleObject(event, 0);
1867 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1868
1869 ret = WaitForSingleObject(mutex, 0);
1870 if (expected_code == STILL_ACTIVE)
1871 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1872 else
1873 ok(ret == WAIT_ABANDONED, "expected WAIT_ABANDONED, got %#x\n", ret);
1874
1875 /* semaphore is not abandoned on thread termination */
1876 ret = WaitForSingleObject(semaphore, 0);
1877 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1878
1879 if (expected_code == STILL_ACTIVE)
1880 {
1881 ret = WaitForSingleObject(attached_thread[0], 0);
1882 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1883 ret = WaitForSingleObject(attached_thread[1], 0);
1884 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1885 }
1886 else
1887 {
1888 ret = WaitForSingleObject(attached_thread[0], 0);
1889 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1890 ret = WaitForSingleObject(attached_thread[1], 0);
1891 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
1892 }
1893
1894 /* win7 doesn't allow creating a thread during process shutdown but
1895 * earlier Windows versions allow it.
1896 */
1897 noop_thread_started = 0;
1898 SetLastError(0xdeadbeef);
1899 handle = CreateThread(NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
1900 if (param)
1901 {
1902 ok(!handle || broken(handle != 0) /* before win7 */, "CreateThread should fail\n");
1903 if (!handle)
1904 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1905 else
1906 {
1907 ret = WaitForSingleObject(handle, 1000);
1908 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1909 CloseHandle(handle);
1910 }
1911 }
1912 else
1913 {
1914 ok(handle != 0, "CreateThread error %d\n", GetLastError());
1915 ret = WaitForSingleObject(handle, 1000);
1916 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1917 ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n");
1918 CloseHandle(handle);
1919 }
1920
1921 SetLastError(0xdeadbeef);
1922 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, GetCurrentProcessId());
1923 ok(process != NULL, "OpenProcess error %d\n", GetLastError());
1924
1925 noop_thread_started = 0;
1926 SetLastError(0xdeadbeef);
1927 handle = CreateRemoteThread(process, NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
1928 if (param)
1929 {
1930 ok(!handle || broken(handle != 0) /* before win7 */, "CreateRemoteThread should fail\n");
1931 if (!handle)
1932 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1933 else
1934 {
1935 ret = WaitForSingleObject(handle, 1000);
1936 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1937 CloseHandle(handle);
1938 }
1939 }
1940 else
1941 {
1942 ok(handle != 0, "CreateRemoteThread error %d\n", GetLastError());
1943 ret = WaitForSingleObject(handle, 1000);
1944 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
1945 ok(!noop_thread_started || broken(noop_thread_started) /* XP64 */, "thread shouldn't start yet\n");
1946 CloseHandle(handle);
1947 }
1948
1949 SetLastError(0xdeadbeef);
1950 handle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
1951 ok(handle != 0, "CreateFileMapping error %d\n", GetLastError());
1952
1953 offset.u.LowPart = 0;
1954 offset.u.HighPart = 0;
1955 addr = NULL;
1956 size = 0;
1957 ret = pNtMapViewOfSection(handle, process, &addr, 0, 0, &offset,
1958 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1959 ok(ret == STATUS_SUCCESS, "NtMapViewOfSection error %#x\n", ret);
1960 ret = pNtUnmapViewOfSection(process, addr);
1961 ok(ret == STATUS_SUCCESS, "NtUnmapViewOfSection error %#x\n", ret);
1962
1963 CloseHandle(handle);
1964 CloseHandle(process);
1965
1966 handle = GetModuleHandleA("winver.exe");
1967 ok(!handle, "winver.exe shouldn't be loaded yet\n");
1968 SetLastError(0xdeadbeef);
1969 handle = LoadLibraryA("winver.exe");
1970 ok(handle != 0, "LoadLibrary error %d\n", GetLastError());
1971 SetLastError(0xdeadbeef);
1972 ret = FreeLibrary(handle);
1973 ok(ret, "FreeLibrary error %d\n", GetLastError());
1974 handle = GetModuleHandleA("winver.exe");
1975 if (param)
1976 ok(handle != 0, "winver.exe should not be unloaded\n");
1977 else
1978 todo_wine
1979 ok(!handle || broken(handle != 0) /* before win7 */, "winver.exe should be unloaded\n");
1980
1981 SetLastError(0xdeadbeef);
1982 ret = WaitForDebugEvent(&de, 0);
1983 ok(!ret, "WaitForDebugEvent should fail\n");
1984 todo_wine
1985 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
1986
1987 SetLastError(0xdeadbeef);
1988 ret = DebugActiveProcess(GetCurrentProcessId());
1989 ok(!ret, "DebugActiveProcess should fail\n");
1990 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
1991
1992 SetLastError(0xdeadbeef);
1993 ret = WaitForDebugEvent(&de, 0);
1994 ok(!ret, "WaitForDebugEvent should fail\n");
1995 ok(GetLastError() == ERROR_SEM_TIMEOUT, "expected ERROR_SEM_TIMEOUT, got %d\n", GetLastError());
1996
1997 if (test_dll_phase == 2)
1998 {
1999 trace("dll: call ExitProcess()\n");
2000 *child_failures = winetest_get_failures();
2001 ExitProcess(197);
2002 }
2003 trace("dll: %p, DLL_PROCESS_DETACH, %p => DONE\n", hinst, param);
2004 break;
2005 }
2006 case DLL_THREAD_ATTACH:
2007 trace("dll: %p, DLL_THREAD_ATTACH, %p\n", hinst, param);
2008
2009 ret = pRtlDllShutdownInProgress();
2010 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2011
2012 if (attached_thread_count < MAX_COUNT)
2013 {
2014 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &attached_thread[attached_thread_count],
2015 0, TRUE, DUPLICATE_SAME_ACCESS);
2016 attached_thread_count++;
2017 }
2018
2019 /* Make sure the FLS slot is empty, if FLS is available */
2020 if (pFlsGetValue)
2021 {
2022 void* value;
2023 BOOL ret;
2024 SetLastError(0xdeadbeef);
2025 value = pFlsGetValue(fls_index);
2026 ok(!value, "FlsGetValue returned %p, expected NULL\n", value);
2027 todo_wine
2028 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
2029 ret = pFlsSetValue(fls_index, (void*) 0x31415);
2030 ok(ret, "FlsSetValue failed\n");
2031 fls_count++;
2032 }
2033
2034 break;
2035 case DLL_THREAD_DETACH:
2036 trace("dll: %p, DLL_THREAD_DETACH, %p\n", hinst, param);
2037 thread_detach_count++;
2038
2039 ret = pRtlDllShutdownInProgress();
2040 /* win7 doesn't allow creating a thread during process shutdown but
2041 * earlier Windows versions allow it. In that case DLL_THREAD_DETACH is
2042 * sent on thread exit, but DLL_THREAD_ATTACH is never received.
2043 */
2044 if (noop_thread_started)
2045 ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
2046 else
2047 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2048
2049 /* FLS data should already be destroyed, if FLS is available.
2050 * Note that this is broken for Win2k3, which runs the callbacks *after* the DLL entry
2051 * point has already run.
2052 */
2053 if (pFlsGetValue && fls_index != FLS_OUT_OF_INDEXES)
2054 {
2055 void* value;
2056 SetLastError(0xdeadbeef);
2057 value = pFlsGetValue(fls_index);
2058 todo_wine
2059 {
2060 ok(broken(value == (void*) 0x31415) || /* Win2k3 */
2061 !value, "FlsGetValue returned %p, expected NULL\n", value);
2062 }
2063 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
2064 }
2065
2066 break;
2067 default:
2068 trace("dll: %p, %d, %p\n", hinst, reason, param);
2069 break;
2070 }
2071
2072 *child_failures = winetest_get_failures();
2073
2074 return TRUE;
2075 }
2076
2077 static void child_process(const char *dll_name, DWORD target_offset)
2078 {
2079 void *target;
2080 DWORD ret, dummy, i, code, expected_code;
2081 HANDLE file, thread, process;
2082 HMODULE hmod;
2083 struct PROCESS_BASIC_INFORMATION_PRIVATE pbi;
2084 DWORD_PTR affinity;
2085
2086 trace("phase %d: writing %p at %#x\n", test_dll_phase, dll_entry_point, target_offset);
2087
2088 SetLastError(0xdeadbeef);
2089 mutex = CreateMutexW(NULL, FALSE, NULL);
2090 ok(mutex != 0, "CreateMutex error %d\n", GetLastError());
2091
2092 SetLastError(0xdeadbeef);
2093 semaphore = CreateSemaphoreW(NULL, 1, 1, NULL);
2094 ok(semaphore != 0, "CreateSemaphore error %d\n", GetLastError());
2095
2096 SetLastError(0xdeadbeef);
2097 event = CreateEventW(NULL, TRUE, FALSE, NULL);
2098 ok(event != 0, "CreateEvent error %d\n", GetLastError());
2099
2100 SetLastError(0xdeadbeef);
2101 loader_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2102 ok(loader_lock_event != 0, "CreateEvent error %d\n", GetLastError());
2103
2104 SetLastError(0xdeadbeef);
2105 peb_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2106 ok(peb_lock_event != 0, "CreateEvent error %d\n", GetLastError());
2107
2108 SetLastError(0xdeadbeef);
2109 heap_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2110 ok(heap_lock_event != 0, "CreateEvent error %d\n", GetLastError());
2111
2112 SetLastError(0xdeadbeef);
2113 ack_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2114 ok(ack_event != 0, "CreateEvent error %d\n", GetLastError());
2115
2116 file = CreateFileA(dll_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2117 if (file == INVALID_HANDLE_VALUE)
2118 {
2119 ok(0, "could not open %s\n", dll_name);
2120 return;
2121 }
2122 SetFilePointer(file, target_offset, NULL, FILE_BEGIN);
2123 SetLastError(0xdeadbeef);
2124 target = dll_entry_point;
2125 ret = WriteFile(file, &target, sizeof(target), &dummy, NULL);
2126 ok(ret, "WriteFile error %d\n", GetLastError());
2127 CloseHandle(file);
2128
2129 SetLastError(0xdeadbeef);
2130 hmod = LoadLibraryA(dll_name);
2131 ok(hmod != 0, "LoadLibrary error %d\n", GetLastError());
2132
2133 SetLastError(0xdeadbeef);
2134 stop_event = CreateEventW(NULL, TRUE, FALSE, NULL);
2135 ok(stop_event != 0, "CreateEvent error %d\n", GetLastError());
2136
2137 SetLastError(0xdeadbeef);
2138 thread = CreateThread(NULL, 0, mutex_thread_proc, event, 0, &dummy);
2139 ok(thread != 0, "CreateThread error %d\n", GetLastError());
2140 WaitForSingleObject(event, 3000);
2141 CloseHandle(thread);
2142
2143 ResetEvent(event);
2144
2145 SetLastError(0xdeadbeef);
2146 thread = CreateThread(NULL, 0, semaphore_thread_proc, event, 0, &dummy);
2147 ok(thread != 0, "CreateThread error %d\n", GetLastError());
2148 WaitForSingleObject(event, 3000);
2149 CloseHandle(thread);
2150
2151 ResetEvent(event);
2152 Sleep(100);
2153
2154 ok(attached_thread_count == 2, "attached thread count should be 2\n");
2155 for (i = 0; i < attached_thread_count; i++)
2156 {
2157 ret = GetExitCodeThread(attached_thread[i], &code);
2158 trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
2159 ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
2160 ok(code == STILL_ACTIVE, "expected thread exit code STILL_ACTIVE, got %u\n", code);
2161 }
2162
2163 ret = WaitForSingleObject(attached_thread[0], 0);
2164 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2165 ret = WaitForSingleObject(attached_thread[1], 0);
2166 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2167
2168 ret = WaitForSingleObject(event, 0);
2169 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2170 ret = WaitForSingleObject(mutex, 0);
2171 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2172 ret = WaitForSingleObject(semaphore, 0);
2173 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2174
2175 ret = pRtlDllShutdownInProgress();
2176 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2177
2178 SetLastError(0xdeadbeef);
2179 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, GetCurrentProcessId());
2180 ok(process != NULL, "OpenProcess error %d\n", GetLastError());
2181
2182 SetLastError(0xdeadbeef);
2183 ret = TerminateProcess(0, 195);
2184 ok(!ret, "TerminateProcess(0) should fail\n");
2185 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
2186
2187 Sleep(100);
2188
2189 affinity = 1;
2190 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
2191 ok(!ret, "NtSetInformationProcess error %#x\n", ret);
2192
2193 switch (test_dll_phase)
2194 {
2195 case 0:
2196 ret = pRtlDllShutdownInProgress();
2197 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2198
2199 trace("call NtTerminateProcess(0, 195)\n");
2200 ret = pNtTerminateProcess(0, 195);
2201 ok(!ret, "NtTerminateProcess error %#x\n", ret);
2202
2203 memset(&pbi, 0, sizeof(pbi));
2204 ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
2205 ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
2206 ok(pbi.ExitStatus == STILL_ACTIVE || pbi.ExitStatus == 195,
2207 "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus);
2208 affinity = 1;
2209 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
2210 ok(!ret, "NtSetInformationProcess error %#x\n", ret);
2211
2212 ret = pRtlDllShutdownInProgress();
2213 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2214
2215 hmod = GetModuleHandleA(dll_name);
2216 ok(hmod != 0, "DLL should not be unloaded\n");
2217
2218 SetLastError(0xdeadbeef);
2219 thread = CreateThread(NULL, 0, noop_thread_proc, &dummy, 0, &ret);
2220 ok(!thread || broken(thread != 0) /* before win7 */, "CreateThread should fail\n");
2221 if (!thread)
2222 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2223 else
2224 {
2225 ret = WaitForSingleObject(thread, 1000);
2226 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2227 CloseHandle(thread);
2228 }
2229
2230 trace("call LdrShutdownProcess()\n");
2231 pLdrShutdownProcess();
2232
2233 ret = pRtlDllShutdownInProgress();
2234 ok(ret, "RtlDllShutdownInProgress returned %d\n", ret);
2235
2236 hmod = GetModuleHandleA(dll_name);
2237 ok(hmod != 0, "DLL should not be unloaded\n");
2238
2239 memset(&pbi, 0, sizeof(pbi));
2240 ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
2241 ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
2242 ok(pbi.ExitStatus == STILL_ACTIVE || pbi.ExitStatus == 195,
2243 "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus);
2244 affinity = 1;
2245 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
2246 ok(!ret, "NtSetInformationProcess error %#x\n", ret);
2247 break;
2248
2249 case 1: /* normal ExitProcess */
2250 ret = pRtlDllShutdownInProgress();
2251 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2252 break;
2253
2254 case 2: /* ExitProcess will be called by the PROCESS_DETACH handler */
2255 ret = pRtlDllShutdownInProgress();
2256 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2257
2258 trace("call FreeLibrary(%p)\n", hmod);
2259 SetLastError(0xdeadbeef);
2260 ret = FreeLibrary(hmod);
2261 ok(ret, "FreeLibrary error %d\n", GetLastError());
2262 hmod = GetModuleHandleA(dll_name);
2263 ok(!hmod, "DLL should be unloaded\n");
2264
2265 if (test_dll_phase == 2)
2266 ok(0, "FreeLibrary+ExitProcess should never return\n");
2267
2268 ret = pRtlDllShutdownInProgress();
2269 ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
2270
2271 break;
2272
2273 case 3:
2274 trace("signalling thread exit\n");
2275 SetEvent(stop_event);
2276 CloseHandle(stop_event);
2277 break;
2278
2279 case 4:
2280 trace("setting loader_lock_event\n");
2281 SetEvent(loader_lock_event);
2282 WaitForSingleObject(ack_event, 1000);
2283 ok(inside_loader_lock != 0, "inside_loader_lock is not set\n");
2284
2285 /* calling NtTerminateProcess should not cause a deadlock */
2286 trace("call NtTerminateProcess(0, 198)\n");
2287 ret = pNtTerminateProcess(0, 198);
2288 ok(!ret, "NtTerminateProcess error %#x\n", ret);
2289
2290 *child_failures = winetest_get_failures();
2291
2292 /* Windows fails to release loader lock acquired from another thread,
2293 * so the LdrUnlockLoaderLock call fails here and ExitProcess deadlocks
2294 * later on, so NtTerminateProcess is used instead.
2295 */
2296 trace("call NtTerminateProcess(GetCurrentProcess(), 198)\n");
2297 pNtTerminateProcess(GetCurrentProcess(), 198);
2298 ok(0, "NtTerminateProcess should not return\n");
2299 break;
2300
2301 case 5:
2302 trace("setting peb_lock_event\n");
2303 SetEvent(peb_lock_event);
2304 WaitForSingleObject(ack_event, 1000);
2305 ok(inside_peb_lock != 0, "inside_peb_lock is not set\n");
2306
2307 *child_failures = winetest_get_failures();
2308
2309 /* calling ExitProcess should cause a deadlock */
2310 trace("call ExitProcess(198)\n");
2311 ExitProcess(198);
2312 ok(0, "ExitProcess should not return\n");
2313 break;
2314
2315 case 6:
2316 trace("setting heap_lock_event\n");
2317 SetEvent(heap_lock_event);
2318 WaitForSingleObject(ack_event, 1000);
2319 ok(inside_heap_lock != 0, "inside_heap_lock is not set\n");
2320
2321 *child_failures = winetest_get_failures();
2322
2323 /* calling ExitProcess should cause a deadlock */
2324 trace("call ExitProcess(1)\n");
2325 ExitProcess(1);
2326 ok(0, "ExitProcess should not return\n");
2327 break;
2328
2329 default:
2330 assert(0);
2331 break;
2332 }
2333
2334 if (test_dll_phase == 0) expected_code = 195;
2335 else if (test_dll_phase == 3) expected_code = 196;
2336 else if (test_dll_phase == 4) expected_code = 198;
2337 else expected_code = STILL_ACTIVE;
2338
2339 if (expected_code == STILL_ACTIVE)
2340 {
2341 ret = WaitForSingleObject(attached_thread[0], 100);
2342 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2343 ret = WaitForSingleObject(attached_thread[1], 100);
2344 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
2345 }
2346 else
2347 {
2348 ret = WaitForSingleObject(attached_thread[0], 2000);
2349 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2350 ret = WaitForSingleObject(attached_thread[1], 2000);
2351 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#x\n", ret);
2352 }
2353
2354 for (i = 0; i < attached_thread_count; i++)
2355 {
2356 ret = GetExitCodeThread(attached_thread[i], &code);
2357 trace("child: GetExitCodeThread(%u) => %d,%u\n", i, ret, code);
2358 ok(ret == 1, "GetExitCodeThread returned %d, expected 1\n", ret);
2359 ok(code == expected_code, "expected thread exit code %u, got %u\n", expected_code, code);
2360 }
2361
2362 *child_failures = winetest_get_failures();
2363
2364 trace("call ExitProcess(195)\n");
2365 ExitProcess(195);
2366 }
2367
2368 static void test_ExitProcess(void)
2369 {
2370 #include "pshpack1.h"
2371 #ifdef __x86_64__
2372 static struct section_data
2373 {
2374 BYTE mov_rax[2];
2375 void *target;
2376 BYTE jmp_rax[2];
2377 } section_data = { { 0x48,0xb8 }, dll_entry_point, { 0xff,0xe0 } };
2378 #else
2379 static struct section_data
2380 {
2381 BYTE mov_eax;
2382 void *target;
2383 BYTE jmp_eax[2];
2384 } section_data = { 0xb8, dll_entry_point, { 0xff,0xe0 } };
2385 #endif
2386 #include "poppack.h"
2387 DWORD dummy, file_align;
2388 HANDLE file, thread, process, hmap, hmap_dup;
2389 char temp_path[MAX_PATH], dll_name[MAX_PATH], cmdline[MAX_PATH * 2];
2390 DWORD ret, target_offset, old_prot;
2391 char **argv, buf[256];
2392 PROCESS_INFORMATION pi;
2393 STARTUPINFOA si = { sizeof(si) };
2394 CONTEXT ctx;
2395 struct PROCESS_BASIC_INFORMATION_PRIVATE pbi;
2396 MEMORY_BASIC_INFORMATION mbi;
2397 DWORD_PTR affinity;
2398 void *addr;
2399 LARGE_INTEGER offset;
2400 SIZE_T size;
2401 IMAGE_NT_HEADERS nt_header;
2402
2403 #if !defined(__i386__) && !defined(__x86_64__)
2404 skip("x86 specific ExitProcess test\n");
2405 return;
2406 #endif
2407
2408 if (!pRtlDllShutdownInProgress)
2409 {
2410 win_skip("RtlDllShutdownInProgress is not available on this platform (XP+)\n");
2411 return;
2412 }
2413 if (!pNtQueryInformationProcess || !pNtSetInformationProcess)
2414 {
2415 win_skip("NtQueryInformationProcess/NtSetInformationProcess are not available on this platform\n");
2416 return;
2417 }
2418 if (!pNtAllocateVirtualMemory || !pNtFreeVirtualMemory)
2419 {
2420 win_skip("NtAllocateVirtualMemory/NtFreeVirtualMemory are not available on this platform\n");
2421 return;
2422 }
2423
2424 /* prevent displaying of the "Unable to load this DLL" message box */
2425 SetErrorMode(SEM_FAILCRITICALERRORS);
2426
2427 GetTempPathA(MAX_PATH, temp_path);
2428 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
2429
2430 /*trace("creating %s\n", dll_name);*/
2431 file = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2432 if (file == INVALID_HANDLE_VALUE)
2433 {
2434 ok(0, "could not create %s\n", dll_name);
2435 return;
2436 }
2437
2438 SetLastError(0xdeadbeef);
2439 ret = WriteFile(file, &dos_header, sizeof(dos_header), &dummy, NULL);
2440 ok(ret, "WriteFile error %d\n", GetLastError());
2441
2442 nt_header = nt_header_template;
2443 nt_header.FileHeader.NumberOfSections = 1;
2444 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
2445 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL | IMAGE_FILE_RELOCS_STRIPPED;
2446
2447 nt_header.OptionalHeader.AddressOfEntryPoint = 0x1000;
2448 nt_header.OptionalHeader.SectionAlignment = 0x1000;
2449 nt_header.OptionalHeader.FileAlignment = 0x200;
2450 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000;
2451 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
2452 SetLastError(0xdeadbeef);
2453 ret = WriteFile(file, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
2454 ok(ret, "WriteFile error %d\n", GetLastError());
2455 SetLastError(0xdeadbeef);
2456 ret = WriteFile(file, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
2457 ok(ret, "WriteFile error %d\n", GetLastError());
2458
2459 section.SizeOfRawData = sizeof(section_data);
2460 section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
2461 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
2462 section.Misc.VirtualSize = sizeof(section_data);
2463 section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
2464 SetLastError(0xdeadbeef);
2465 ret = WriteFile(file, &section, sizeof(section), &dummy, NULL);
2466 ok(ret, "WriteFile error %d\n", GetLastError());
2467
2468 file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
2469 assert(file_align < sizeof(filler));
2470 SetLastError(0xdeadbeef);
2471 ret = WriteFile(file, filler, file_align, &dummy, NULL);
2472 ok(ret, "WriteFile error %d\n", GetLastError());
2473
2474 target_offset = SetFilePointer(file, 0, NULL, FILE_CURRENT) + FIELD_OFFSET(struct section_data, target);
2475
2476 /* section data */
2477 SetLastError(0xdeadbeef);
2478 ret = WriteFile(file, &section_data, sizeof(section_data), &dummy, NULL);
2479 ok(ret, "WriteFile error %d\n", GetLastError());
2480
2481 CloseHandle(file);
2482
2483 winetest_get_mainargs(&argv);
2484
2485 /* phase 0 */
2486 *child_failures = -1;
2487 sprintf(cmdline, "\"%s\" loader %s %u 0", argv[0], dll_name, target_offset);
2488 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2489 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2490 ret = WaitForSingleObject(pi.hProcess, 10000);
2491 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2492 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2493 GetExitCodeProcess(pi.hProcess, &ret);
2494 ok(ret == 195, "expected exit code 195, got %u\n", ret);
2495 if (*child_failures)
2496 {
2497 trace("%d failures in child process\n", *child_failures);
2498 winetest_add_failures(*child_failures);
2499 }
2500 CloseHandle(pi.hThread);
2501 CloseHandle(pi.hProcess);
2502
2503 /* phase 1 */
2504 *child_failures = -1;
2505 sprintf(cmdline, "\"%s\" loader %s %u 1", argv[0], dll_name, target_offset);
2506 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2507 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2508 ret = WaitForSingleObject(pi.hProcess, 10000);
2509 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2510 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2511 GetExitCodeProcess(pi.hProcess, &ret);
2512 ok(ret == 195, "expected exit code 195, got %u\n", ret);
2513 if (*child_failures)
2514 {
2515 trace("%d failures in child process\n", *child_failures);
2516 winetest_add_failures(*child_failures);
2517 }
2518 CloseHandle(pi.hThread);
2519 CloseHandle(pi.hProcess);
2520
2521 /* phase 2 */
2522 *child_failures = -1;
2523 sprintf(cmdline, "\"%s\" loader %s %u 2", argv[0], dll_name, target_offset);
2524 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2525 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2526 ret = WaitForSingleObject(pi.hProcess, 10000);
2527 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2528 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2529 GetExitCodeProcess(pi.hProcess, &ret);
2530 ok(ret == 197, "expected exit code 197, got %u\n", ret);
2531 if (*child_failures)
2532 {
2533 trace("%d failures in child process\n", *child_failures);
2534 winetest_add_failures(*child_failures);
2535 }
2536 CloseHandle(pi.hThread);
2537 CloseHandle(pi.hProcess);
2538
2539 /* phase 3 */
2540 *child_failures = -1;
2541 sprintf(cmdline, "\"%s\" loader %s %u 3", argv[0], dll_name, target_offset);
2542 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2543 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2544 ret = WaitForSingleObject(pi.hProcess, 10000);
2545 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2546 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2547 GetExitCodeProcess(pi.hProcess, &ret);
2548 ok(ret == 195, "expected exit code 195, got %u\n", ret);
2549 if (*child_failures)
2550 {
2551 trace("%d failures in child process\n", *child_failures);
2552 winetest_add_failures(*child_failures);
2553 }
2554 CloseHandle(pi.hThread);
2555 CloseHandle(pi.hProcess);
2556
2557 /* phase 4 */
2558 if (pLdrLockLoaderLock && pLdrUnlockLoaderLock)
2559 {
2560 *child_failures = -1;
2561 sprintf(cmdline, "\"%s\" loader %s %u 4", argv[0], dll_name, target_offset);
2562 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2563 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2564 ret = WaitForSingleObject(pi.hProcess, 10000);
2565 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2566 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
2567 GetExitCodeProcess(pi.hProcess, &ret);
2568 ok(ret == 198, "expected exit code 198, got %u\n", ret);
2569 if (*child_failures)
2570 {
2571 trace("%d failures in child process\n", *child_failures);
2572 winetest_add_failures(*child_failures);
2573 }
2574 CloseHandle(pi.hThread);
2575 CloseHandle(pi.hProcess);
2576 }
2577 else
2578 win_skip("LdrLockLoaderLock/LdrUnlockLoaderLock are not available on this platform\n");
2579
2580 /* phase 5 */
2581 if (pRtlAcquirePebLock && pRtlReleasePebLock)
2582 {
2583 *child_failures = -1;
2584 sprintf(cmdline, "\"%s\" loader %s %u 5", argv[0], dll_name, target_offset);
2585 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2586 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2587 ret = WaitForSingleObject(pi.hProcess, 5000);
2588 ok(ret == WAIT_TIMEOUT, "child process should fail to terminate\n");
2589 if (ret != WAIT_OBJECT_0)
2590 {
2591 trace("terminating child process\n");
2592 TerminateProcess(pi.hProcess, 199);
2593 }
2594 ret = WaitForSingleObject(pi.hProcess, 1000);
2595 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2596 GetExitCodeProcess(pi.hProcess, &ret);
2597 ok(ret == 199, "expected exit code 199, got %u\n", ret);
2598 if (*child_failures)
2599 {
2600 trace("%d failures in child process\n", *child_failures);
2601 winetest_add_failures(*child_failures);
2602 }
2603 CloseHandle(pi.hThread);
2604 CloseHandle(pi.hProcess);
2605 }
2606 else
2607 win_skip("RtlAcquirePebLock/RtlReleasePebLock are not available on this platform\n");
2608
2609 /* phase 6 */
2610 *child_failures = -1;
2611 sprintf(cmdline, "\"%s\" loader %s %u 6", argv[0], dll_name, target_offset);
2612 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2613 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
2614 ret = WaitForSingleObject(pi.hProcess, 5000);
2615 ok(ret == WAIT_TIMEOUT || broken(ret == WAIT_OBJECT_0) /* XP */, "child process should fail to terminate\n");
2616 if (ret != WAIT_OBJECT_0)
2617 {
2618 trace("terminating child process\n");
2619 TerminateProcess(pi.hProcess, 201);
2620 }
2621 ret = WaitForSingleObject(pi.hProcess, 1000);
2622 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
2623 GetExitCodeProcess(pi.hProcess, &ret);
2624 ok(ret == 201 || broken(ret == 1) /* XP */, "expected exit code 201, got %u\n", ret);
2625 if (*child_failures)
2626 {
2627 trace("%d failures in child process\n", *child_failures);
2628 winetest_add_failures(*child_failures);
2629 }
2630 CloseHandle(pi.hThread);
2631 CloseHandle(pi.hProcess);
2632
2633 /* test remote process termination */
2634 SetLastError(0xdeadbeef);
2635 ret = CreateProcessA(argv[0], NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
2636 ok(ret, "CreateProcess(%s) error %d\n", argv[0], GetLastError());
2637
2638 SetLastError(0xdeadbeef);
2639 addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
2640 ok(addr != NULL, "VirtualAllocEx error %d\n", GetLastError());
2641 SetLastError(0xdeadbeef);
2642 ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READONLY, &old_prot);
2643 ok(ret, "VirtualProtectEx error %d\n", GetLastError());
2644 ok(old_prot == PAGE_READWRITE, "expected PAGE_READWRITE, got %#x\n", old_prot);
2645 SetLastError(0xdeadbeef);
2646 size = VirtualQueryEx(pi.hProcess, NULL, &mbi, sizeof(mbi));
2647 ok(size == sizeof(mbi), "VirtualQueryEx error %d\n", GetLastError());
2648
2649 SetLastError(0xdeadbeef);
2650 ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size);
2651 ok(ret, "ReadProcessMemory error %d\n", GetLastError());
2652 ok(size == 4, "expected 4, got %lu\n", size);
2653
2654 SetLastError(0xdeadbeef);
2655 hmap = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
2656 ok(hmap != 0, "CreateFileMapping error %d\n", GetLastError());
2657
2658 SetLastError(0xdeadbeef);
2659 ret = DuplicateHandle(GetCurrentProcess(), hmap, pi.hProcess, &hmap_dup,
2660 0, FALSE, DUPLICATE_SAME_ACCESS);
2661 ok(ret, "DuplicateHandle error %d\n", GetLastError());
2662
2663 offset.u.LowPart = 0;
2664 offset.u.HighPart = 0;
2665 addr = NULL;
2666 size = 0;
2667 ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset,
2668 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
2669 ok(!ret, "NtMapViewOfSection error %#x\n", ret);
2670 ret = pNtUnmapViewOfSection(pi.hProcess, addr);
2671 ok(!ret, "NtUnmapViewOfSection error %#x\n", ret);
2672
2673 SetLastError(0xdeadbeef);
2674 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2675 ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError());
2676 SetLastError(0xdeadbeef);
2677 ctx.ContextFlags = CONTEXT_INTEGER;
2678 ret = GetThreadContext(thread, &ctx);
2679 ok(ret, "GetThreadContext error %d\n", GetLastError());
2680 SetLastError(0xdeadbeef);
2681 ctx.ContextFlags = CONTEXT_INTEGER;
2682 ret = SetThreadContext(thread, &ctx);
2683 ok(ret, "SetThreadContext error %d\n", GetLastError());
2684 SetLastError(0xdeadbeef);
2685 ret = SetThreadPriority(thread, 0);
2686 ok(ret, "SetThreadPriority error %d\n", GetLastError());
2687
2688 SetLastError(0xdeadbeef);
2689 ret = TerminateThread(thread, 199);
2690 ok(ret, "TerminateThread error %d\n", GetLastError());
2691 /* Calling GetExitCodeThread() without waiting for thread termination
2692 * leads to different results due to a race condition.
2693 */
2694 ret = WaitForSingleObject(thread, 1000);
2695 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
2696 GetExitCodeThread(thread, &ret);
2697 ok(ret == 199, "expected exit code 199, got %u\n", ret);
2698
2699 SetLastError(0xdeadbeef);
2700 ret = TerminateProcess(pi.hProcess, 198);
2701 ok(ret, "TerminateProcess error %d\n", GetLastError());
2702 /* Checking process state without waiting for process termination
2703 * leads to different results due to a race condition.
2704 */
2705 ret = WaitForSingleObject(pi.hProcess, 1000);
2706 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %x\n", ret);
2707
2708 SetLastError(0xdeadbeef);
2709 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pi.dwProcessId);
2710 ok(process != NULL, "OpenProcess error %d\n", GetLastError());
2711 CloseHandle(process);
2712
2713 memset(&pbi, 0, sizeof(pbi));
2714 ret = pNtQueryInformationProcess(pi.hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
2715 ok(!ret, "NtQueryInformationProcess error %#x\n", ret);
2716 ok(pbi.ExitStatus == 198, "expected 198, got %lu\n", pbi.ExitStatus);
2717 affinity = 1;
2718 ret = pNtSetInformationProcess(pi.hProcess, ProcessAffinityMask, &affinity, sizeof(affinity));
2719 ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#x\n", ret);
2720
2721 SetLastError(0xdeadbeef);
2722 ctx.ContextFlags = CONTEXT_INTEGER;
2723 ret = GetThreadContext(thread, &ctx);
2724 ok(!ret || broken(ret) /* XP 64-bit */, "GetThreadContext should fail\n");
2725 if (!ret)
2726 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
2727 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
2728 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
2729 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2730 SetLastError(0xdeadbeef);
2731 ctx.ContextFlags = CONTEXT_INTEGER;
2732 ret = SetThreadContext(thread, &ctx);
2733 ok(!ret || broken(ret) /* XP 64-bit */, "SetThreadContext should fail\n");
2734 if (!ret)
2735 ok(GetLastError() == ERROR_ACCESS_DENIED ||
2736 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
2737 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
2738 "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2739 SetLastError(0xdeadbeef);
2740 ret = SetThreadPriority(thread, 0);
2741 ok(ret, "SetThreadPriority error %d\n", GetLastError());
2742 CloseHandle(thread);
2743
2744 SetLastError(0xdeadbeef);
2745 ctx.ContextFlags = CONTEXT_INTEGER;
2746 ret = GetThreadContext(pi.hThread, &ctx);
2747 ok(!ret || broken(ret) /* XP 64-bit */, "GetThreadContext should fail\n");
2748 if (!ret)
2749 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
2750 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
2751 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
2752 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2753 SetLastError(0xdeadbeef);
2754 ctx.ContextFlags = CONTEXT_INTEGER;
2755 ret = SetThreadContext(pi.hThread, &ctx);
2756 ok(!ret || broken(ret) /* XP 64-bit */, "SetThreadContext should fail\n");
2757 if (!ret)
2758 ok(GetLastError() == ERROR_ACCESS_DENIED ||
2759 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
2760 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
2761 "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2762 SetLastError(0xdeadbeef);
2763 ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READWRITE, &old_prot);
2764 ok(!ret, "VirtualProtectEx should fail\n");
2765 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2766 SetLastError(0xdeadbeef);
2767 size = 0;
2768 ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size);
2769 ok(!ret, "ReadProcessMemory should fail\n");
2770 ok(GetLastError() == ERROR_PARTIAL_COPY || GetLastError() == ERROR_ACCESS_DENIED,
2771 "expected ERROR_PARTIAL_COPY, got %d\n", GetLastError());
2772 ok(!size, "expected 0, got %lu\n", size);
2773 SetLastError(0xdeadbeef);
2774 ret = VirtualFreeEx(pi.hProcess, addr, 0, MEM_RELEASE);
2775 ok(!ret, "VirtualFreeEx should fail\n");
2776 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2777 SetLastError(0xdeadbeef);
2778 addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
2779 ok(!addr, "VirtualAllocEx should fail\n");
2780 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2781 SetLastError(0xdeadbeef);
2782 size = VirtualQueryEx(pi.hProcess, NULL, &mbi, sizeof(mbi));
2783 ok(!size, "VirtualQueryEx should fail\n");
2784 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2785
2786 /* CloseHandle() call below leads to premature process termination
2787 * under some Windows versions.
2788 */
2789 if (0)
2790 {
2791 SetLastError(0xdeadbeef);
2792 ret = CloseHandle(hmap_dup);
2793 ok(ret, "CloseHandle should not fail\n");
2794 }
2795
2796 SetLastError(0xdeadbeef);
2797 ret = DuplicateHandle(GetCurrentProcess(), hmap, pi.hProcess, &hmap_dup,
2798 0, FALSE, DUPLICATE_SAME_ACCESS);
2799 ok(!ret, "DuplicateHandle should fail\n");
2800 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2801
2802 offset.u.LowPart = 0;
2803 offset.u.HighPart = 0;
2804 addr = NULL;
2805 size = 0;
2806 ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset,
2807 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
2808 ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#x\n", ret);
2809
2810 SetLastError(0xdeadbeef);
2811 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2812 ok(!thread, "CreateRemoteThread should fail\n");
2813 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2814
2815 SetLastError(0xdeadbeef);
2816 ret = DebugActiveProcess(pi.dwProcessId);
2817 ok(!ret, "DebugActiveProcess should fail\n");
2818 ok(GetLastError() == ERROR_ACCESS_DENIED /* 64-bit */ || GetLastError() == ERROR_NOT_SUPPORTED /* 32-bit */,
2819 "ERROR_ACCESS_DENIED, got %d\n", GetLastError());
2820
2821 GetExitCodeProcess(pi.hProcess, &ret);
2822 ok(ret == 198 || broken(ret != 198) /* some 32-bit XP version in a VM returns random exit code */,
2823 "expected exit code 198, got %u\n", ret);
2824 CloseHandle(pi.hThread);
2825 CloseHandle(pi.hProcess);
2826
2827 ret = DeleteFileA(dll_name);
2828 ok(ret, "DeleteFile error %d\n", GetLastError());
2829 }
2830
2831 static PVOID WINAPI failuredllhook(ULONG ul, DELAYLOAD_INFO* pd)
2832 {
2833 ok(ul == 4, "expected 4, got %u\n", ul);
2834 ok(!!pd, "no delayload info supplied\n");
2835 if (pd)
2836 {
2837 ok(pd->Size == sizeof(*pd), "got %u\n", pd->Size);
2838 ok(!!pd->DelayloadDescriptor, "no DelayloadDescriptor supplied\n");
2839 if (pd->DelayloadDescriptor)
2840 {
2841 ok(pd->DelayloadDescriptor->Attributes.AllAttributes == 1,
2842 "expected 1, got %u\n", pd->DelayloadDescriptor->Attributes.AllAttributes);
2843 ok(pd->DelayloadDescriptor->DllNameRVA == 0x2000,
2844 "expected 0x2000, got %x\n", pd->DelayloadDescriptor->DllNameRVA);
2845 ok(pd->DelayloadDescriptor->ModuleHandleRVA == 0x201a,
2846 "expected 0x201a, got %x\n", pd->DelayloadDescriptor->ModuleHandleRVA);
2847 ok(pd->DelayloadDescriptor->ImportAddressTableRVA > pd->DelayloadDescriptor->ModuleHandleRVA,
2848 "expected %x > %x\n", pd->DelayloadDescriptor->ImportAddressTableRVA,
2849 pd->DelayloadDescriptor->ModuleHandleRVA);
2850 ok(pd->DelayloadDescriptor->ImportNameTableRVA > pd->DelayloadDescriptor->ImportAddressTableRVA,
2851 "expected %x > %x\n", pd->DelayloadDescriptor->ImportNameTableRVA,
2852 pd->DelayloadDescriptor->ImportAddressTableRVA);
2853 ok(pd->DelayloadDescriptor->BoundImportAddressTableRVA == 0,
2854 "expected 0, got %x\n", pd->DelayloadDescriptor->BoundImportAddressTableRVA);
2855 ok(pd->DelayloadDescriptor->UnloadInformationTableRVA == 0,
2856 "expected 0, got %x\n", pd->DelayloadDescriptor->UnloadInformationTableRVA);
2857 ok(pd->DelayloadDescriptor->TimeDateStamp == 0,
2858 "expected 0, got %x\n", pd->DelayloadDescriptor->TimeDateStamp);
2859 }
2860
2861 ok(!!pd->ThunkAddress, "no ThunkAddress supplied\n");
2862 if (pd->ThunkAddress)
2863 ok(pd->ThunkAddress->u1.Ordinal, "no ThunkAddress value supplied\n");
2864
2865 ok(!!pd->TargetDllName, "no TargetDllName supplied\n");
2866 if (pd->TargetDllName)
2867 ok(!strcmp(pd->TargetDllName, "secur32.dll"),
2868 "expected \"secur32.dll\", got \"%s\"\n", pd->TargetDllName);
2869
2870 ok(pd->TargetApiDescriptor.ImportDescribedByName == 0,
2871 "expected 0, got %x\n", pd->TargetApiDescriptor.ImportDescribedByName);
2872 ok(pd->TargetApiDescriptor.Description.Ordinal == 0 ||
2873 pd->TargetApiDescriptor.Description.Ordinal == 999,
2874 "expected 0, got %x\n", pd->TargetApiDescriptor.Description.Ordinal);
2875
2876 ok(!!pd->TargetModuleBase, "no TargetModuleBase supplied\n");
2877 ok(pd->Unused == NULL, "expected NULL, got %p\n", pd->Unused);
2878 ok(pd->LastError, "no LastError supplied\n");
2879 }
2880 cb_count++;
2881 return (void*)0xdeadbeef;
2882 }
2883
2884 static void test_ResolveDelayLoadedAPI(void)
2885 {
2886 static const char test_dll[] = "secur32.dll";
2887 static const char test_func[] = "SealMessage";
2888 char temp_path[MAX_PATH];
2889 char dll_name[MAX_PATH];
2890 IMAGE_DELAYLOAD_DESCRIPTOR idd, *delaydir;
2891 IMAGE_THUNK_DATA itd32;
2892 HANDLE hfile;
2893 HMODULE hlib;
2894 DWORD dummy, file_size, i;
2895 WORD hint = 0;
2896 BOOL ret;
2897 IMAGE_NT_HEADERS nt_header;
2898
2899 static const struct test_data
2900 {
2901 BOOL func;
2902 UINT_PTR ordinal;
2903 BOOL succeeds;
2904 } td[] =
2905 {
2906 {
2907 TRUE, 0, TRUE
2908 },
2909 {
2910 FALSE, IMAGE_ORDINAL_FLAG | 2, TRUE
2911 },
2912 {
2913 FALSE, IMAGE_ORDINAL_FLAG | 5, TRUE
2914 },
2915 {
2916 FALSE, IMAGE_ORDINAL_FLAG | 0, FALSE
2917 },
2918 {
2919 FALSE, IMAGE_ORDINAL_FLAG | 999, FALSE
2920 },
2921 };
2922
2923 if (!pResolveDelayLoadedAPI)
2924 {
2925 win_skip("ResolveDelayLoadedAPI is not available\n");
2926 return;
2927 }
2928
2929 if (0) /* crashes on native */
2930 {
2931 SetLastError(0xdeadbeef);
2932 ok(!pResolveDelayLoadedAPI(NULL, NULL, NULL, NULL, NULL, 0),
2933 "ResolveDelayLoadedAPI succeeded\n");
2934 ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %x\n", GetLastError());
2935
2936 cb_count = 0;
2937 SetLastError(0xdeadbeef);
2938 ok(!pResolveDelayLoadedAPI(NULL, NULL, failuredllhook, NULL, NULL, 0),
2939 "ResolveDelayLoadedAPI succeeded\n");
2940 ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %x\n", GetLastError());
2941 ok(cb_count == 1, "Wrong callback count: %d\n", cb_count);
2942 }
2943
2944 GetTempPathA(MAX_PATH, temp_path);
2945 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
2946 trace("creating %s\n", dll_name);
2947 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2948 if (hfile == INVALID_HANDLE_VALUE)
2949 {
2950 ok(0, "could not create %s\n", dll_name);
2951 return;
2952 }
2953
2954 SetLastError(0xdeadbeef);
2955 ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
2956 ok(ret, "WriteFile error %d\n", GetLastError());
2957
2958 nt_header = nt_header_template;
2959 nt_header.FileHeader.NumberOfSections = 2;
2960 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
2961
2962 nt_header.OptionalHeader.SectionAlignment = 0x1000;
2963 nt_header.OptionalHeader.FileAlignment = 0x1000;
2964 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x2200;
2965 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + 2 * sizeof(IMAGE_SECTION_HEADER);
2966 nt_header.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
2967 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress = 0x1000;
2968 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size = 0x100;
2969
2970 SetLastError(0xdeadbeef);
2971 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
2972 ok(ret, "WriteFile error %d\n", GetLastError());
2973
2974 SetLastError(0xdeadbeef);
2975 ret = WriteFile(hfile, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
2976 ok(ret, "WriteFile error %d\n", GetLastError());
2977
2978 /* sections */
2979 section.PointerToRawData = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
2980 section.VirtualAddress = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
2981 section.Misc.VirtualSize = 2 * sizeof(idd);
2982 section.SizeOfRawData = section.Misc.VirtualSize;
2983 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
2984 SetLastError(0xdeadbeef);
2985 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
2986 ok(ret, "WriteFile error %d\n", GetLastError());
2987
2988 section.PointerToRawData = 0x2000;
2989 section.VirtualAddress = 0x2000;
2990 i = sizeof(td)/sizeof(td[0]);
2991 section.Misc.VirtualSize = sizeof(test_dll) + sizeof(hint) + sizeof(test_func) + sizeof(HMODULE) +
2992 2 * (i + 1) * sizeof(IMAGE_THUNK_DATA);
2993 ok(section.Misc.VirtualSize <= 0x1000, "Too much tests, add a new section!\n");
2994 section.SizeOfRawData = section.Misc.VirtualSize;
2995 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
2996 SetLastError(0xdeadbeef);
2997 ret = WriteFile(hfile, &section, sizeof(section), &dummy, NULL);
2998 ok(ret, "WriteFile error %d\n", GetLastError());
2999
3000 /* fill up to delay data */
3001 SetFilePointer( hfile, nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress, NULL, SEEK_SET );
3002
3003 /* delay data */
3004 idd.Attributes.AllAttributes = 1;
3005 idd.DllNameRVA = 0x2000;
3006 idd.ModuleHandleRVA = idd.DllNameRVA + sizeof(test_dll) + sizeof(hint) + sizeof(test_func);
3007 idd.ImportAddressTableRVA = idd.ModuleHandleRVA + sizeof(HMODULE);
3008 idd.ImportNameTableRVA = idd.ImportAddressTableRVA + (i + 1) * sizeof(IMAGE_THUNK_DATA);
3009 idd.BoundImportAddressTableRVA = 0;
3010 idd.UnloadInformationTableRVA = 0;
3011 idd.TimeDateStamp = 0;
3012
3013 SetLastError(0xdeadbeef);
3014 ret = WriteFile(hfile, &idd, sizeof(idd), &dummy, NULL);
3015 ok(ret, "WriteFile error %d\n", GetLastError());
3016
3017 SetLastError(0xdeadbeef);
3018 ret = WriteFile(hfile, filler, sizeof(idd), &dummy, NULL);
3019 ok(ret, "WriteFile error %d\n", GetLastError());
3020
3021 /* fill up to extended delay data */
3022 SetFilePointer( hfile, idd.DllNameRVA, NULL, SEEK_SET );
3023
3024 /* extended delay data */
3025 SetLastError(0xdeadbeef);
3026 ret = WriteFile(hfile, test_dll, sizeof(test_dll), &dummy, NULL);
3027 ok(ret, "WriteFile error %d\n", GetLastError());
3028
3029 SetLastError(0xdeadbeef);
3030 ret = WriteFile(hfile, &hint, sizeof(hint), &dummy, NULL);
3031 ok(ret, "WriteFile error %d\n", GetLastError());
3032
3033 SetLastError(0xdeadbeef);
3034 ret = WriteFile(hfile, test_func, sizeof(test_func), &dummy, NULL);
3035 ok(ret, "WriteFile error %d\n", GetLastError());
3036
3037 SetFilePointer( hfile, idd.ImportAddressTableRVA, NULL, SEEK_SET );
3038
3039 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
3040 {
3041 /* 0x1a00 is an empty space between delay data and extended delay data, real thunks are not necessary */
3042 itd32.u1.Function = nt_header.OptionalHeader.ImageBase + 0x1a00 + i * 0x20;
3043 SetLastError(0xdeadbeef);
3044 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
3045 ok(ret, "WriteFile error %d\n", GetLastError());
3046 }
3047
3048 itd32.u1.Function = 0;
3049 SetLastError(0xdeadbeef);
3050 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
3051 ok(ret, "WriteFile error %d\n", GetLastError());
3052
3053 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
3054 {
3055 if (td[i].func)
3056 itd32.u1.AddressOfData = idd.DllNameRVA + sizeof(test_dll);
3057 else
3058 itd32.u1.Ordinal = td[i].ordinal;
3059 SetLastError(0xdeadbeef);
3060 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
3061 ok(ret, "WriteFile error %d\n", GetLastError());
3062 }
3063
3064 itd32.u1.Ordinal = 0;
3065 SetLastError(0xdeadbeef);
3066 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
3067 ok(ret, "WriteFile error %d\n", GetLastError());
3068
3069 /* fill up to eof */
3070 SetFilePointer( hfile, section.VirtualAddress + section.Misc.VirtualSize, NULL, SEEK_SET );
3071 SetEndOfFile( hfile );
3072 CloseHandle(hfile);
3073
3074 SetLastError(0xdeadbeef);
3075 hlib = LoadLibraryA(dll_name);
3076 ok(hlib != NULL, "LoadLibrary error %u\n", GetLastError());
3077 if (!hlib)
3078 {
3079 skip("couldn't load %s.\n", dll_name);
3080 DeleteFileA(dll_name);
3081 return;
3082 }
3083
3084 delaydir = pRtlImageDirectoryEntryToData(hlib, TRUE, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, &file_size);
3085 if (!delaydir)
3086 {
3087 skip("haven't found section for delay import directory.\n");
3088 FreeLibrary(hlib);
3089 DeleteFileA(dll_name);
3090 return;
3091 }
3092
3093 for (;;)
3094 {
3095 IMAGE_THUNK_DATA *itdn, *itda;
3096 HMODULE htarget;
3097
3098 if (!delaydir->DllNameRVA ||
3099 !delaydir->ImportAddressTableRVA ||
3100 !delaydir->ImportNameTableRVA) break;
3101
3102 itdn = RVAToAddr(delaydir->ImportNameTableRVA, hlib);
3103 itda = RVAToAddr(delaydir->ImportAddressTableRVA, hlib);
3104 htarget = LoadLibraryA(RVAToAddr(delaydir->DllNameRVA, hlib));
3105
3106 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
3107 {
3108 void *ret, *load;
3109
3110 if (IMAGE_SNAP_BY_ORDINAL(itdn[i].u1.Ordinal))
3111 load = (void *)GetProcAddress(htarget, (LPSTR)IMAGE_ORDINAL(itdn[i].u1.Ordinal));
3112 else
3113 {
3114 const IMAGE_IMPORT_BY_NAME* iibn = RVAToAddr(itdn[i].u1.AddressOfData, hlib);
3115 load = (void *)GetProcAddress(htarget, (char*)iibn->Name);
3116 }
3117
3118 cb_count = 0;
3119 ret = pResolveDelayLoadedAPI(hlib, delaydir, failuredllhook, NULL, &itda[i], 0);
3120 if (td[i].succeeds)
3121 {
3122 ok(ret != NULL, "Test %u: ResolveDelayLoadedAPI failed\n", i);
3123 ok(ret == load, "Test %u: expected %p, got %p\n", i, load, ret);
3124 ok(ret == (void*)itda[i].u1.AddressOfData, "Test %u: expected %p, got %p\n",
3125 i, ret, (void*)itda[i].u1.AddressOfData);
3126 ok(!cb_count, "Test %u: Wrong callback count: %d\n", i, cb_count);
3127 }
3128 else
3129 {
3130 ok(ret == (void*)0xdeadbeef, "Test %u: ResolveDelayLoadedAPI succeeded with %p\n", i, ret);
3131 ok(cb_count, "Test %u: Wrong callback count: %d\n", i, cb_count);
3132 }
3133 }
3134 delaydir++;
3135 }
3136
3137 FreeLibrary(hlib);
3138 trace("deleting %s\n", dll_name);
3139 DeleteFileA(dll_name);
3140 }
3141
3142 static void test_InMemoryOrderModuleList(void)
3143 {
3144 PEB_LDR_DATA *ldr = NtCurrentTeb()->Peb->LdrData;
3145 LIST_ENTRY *entry1, *mark1 = &ldr->InLoadOrderModuleList;
3146 LIST_ENTRY *entry2, *mark2 = &ldr->InMemoryOrderModuleList;
3147 LDR_MODULE *module1, *module2;
3148
3149 ok(ldr->Initialized == TRUE, "expected TRUE, got %u\n", ldr->Initialized);
3150
3151 for (entry1 = mark1->Flink, entry2 = mark2->Flink;
3152 entry1 != mark1 && entry2 != mark2;
3153 entry1 = entry1->Flink, entry2 = entry2->Flink)
3154 {
3155 module1 = CONTAINING_RECORD(entry1, LDR_MODULE, InLoadOrderModuleList);
3156 module2 = CONTAINING_RECORD(entry2, LDR_MODULE, InMemoryOrderModuleList);
3157 ok(module1 == module2, "expected module1 == module2, got %p and %p\n", module1, module2);
3158 }
3159 ok(entry1 == mark1, "expected entry1 == mark1, got %p and %p\n", entry1, mark1);
3160 ok(entry2 == mark2, "expected entry2 == mark2, got %p and %p\n", entry2, mark2);
3161 }
3162
3163 static inline WCHAR toupperW(WCHAR c)
3164 {
3165 WCHAR tmp = c;
3166 CharUpperBuffW(&tmp, 1);
3167 return tmp;
3168 }
3169
3170 static ULONG hash_basename(const WCHAR *basename)
3171 {
3172 WORD version = MAKEWORD(NtCurrentTeb()->Peb->OSMinorVersion,
3173 NtCurrentTeb()->Peb->OSMajorVersion);
3174 ULONG hash = 0;
3175
3176 if (version >= 0x0602)
3177 {
3178 for (; *basename; basename++)
3179 hash = hash * 65599 + toupperW(*basename);
3180 }
3181 else if (version == 0x0601)
3182 {
3183 for (; *basename; basename++)
3184 hash = hash + 65599 * toupperW(*basename);
3185 }
3186 else
3187 hash = toupperW(basename[0]) - 'A';
3188
3189 return hash & 31;
3190 }
3191
3192 static void test_HashLinks(void)
3193 {
3194 static WCHAR ntdllW[] = {'n','t','d','l','l','.','d','l','l',0};
3195 static WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
3196
3197 LIST_ENTRY *hash_map, *entry, *mark;
3198 LDR_MODULE *module;
3199 BOOL found;
3200
3201 entry = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
3202 entry = entry->Flink;
3203
3204 module = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
3205 entry = module->HashLinks.Blink;
3206
3207 hash_map = entry - hash_basename(module->BaseDllName.Buffer);
3208
3209 mark = &hash_map[hash_basename(ntdllW)];
3210 found = FALSE;
3211 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
3212 {
3213 module = CONTAINING_RECORD(entry, LDR_MODULE, HashLinks);
3214 if (!lstrcmpiW(module->BaseDllName.Buffer, ntdllW))
3215 {
3216 found = TRUE;
3217 break;
3218 }
3219 }
3220 ok(found, "Could not find ntdll\n");
3221
3222 mark = &hash_map[hash_basename(kernel32W)];
3223 found = FALSE;
3224 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
3225 {
3226 module = CONTAINING_RECORD(entry, LDR_MODULE, HashLinks);
3227 if (!lstrcmpiW(module->BaseDllName.Buffer, kernel32W))
3228 {
3229 found = TRUE;
3230 break;
3231 }
3232 }
3233 ok(found, "Could not find kernel32\n");
3234 }
3235
3236 START_TEST(loader)
3237 {
3238 int argc;
3239 char **argv;
3240 HANDLE ntdll, mapping, kernel32;
3241 SYSTEM_INFO si;
3242
3243 ntdll = GetModuleHandleA("ntdll.dll");
3244 kernel32 = GetModuleHandleA("kernel32.dll");
3245 pNtCreateSection = (void *)GetProcAddress(ntdll, "NtCreateSection");
3246 pNtQuerySection = (void *)GetProcAddress(ntdll, "NtQuerySection");
3247 pNtMapViewOfSection = (void *)GetProcAddress(ntdll, "NtMapViewOfSection");
3248 pNtUnmapViewOfSection = (void *)GetProcAddress(ntdll, "NtUnmapViewOfSection");
3249 pNtTerminateProcess = (void *)GetProcAddress(ntdll, "NtTerminateProcess");
3250 pNtQueryInformationProcess = (void *)GetProcAddress(ntdll, "NtQueryInformationProcess");
3251 pNtSetInformationProcess = (void *)GetProcAddress(ntdll, "NtSetInformationProcess");
3252 pLdrShutdownProcess = (void *)GetProcAddress(ntdll, "LdrShutdownProcess");
3253 pRtlDllShutdownInProgress = (void *)GetProcAddress(ntdll, "RtlDllShutdownInProgress");
3254 pNtAllocateVirtualMemory = (void *)GetProcAddress(ntdll, "NtAllocateVirtualMemory");
3255 pNtFreeVirtualMemory = (void *)GetProcAddress(ntdll, "NtFreeVirtualMemory");
3256 pLdrLockLoaderLock = (void *)GetProcAddress(ntdll, "LdrLockLoaderLock");
3257 pLdrUnlockLoaderLock = (void *)GetProcAddress(ntdll, "LdrUnlockLoaderLock");
3258 pRtlAcquirePebLock = (void *)GetProcAddress(ntdll, "RtlAcquirePebLock");
3259 pRtlReleasePebLock = (void *)GetProcAddress(ntdll, "RtlReleasePebLock");
3260 pRtlImageDirectoryEntryToData = (void *)GetProcAddress(ntdll, "RtlImageDirectoryEntryToData");
3261 pFlsAlloc = (void *)GetProcAddress(kernel32, "FlsAlloc");
3262 pFlsSetValue = (void *)GetProcAddress(kernel32, "FlsSetValue");
3263 pFlsGetValue = (void *)GetProcAddress(kernel32, "FlsGetValue");
3264 pFlsFree = (void *)GetProcAddress(kernel32, "FlsFree");
3265 pResolveDelayLoadedAPI = (void *)GetProcAddress(kernel32, "ResolveDelayLoadedAPI");
3266
3267 GetSystemInfo( &si );
3268 page_size = si.dwPageSize;
3269 dos_header.e_magic = IMAGE_DOS_SIGNATURE;
3270 dos_header.e_lfanew = sizeof(dos_header);
3271
3272 mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_loader");
3273 ok(mapping != 0, "CreateFileMapping failed\n");
3274 child_failures = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 4096);
3275 if (*child_failures == -1)
3276 {
3277 *child_failures = 0;
3278 }
3279 else
3280 *child_failures = -1;
3281
3282 argc = winetest_get_mainargs(&argv);
3283 if (argc > 4)
3284 {
3285 test_dll_phase = atoi(argv[4]);
3286 child_process(argv[2], atol(argv[3]));
3287 return;
3288 }
3289
3290 test_Loader();
3291 test_FakeDLL();
3292 test_ResolveDelayLoadedAPI();
3293 test_ImportDescriptors();
3294 test_section_access();
3295 test_import_resolution();
3296 test_ExitProcess();
3297 test_InMemoryOrderModuleList();
3298 test_HashLinks();
3299 }