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