Reactos
1/*
2 * Unit test suite for the PE loader.
3 *
4 * Copyright 2006,2011 Dmitry Timoshkov
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21#include <stdarg.h>
22#include <stdio.h>
23#include <assert.h>
24
25#include "ntstatus.h"
26#define WIN32_NO_STATUS
27#include "windef.h"
28#include "winbase.h"
29#include "winternl.h"
30#include "winnls.h"
31#include "wine/test.h"
32#include "delayloadhandler.h"
33#ifdef __REACTOS__
34#include "winehacks.h"
35#endif
36
37/* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
38#define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
39
40#define ALIGN_SIZE(size, alignment) (((size) + ((ULONG_PTR)(alignment) - 1)) & ~(((ULONG_PTR)(alignment) - 1)))
41
42struct PROCESS_BASIC_INFORMATION_PRIVATE
43{
44 NTSTATUS ExitStatus;
45 PPEB PebBaseAddress;
46 DWORD_PTR AffinityMask;
47 DWORD_PTR BasePriority;
48 ULONG_PTR UniqueProcessId;
49 ULONG_PTR InheritedFromUniqueProcessId;
50};
51
52static LONG *child_failures;
53static WORD cb_count, cb_count_sys;
54static DWORD page_size;
55static BOOL is_win64 = sizeof(void *) > sizeof(int);
56static BOOL is_wow64;
57static char system_dir[MAX_PATH];
58static char syswow_dir[MAX_PATH]; /* only available if is_wow64 */
59
60static NTSTATUS (WINAPI *pNtCreateSection)(HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *,
61 const LARGE_INTEGER *, ULONG, ULONG, HANDLE );
62static NTSTATUS (WINAPI *pNtQuerySection)(HANDLE, SECTION_INFORMATION_CLASS, void *, SIZE_T, SIZE_T *);
63static NTSTATUS (WINAPI *pNtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG_PTR, SIZE_T, const LARGE_INTEGER *, SIZE_T *, ULONG, ULONG, ULONG);
64static NTSTATUS (WINAPI *pNtUnmapViewOfSection)(HANDLE, PVOID);
65static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
66static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
67static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE, DWORD);
68static void (WINAPI *pLdrShutdownProcess)(void);
69static BOOLEAN (WINAPI *pRtlDllShutdownInProgress)(void);
70static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG_PTR, SIZE_T *, ULONG, ULONG);
71static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG);
72static NTSTATUS (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG *, ULONG_PTR *);
73static NTSTATUS (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG_PTR);
74static NTSTATUS (WINAPI *pLdrLoadDll)(LPCWSTR,DWORD,const UNICODE_STRING *,HMODULE*);
75static NTSTATUS (WINAPI *pLdrUnloadDll)(HMODULE);
76static void (WINAPI *pRtlInitUnicodeString)(PUNICODE_STRING,LPCWSTR);
77static void (WINAPI *pRtlAcquirePebLock)(void);
78static void (WINAPI *pRtlReleasePebLock)(void);
79static PVOID (WINAPI *pResolveDelayLoadedAPI)(PVOID, PCIMAGE_DELAYLOAD_DESCRIPTOR,
80 PDELAYLOAD_FAILURE_DLL_CALLBACK,
81 PDELAYLOAD_FAILURE_SYSTEM_ROUTINE,
82 PIMAGE_THUNK_DATA ThunkAddress,ULONG);
83static PVOID (WINAPI *pRtlImageDirectoryEntryToData)(HMODULE,BOOL,WORD,ULONG *);
84static PIMAGE_NT_HEADERS (WINAPI *pRtlImageNtHeader)(HMODULE);
85static DWORD (WINAPI *pFlsAlloc)(PFLS_CALLBACK_FUNCTION);
86static BOOL (WINAPI *pFlsSetValue)(DWORD, PVOID);
87static PVOID (WINAPI *pFlsGetValue)(DWORD);
88static BOOL (WINAPI *pFlsFree)(DWORD);
89static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
90static BOOL (WINAPI *pWow64DisableWow64FsRedirection)(void **);
91static BOOL (WINAPI *pWow64RevertWow64FsRedirection)(void *);
92static HMODULE (WINAPI *pLoadPackagedLibrary)(LPCWSTR lpwLibFileName, DWORD Reserved);
93static NTSTATUS (WINAPI *pLdrRegisterDllNotification)(ULONG, PLDR_DLL_NOTIFICATION_FUNCTION, void *, void **);
94
95static PVOID RVAToAddr(DWORD_PTR rva, HMODULE module)
96{
97 if (rva == 0)
98 return NULL;
99 return ((char*) module) + rva;
100}
101
102static IMAGE_DOS_HEADER dos_header;
103
104static const IMAGE_NT_HEADERS nt_header_template =
105{
106 IMAGE_NT_SIGNATURE, /* Signature */
107 {
108#if defined __i386__
109 IMAGE_FILE_MACHINE_I386, /* Machine */
110#elif defined __x86_64__
111 IMAGE_FILE_MACHINE_AMD64, /* Machine */
112#elif defined __arm__
113 IMAGE_FILE_MACHINE_ARMNT, /* Machine */
114#elif defined __aarch64__
115 IMAGE_FILE_MACHINE_ARM64, /* Machine */
116#else
117# error You must specify the machine type
118#endif
119 1, /* NumberOfSections */
120 0, /* TimeDateStamp */
121 0, /* PointerToSymbolTable */
122 0, /* NumberOfSymbols */
123 sizeof(IMAGE_OPTIONAL_HEADER), /* SizeOfOptionalHeader */
124 IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL /* Characteristics */
125 },
126 { IMAGE_NT_OPTIONAL_HDR_MAGIC, /* Magic */
127 1, /* MajorLinkerVersion */
128 0, /* MinorLinkerVersion */
129 0, /* SizeOfCode */
130 0, /* SizeOfInitializedData */
131 0, /* SizeOfUninitializedData */
132 0, /* AddressOfEntryPoint */
133 0x10, /* BaseOfCode, also serves as e_lfanew in the truncated MZ header */
134#ifndef _WIN64
135 0, /* BaseOfData */
136 0x10000000, /* ImageBase */
137#else
138 0x123450000, /* ImageBase */
139#endif
140 0, /* SectionAlignment */
141 0, /* FileAlignment */
142 4, /* MajorOperatingSystemVersion */
143 0, /* MinorOperatingSystemVersion */
144 1, /* MajorImageVersion */
145 0, /* MinorImageVersion */
146 4, /* MajorSubsystemVersion */
147 0, /* MinorSubsystemVersion */
148 0, /* Win32VersionValue */
149 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000, /* SizeOfImage */
150 sizeof(dos_header) + sizeof(nt_header_template), /* SizeOfHeaders */
151 0, /* CheckSum */
152 IMAGE_SUBSYSTEM_WINDOWS_CUI, /* Subsystem */
153 IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT, /* DllCharacteristics */
154 0x100000, /* SizeOfStackReserve */
155 0x1000, /* SizeOfStackCommit */
156 0x100000, /* SizeOfHeapReserve */
157 0x1000, /* SizeOfHeapCommit */
158 0, /* LoaderFlags */
159 IMAGE_NUMBEROF_DIRECTORY_ENTRIES, /* NumberOfRvaAndSizes */
160 { { 0 } } /* DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] */
161 }
162};
163
164static IMAGE_SECTION_HEADER section =
165{
166 ".rodata", /* Name */
167 { 0 }, /* Misc */
168 0, /* VirtualAddress */
169 0, /* SizeOfRawData */
170 0, /* PointerToRawData */
171 0, /* PointerToRelocations */
172 0, /* PointerToLinenumbers */
173 0, /* NumberOfRelocations */
174 0, /* NumberOfLinenumbers */
175 IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, /* Characteristics */
176};
177
178
179static const char filler[0x1000];
180static const char section_data[0x10] = "section data";
181
182/* return an alternate machine of the same 32/64 bitness */
183static WORD get_alt_machine( WORD orig_machine )
184{
185 switch (orig_machine)
186 {
187 case IMAGE_FILE_MACHINE_I386: return IMAGE_FILE_MACHINE_ARMNT;
188 case IMAGE_FILE_MACHINE_AMD64: return IMAGE_FILE_MACHINE_ARM64;
189 case IMAGE_FILE_MACHINE_ARMNT: return IMAGE_FILE_MACHINE_I386;
190 case IMAGE_FILE_MACHINE_ARM64: return IMAGE_FILE_MACHINE_AMD64;
191 }
192 return 0;
193}
194
195/* return the machine of the alternate 32/64 bitness */
196static WORD get_alt_bitness_machine( WORD orig_machine )
197{
198 switch (orig_machine)
199 {
200 case IMAGE_FILE_MACHINE_I386: return IMAGE_FILE_MACHINE_AMD64;
201 case IMAGE_FILE_MACHINE_AMD64: return IMAGE_FILE_MACHINE_I386;
202 case IMAGE_FILE_MACHINE_ARMNT: return IMAGE_FILE_MACHINE_ARM64;
203 case IMAGE_FILE_MACHINE_ARM64: return IMAGE_FILE_MACHINE_ARMNT;
204 }
205 return 0;
206}
207
208static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size,
209 const IMAGE_NT_HEADERS *nt_header, char dll_name[MAX_PATH] )
210{
211 char temp_path[MAX_PATH];
212 DWORD dummy, size, file_align;
213 HANDLE hfile;
214 BOOL ret;
215
216 GetTempPathA(MAX_PATH, temp_path);
217 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
218
219 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
220 ok( hfile != INVALID_HANDLE_VALUE, "failed to create %s err %lu\n", dll_name, GetLastError() );
221 if (hfile == INVALID_HANDLE_VALUE) return 0;
222
223 SetLastError(0xdeadbeef);
224 ret = WriteFile(hfile, dos_header, dos_size, &dummy, NULL);
225 ok(ret, "WriteFile error %ld\n", GetLastError());
226
227 SetLastError(0xdeadbeef);
228 ret = WriteFile(hfile, nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
229 ok(ret, "WriteFile error %ld\n", GetLastError());
230
231 if (nt_header->FileHeader.SizeOfOptionalHeader)
232 {
233 SetLastError(0xdeadbeef);
234 ret = WriteFile(hfile, &nt_header->OptionalHeader,
235 sizeof(IMAGE_OPTIONAL_HEADER),
236 &dummy, NULL);
237 ok(ret, "WriteFile error %ld\n", GetLastError());
238 if (nt_header->FileHeader.SizeOfOptionalHeader > sizeof(IMAGE_OPTIONAL_HEADER))
239 {
240 file_align = nt_header->FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER);
241 assert(file_align < sizeof(filler));
242 SetLastError(0xdeadbeef);
243 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
244 ok(ret, "WriteFile error %ld\n", GetLastError());
245 }
246 }
247
248 assert(nt_header->FileHeader.NumberOfSections <= 1);
249 if (nt_header->FileHeader.NumberOfSections)
250 {
251 SetFilePointer(hfile, dos_size + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + nt_header->FileHeader.SizeOfOptionalHeader, NULL, FILE_BEGIN);
252
253 section.SizeOfRawData = 10;
254
255 if (nt_header->OptionalHeader.SectionAlignment >= page_size)
256 {
257 section.PointerToRawData = dos_size;
258 section.VirtualAddress = nt_header->OptionalHeader.SectionAlignment;
259 section.Misc.VirtualSize = section.SizeOfRawData * 10;
260 }
261 else
262 {
263 section.PointerToRawData = nt_header->OptionalHeader.SizeOfHeaders;
264 section.VirtualAddress = nt_header->OptionalHeader.SizeOfHeaders;
265 section.Misc.VirtualSize = 5;
266 }
267
268 SetLastError(0xdeadbeef);
269 ret = WriteFile(hfile, §ion, sizeof(section), &dummy, NULL);
270 ok(ret, "WriteFile error %ld\n", GetLastError());
271
272 /* section data */
273 SetLastError(0xdeadbeef);
274 ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
275 ok(ret, "WriteFile error %ld\n", GetLastError());
276 }
277
278 /* Minimal PE image that Windows7+ is able to load: 268 bytes */
279 size = GetFileSize(hfile, NULL);
280 if (size < 268)
281 {
282 file_align = 268 - size;
283 SetLastError(0xdeadbeef);
284 ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
285 ok(ret, "WriteFile error %ld\n", GetLastError());
286 }
287
288 size = GetFileSize(hfile, NULL);
289 CloseHandle(hfile);
290 return size;
291}
292
293static DWORD create_test_dll_sections( const IMAGE_DOS_HEADER *dos_header, const IMAGE_NT_HEADERS *nt_header,
294 const IMAGE_SECTION_HEADER *sections, const void *section_data,
295 char dll_name[MAX_PATH] )
296{
297 char temp_path[MAX_PATH];
298 DWORD dummy, i, size;
299 HANDLE hfile;
300 BOOL ret;
301
302 GetTempPathA(MAX_PATH, temp_path);
303 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
304
305 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
306 ok( hfile != INVALID_HANDLE_VALUE, "failed to create %s err %lu\n", dll_name, GetLastError() );
307 if (hfile == INVALID_HANDLE_VALUE) return 0;
308
309 SetLastError(0xdeadbeef);
310 ret = WriteFile(hfile, dos_header, sizeof(*dos_header), &dummy, NULL);
311 ok(ret, "WriteFile error %ld\n", GetLastError());
312
313 SetLastError(0xdeadbeef);
314 ret = WriteFile(hfile, nt_header, offsetof(IMAGE_NT_HEADERS, OptionalHeader) + nt_header->FileHeader.SizeOfOptionalHeader, &dummy, NULL);
315 ok(ret, "WriteFile error %ld\n", GetLastError());
316
317 SetLastError(0xdeadbeef);
318 ret = WriteFile(hfile, sections, sizeof(*sections) * nt_header->FileHeader.NumberOfSections,
319 &dummy, NULL);
320 ok(ret, "WriteFile error %ld\n", GetLastError());
321
322 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
323 {
324 SetFilePointer(hfile, sections[i].PointerToRawData, NULL, FILE_BEGIN);
325 SetLastError(0xdeadbeef);
326 ret = WriteFile(hfile, section_data, sections[i].SizeOfRawData, &dummy, NULL);
327 ok(ret, "WriteFile error %ld\n", GetLastError());
328 }
329 size = GetFileSize(hfile, NULL);
330 CloseHandle(hfile);
331 return size;
332}
333
334static BOOL query_image_section( int id, const char *dll_name, const IMAGE_NT_HEADERS *nt_header,
335 const void *section_data )
336{
337 SECTION_BASIC_INFORMATION info;
338 SECTION_IMAGE_INFORMATION image;
339 const IMAGE_COR20_HEADER *cor_header = NULL;
340 SIZE_T info_size = (SIZE_T)0xdeadbeef << 16;
341 NTSTATUS status;
342 HANDLE file, mapping;
343 ULONG file_size;
344 LARGE_INTEGER map_size;
345 SIZE_T max_stack, commit_stack;
346 void *entry_point;
347 BOOL truncated;
348
349 file = CreateFileA( dll_name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE,
350 NULL, OPEN_EXISTING, 0, 0 );
351 ok( file != INVALID_HANDLE_VALUE, "%u: CreateFile error %ld\n", id, GetLastError() );
352 file_size = GetFileSize( file, NULL );
353
354 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
355 NULL, NULL, PAGE_READONLY, SEC_IMAGE, file );
356 ok( !status, "%u: NtCreateSection failed err %lx\n", id, status );
357 if (status)
358 {
359 CloseHandle( file );
360 return FALSE;
361 }
362 status = pNtQuerySection( mapping, SectionImageInformation, &image, sizeof(image), &info_size );
363 ok( !status, "%u: NtQuerySection failed err %lx\n", id, status );
364 ok( info_size == sizeof(image), "%u: NtQuerySection wrong size %Iu\n", id, info_size );
365 if (nt_header->OptionalHeader.Magic == (is_win64 ? IMAGE_NT_OPTIONAL_HDR64_MAGIC
366 : IMAGE_NT_OPTIONAL_HDR32_MAGIC))
367 {
368 max_stack = nt_header->OptionalHeader.SizeOfStackReserve;
369 commit_stack = nt_header->OptionalHeader.SizeOfStackCommit;
370 entry_point = (char *)nt_header->OptionalHeader.ImageBase + nt_header->OptionalHeader.AddressOfEntryPoint;
371 truncated = nt_header->FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER);
372 if (!truncated &&
373 nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress &&
374 nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
375 cor_header = section_data;
376 }
377 else if (nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
378 {
379 const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt_header;
380 max_stack = 0x100000;
381 commit_stack = 0x10000;
382 entry_point = (void *)0x81231234;
383 truncated = nt_header->FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER64);
384 if (!truncated &&
385 nt64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress &&
386 nt64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
387 cor_header = section_data;
388 }
389 else
390 {
391 const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt_header;
392 max_stack = nt32->OptionalHeader.SizeOfStackReserve;
393 commit_stack = nt32->OptionalHeader.SizeOfStackCommit;
394 entry_point = (char *)(ULONG_PTR)nt32->OptionalHeader.ImageBase + nt32->OptionalHeader.AddressOfEntryPoint;
395 truncated = nt_header->FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER32);
396 if (!truncated &&
397 nt32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress &&
398 nt32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
399 cor_header = section_data;
400 }
401 ok( (char *)image.TransferAddress == (char *)entry_point ||
402 (image.ImageDynamicallyRelocated && LOWORD(image.TransferAddress) == LOWORD(entry_point)),
403 "%u: TransferAddress wrong %p / %p (%08lx)\n", id,
404 image.TransferAddress, entry_point, nt_header->OptionalHeader.AddressOfEntryPoint );
405 ok( image.ZeroBits == 0, "%u: ZeroBits wrong %08lx\n", id, image.ZeroBits );
406 ok( image.MaximumStackSize == max_stack,
407 "%u: MaximumStackSize wrong %Ix / %Ix\n", id, image.MaximumStackSize, max_stack );
408 ok( image.CommittedStackSize == commit_stack,
409 "%u: CommittedStackSize wrong %Ix / %Ix\n", id, image.CommittedStackSize, commit_stack );
410 ok( image.SubSystemType == nt_header->OptionalHeader.Subsystem,
411 "%u: SubSystemType wrong %08lx / %08x\n", id,
412 image.SubSystemType, nt_header->OptionalHeader.Subsystem );
413 ok( image.MinorSubsystemVersion == nt_header->OptionalHeader.MinorSubsystemVersion,
414 "%u: MinorSubsystemVersion wrong %04x / %04x\n", id,
415 image.MinorSubsystemVersion, nt_header->OptionalHeader.MinorSubsystemVersion );
416 ok( image.MajorSubsystemVersion == nt_header->OptionalHeader.MajorSubsystemVersion,
417 "%u: MajorSubsystemVersion wrong %04x / %04x\n", id,
418 image.MajorSubsystemVersion, nt_header->OptionalHeader.MajorSubsystemVersion );
419 ok( image.MajorOperatingSystemVersion == nt_header->OptionalHeader.MajorOperatingSystemVersion ||
420 broken( !image.MajorOperatingSystemVersion), /* before win10 */
421 "%u: MajorOperatingSystemVersion wrong %04x / %04x\n", id,
422 image.MajorOperatingSystemVersion, nt_header->OptionalHeader.MajorOperatingSystemVersion );
423 ok( image.MinorOperatingSystemVersion == nt_header->OptionalHeader.MinorOperatingSystemVersion,
424 "%u: MinorOperatingSystemVersion wrong %04x / %04x\n", id,
425 image.MinorOperatingSystemVersion, nt_header->OptionalHeader.MinorOperatingSystemVersion );
426 ok( image.ImageCharacteristics == nt_header->FileHeader.Characteristics,
427 "%u: ImageCharacteristics wrong %04x / %04x\n", id,
428 image.ImageCharacteristics, nt_header->FileHeader.Characteristics );
429 ok( image.DllCharacteristics == nt_header->OptionalHeader.DllCharacteristics,
430 "%u: DllCharacteristics wrong %04x / %04x\n", id,
431 image.DllCharacteristics, nt_header->OptionalHeader.DllCharacteristics );
432 ok( image.Machine == nt_header->FileHeader.Machine, "%u: Machine wrong %04x / %04x\n", id,
433 image.Machine, nt_header->FileHeader.Machine );
434 ok( image.LoaderFlags == (cor_header != NULL), "%u: LoaderFlags wrong %08lx\n", id, image.LoaderFlags );
435 ok( image.ImageFileSize == file_size,
436 "%u: ImageFileSize wrong %08lx / %08lx\n", id, image.ImageFileSize, file_size );
437 ok( image.CheckSum == nt_header->OptionalHeader.CheckSum,
438 "%u: CheckSum wrong %08lx / %08lx\n", id,
439 image.CheckSum, nt_header->OptionalHeader.CheckSum );
440
441 if (nt_header->OptionalHeader.SizeOfCode || nt_header->OptionalHeader.AddressOfEntryPoint)
442 ok( image.ImageContainsCode == TRUE, "%u: ImageContainsCode wrong %u\n", id,
443 image.ImageContainsCode );
444 else if ((nt_header->OptionalHeader.SectionAlignment % page_size) ||
445 (nt_header->FileHeader.NumberOfSections == 1 &&
446 (section.Characteristics & IMAGE_SCN_MEM_EXECUTE)))
447 ok( image.ImageContainsCode == TRUE || broken(!image.ImageContainsCode), /* <= win8 */
448 "%u: ImageContainsCode wrong %u\n", id, image.ImageContainsCode );
449 else
450 ok( !image.ImageContainsCode, "%u: ImageContainsCode wrong %u\n", id, image.ImageContainsCode );
451
452 if (cor_header &&
453 (cor_header->Flags & COMIMAGE_FLAGS_ILONLY) &&
454 (cor_header->MajorRuntimeVersion > 2 ||
455 (cor_header->MajorRuntimeVersion == 2 && cor_header->MinorRuntimeVersion >= 5)))
456 {
457#ifdef __REACTOS__
458 ok( image.ComPlusILOnly || broken(GetNTVersion() < _WIN32_WINNT_VISTA),
459#else
460 ok( image.ComPlusILOnly,
461#endif
462 "%u: wrong ComPlusILOnly flags %02x\n", id, image.ImageFlags );
463 if (nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
464 !(cor_header->Flags & COMIMAGE_FLAGS_32BITREQUIRED))
465#ifdef __REACTOS__
466 ok( image.ComPlusNativeReady || broken(GetNTVersion() < _WIN32_WINNT_VISTA),
467#else
468 ok( image.ComPlusNativeReady,
469#endif
470 "%u: wrong ComPlusNativeReady flags %02x\n", id, image.ImageFlags );
471 else
472 ok( !image.ComPlusNativeReady,
473 "%u: wrong ComPlusNativeReady flags %02x\n", id, image.ImageFlags );
474 if (nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
475 (cor_header->Flags & COMIMAGE_FLAGS_32BITPREFERRED))
476 ok( image.ComPlusPrefer32bit ||
477 broken( !image.MajorOperatingSystemVersion ), /* before win10 */
478 "%u: wrong ComPlusPrefer32bit flags %02x\n", id, image.ImageFlags );
479 else
480 ok( !image.ComPlusPrefer32bit, "%u: wrong ComPlusPrefer32bit flags %02x\n", id, image.ImageFlags );
481 }
482 else
483 {
484 ok( !image.ComPlusILOnly, "%u: wrong ComPlusILOnly flags %02x\n", id, image.ImageFlags );
485 ok( !image.ComPlusNativeReady, "%u: wrong ComPlusNativeReady flags %02x\n", id, image.ImageFlags );
486 ok( !image.ComPlusPrefer32bit, "%u: wrong ComPlusPrefer32bit flags %02x\n", id, image.ImageFlags );
487 }
488 if (!(nt_header->OptionalHeader.SectionAlignment % page_size))
489 ok( !image.ImageMappedFlat, "%u: wrong ImageMappedFlat flags %02x\n", id, image.ImageFlags );
490 else
491#ifdef __REACTOS__
492 ok( image.ImageMappedFlat || broken(GetNTVersion() < _WIN32_WINNT_VISTA),
493#else
494 ok( image.ImageMappedFlat,
495#endif
496 "%u: wrong ImageMappedFlat flags %02x\n", id, image.ImageFlags );
497
498 if (!(nt_header->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE))
499 ok( !image.ImageDynamicallyRelocated || broken( image.ComPlusILOnly ), /* <= win7 */
500 "%u: wrong ImageDynamicallyRelocated flags %02x\n", id, image.ImageFlags );
501 else if (image.ImageContainsCode && !image.ImageMappedFlat && !cor_header)
502#ifdef __REACTOS__
503 ok( image.ImageDynamicallyRelocated || broken(GetNTVersion() < _WIN32_WINNT_VISTA),
504#else
505 ok( image.ImageDynamicallyRelocated,
506#endif
507 "%u: wrong ImageDynamicallyRelocated flags %02x\n", id, image.ImageFlags );
508 else
509 ok( !image.ImageDynamicallyRelocated || broken(TRUE), /* <= win8 */
510 "%u: wrong ImageDynamicallyRelocated flags %02x\n", id, image.ImageFlags );
511 ok( !image.BaseBelow4gb, "%u: wrong BaseBelow4gb flags %02x\n", id, image.ImageFlags );
512
513 map_size.QuadPart = (nt_header->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
514 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
515 ok( !status, "NtQuerySection failed err %lx\n", status );
516 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %lx%08lx / %lx%08lx\n",
517 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
518 CloseHandle( mapping );
519
520 map_size.QuadPart = (nt_header->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
521 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
522 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
523 ok( !status, "%u: NtCreateSection failed err %lx\n", id, status );
524 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
525 ok( !status, "NtQuerySection failed err %lx\n", status );
526 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %lx%08lx / %lx%08lx\n",
527 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
528 CloseHandle( mapping );
529
530 map_size.QuadPart++;
531 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
532 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
533 ok( status == STATUS_SECTION_TOO_BIG, "%u: NtCreateSection failed err %lx\n", id, status );
534
535 SetFilePointerEx( file, map_size, NULL, FILE_BEGIN );
536 SetEndOfFile( file );
537 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
538 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
539 ok( status == STATUS_SECTION_TOO_BIG, "%u: NtCreateSection failed err %lx\n", id, status );
540
541 map_size.QuadPart = 1;
542 status = pNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
543 NULL, &map_size, PAGE_READONLY, SEC_IMAGE, file );
544 ok( !status, "%u: NtCreateSection failed err %lx\n", id, status );
545 status = pNtQuerySection( mapping, SectionBasicInformation, &info, sizeof(info), NULL );
546 ok( !status, "NtQuerySection failed err %lx\n", status );
547 ok( info.Size.QuadPart == map_size.QuadPart, "NtQuerySection wrong size %lx%08lx / %lx%08lx\n",
548 info.Size.u.HighPart, info.Size.u.LowPart, map_size.u.HighPart, map_size.u.LowPart );
549 CloseHandle( mapping );
550
551 CloseHandle( file );
552 return image.ImageContainsCode && (!cor_header || !(cor_header->Flags & COMIMAGE_FLAGS_ILONLY));
553}
554
555static const WCHAR wldr_nameW[] = {'w','l','d','r','t','e','s','t','.','d','l','l',0};
556static WCHAR load_test_name[MAX_PATH], load_fallback_name[MAX_PATH];
557static WCHAR load_path[MAX_PATH];
558
559static void init_load_path( const char *fallback_dll )
560{
561 static const WCHAR pathW[] = {'P','A','T','H',0};
562 static const WCHAR ldrW[] = {'l','d','r',0};
563 static const WCHAR sepW[] = {';',0};
564 static const WCHAR bsW[] = {'\\',0};
565 WCHAR path[MAX_PATH];
566
567 GetTempPathW( MAX_PATH, path );
568 GetTempFileNameW( path, ldrW, 0, load_test_name );
569 GetTempFileNameW( path, ldrW, 0, load_fallback_name );
570 DeleteFileW( load_test_name );
571 ok( CreateDirectoryW( load_test_name, NULL ), "failed to create dir\n" );
572 DeleteFileW( load_fallback_name );
573 ok( CreateDirectoryW( load_fallback_name, NULL ), "failed to create dir\n" );
574 lstrcpyW( load_path, load_test_name );
575 lstrcatW( load_path, sepW );
576 lstrcatW( load_path, load_fallback_name );
577 lstrcatW( load_path, sepW );
578 GetEnvironmentVariableW( pathW, load_path + lstrlenW(load_path),
579 ARRAY_SIZE(load_path) - lstrlenW(load_path) );
580 lstrcatW( load_test_name, bsW );
581 lstrcatW( load_test_name, wldr_nameW );
582 lstrcatW( load_fallback_name, bsW );
583 lstrcatW( load_fallback_name, wldr_nameW );
584 MultiByteToWideChar( CP_ACP, 0, fallback_dll, -1, path, MAX_PATH );
585 MoveFileW( path, load_fallback_name );
586}
587
588static void delete_load_path(void)
589{
590 WCHAR *p;
591
592 DeleteFileW( load_test_name );
593 for (p = load_test_name + lstrlenW(load_test_name) - 1; *p != '\\'; p--) ;
594 *p = 0;
595 RemoveDirectoryW( load_test_name );
596 DeleteFileW( load_fallback_name );
597 for (p = load_fallback_name + lstrlenW(load_fallback_name) - 1; *p != '\\'; p--) ;
598 *p = 0;
599 RemoveDirectoryW( load_fallback_name );
600}
601
602static UINT get_com_dir_size( const IMAGE_NT_HEADERS *nt )
603{
604 if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
605 return ((const IMAGE_NT_HEADERS32 *)nt)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size;
606 else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
607 return ((const IMAGE_NT_HEADERS64 *)nt)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size;
608 else
609 return 0;
610}
611
612/* helper to test image section mapping */
613static NTSTATUS map_image_section( const IMAGE_NT_HEADERS *nt_header, const IMAGE_SECTION_HEADER *sections,
614 const void *section_data, int line )
615{
616 char dll_name[MAX_PATH];
617 WCHAR path[MAX_PATH];
618 UNICODE_STRING name;
619 LARGE_INTEGER size;
620 HANDLE file, map;
621 NTSTATUS status, expect_status, ldr_status;
622 ULONG file_size;
623 BOOL has_code = FALSE, il_only = FALSE, want_32bit = FALSE, expect_fallback = FALSE, wrong_machine = FALSE;
624 HMODULE mod = 0, ldr_mod;
625
626 file_size = create_test_dll_sections( &dos_header, nt_header, sections, section_data, dll_name );
627
628 file = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
629 ok(file != INVALID_HANDLE_VALUE, "CreateFile error %ld\n", GetLastError());
630
631 size.QuadPart = file_size;
632 status = pNtCreateSection(&map, STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ | SECTION_QUERY,
633 NULL, &size, PAGE_READONLY, SEC_IMAGE, file );
634 expect_status = status;
635
636 if (get_com_dir_size( nt_header ))
637 {
638 /* invalid COR20 header seems to corrupt internal loader state on Windows */
639 if (get_com_dir_size( nt_header ) < sizeof(IMAGE_COR20_HEADER)) goto done;
640 if (!((const IMAGE_COR20_HEADER *)section_data)->Flags) goto done;
641 }
642
643 if (!status)
644 {
645 SECTION_BASIC_INFORMATION info;
646 SIZE_T info_size = 0xdeadbeef;
647 NTSTATUS ret = pNtQuerySection( map, SectionBasicInformation, &info, sizeof(info), &info_size );
648 ok( !ret, "NtQuerySection failed err %lx\n", ret );
649 ok( info_size == sizeof(info), "NtQuerySection wrong size %Iu\n", info_size );
650 ok( info.Attributes == (SEC_IMAGE | SEC_FILE), "NtQuerySection wrong attr %lx\n", info.Attributes );
651 ok( info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", info.BaseAddress );
652 ok( info.Size.QuadPart == file_size, "NtQuerySection wrong size %lx%08lx / %08lx\n",
653 info.Size.u.HighPart, info.Size.u.LowPart, file_size );
654 has_code = query_image_section( line, dll_name, nt_header, section_data );
655
656 if (get_com_dir_size( nt_header ))
657 {
658 const IMAGE_COR20_HEADER *cor_header = section_data;
659 il_only = (cor_header->Flags & COMIMAGE_FLAGS_ILONLY) != 0;
660 if (il_only) want_32bit = (cor_header->Flags & COMIMAGE_FLAGS_32BITREQUIRED) != 0;
661 }
662
663 SetLastError( 0xdeadbeef );
664 mod = LoadLibraryExA( dll_name, 0, DONT_RESOLVE_DLL_REFERENCES );
665 /* test loading dll of wrong 32/64 bitness */
666 if (nt_header->OptionalHeader.Magic == (is_win64 ? IMAGE_NT_OPTIONAL_HDR32_MAGIC
667 : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
668 {
669 if (!has_code && is_win64)
670 {
671 ok_(__FILE__,line)( mod != NULL || want_32bit || broken(il_only), /* <= win7 */
672 "loading failed err %lu\n", GetLastError() );
673 }
674 else
675 {
676 ok_(__FILE__, line)( !mod, "loading succeeded\n" );
677 ok_(__FILE__, line)( GetLastError() == ERROR_BAD_EXE_FORMAT, "wrong error %lu\n", GetLastError() );
678 if (nt_header_template.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64)
679 {
680 wrong_machine = TRUE;
681 expect_status = STATUS_INVALID_IMAGE_FORMAT;
682 }
683 }
684 }
685 else
686 {
687 wrong_machine = (nt_header->FileHeader.Machine == get_alt_machine( nt_header_template.FileHeader.Machine ));
688
689 ok( mod != NULL || broken(il_only) || /* <= win7 */
690 broken( wrong_machine ), /* win8 */
691 "%u: loading failed err %lu\n", line, GetLastError() );
692 }
693 if (mod) FreeLibrary( mod );
694 expect_fallback = !mod;
695 }
696
697 /* test fallback to another dll further in the load path */
698
699 MultiByteToWideChar( CP_ACP, 0, dll_name, -1, path, MAX_PATH );
700 CopyFileW( path, load_test_name, FALSE );
701 pRtlInitUnicodeString( &name, wldr_nameW );
702 ldr_status = pLdrLoadDll( load_path, 0, &name, &ldr_mod );
703 if (!ldr_status)
704 {
705 GetModuleFileNameW( ldr_mod, path, MAX_PATH );
706 if (!lstrcmpiW( path, load_test_name ))
707 {
708 if (!expect_status)
709 ok( !expect_fallback, "%u: got test dll but expected fallback\n", line );
710 else
711 ok( !expect_fallback, "%u: got test dll but expected failure %lx\n", line, expect_status );
712 }
713 else if (!lstrcmpiW( path, load_fallback_name ))
714 {
715 trace( "%u: loaded fallback\n", line );
716#ifdef __REACTOS__
717 ok( !expect_status || broken(is_win64) /* Broken on Vista, 8.1 x64 */, "%u: got fallback but expected failure %lx\n", line, expect_status );
718 ok( expect_fallback || broken(is_win64) /* Broken on Vista, 8.1 x64 */ ||
719#else
720 ok( !expect_status, "%u: got fallback but expected failure %lx\n", line, expect_status );
721 ok( expect_fallback ||
722#endif
723 /* win10 also falls back for 32-bit dll without code, even though it could be loaded */
724 (is_win64 && !has_code &&
725 nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC),
726 "%u: got fallback but expected test dll\n", line );
727 }
728 else ok( 0, "%u: got unexpected path %s instead of %s\n", line, wine_dbgstr_w(path), wine_dbgstr_w(load_test_name));
729 pLdrUnloadDll( ldr_mod );
730 }
731 else if (ldr_status == STATUS_DLL_INIT_FAILED ||
732 ldr_status == STATUS_ACCESS_VIOLATION ||
733 ldr_status == STATUS_ILLEGAL_INSTRUCTION)
734 {
735 /* some dlls with invalid entry point will crash, but this means we loaded the test dll */
736#ifdef __REACTOS__
737 ok( !expect_fallback || broken(is_win64 && GetNTVersion() == _WIN32_WINNT_WIN8) /* Broken on 8.1 x64 */, "%u: got test dll but expected fallback\n", line );
738#else
739 ok( !expect_fallback, "%u: got test dll but expected fallback\n", line );
740#endif
741 }
742 else
743 {
744 ok( ldr_status == expect_status ||
745 (wrong_machine && !expect_status && ldr_status == STATUS_INVALID_IMAGE_FORMAT) ||
746 broken(il_only && !expect_status && ldr_status == STATUS_INVALID_IMAGE_FORMAT) ||
747 broken(nt_header->Signature == IMAGE_OS2_SIGNATURE && ldr_status == STATUS_INVALID_IMAGE_NE_FORMAT),
748 "%u: wrong status %lx/%lx\n", line, ldr_status, expect_status );
749 ok( !expect_fallback || wrong_machine || broken(il_only),
750 "%u: failed with %lx expected fallback\n", line, ldr_status );
751 }
752
753done:
754 if (map) CloseHandle( map );
755 CloseHandle( file );
756 DeleteFileA( dll_name );
757 return status;
758}
759
760
761static void test_Loader(void)
762{
763 static const struct test_data
764 {
765 DWORD size_of_dos_header;
766 WORD number_of_sections, size_of_optional_header;
767 DWORD section_alignment, file_alignment;
768 DWORD size_of_image, size_of_headers;
769 DWORD errors[4]; /* 0 means LoadLibrary should succeed */
770 } td[] =
771 {
772 { sizeof(dos_header),
773 1, 0, 0, 0, 0, 0,
774 { ERROR_BAD_EXE_FORMAT }
775 },
776 { sizeof(dos_header),
777 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
778 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0xe00,
779 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
780 { ERROR_BAD_EXE_FORMAT } /* XP doesn't like too small image size */
781 },
782 { sizeof(dos_header),
783 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
784 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
785 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
786 { ERROR_SUCCESS }
787 },
788 { sizeof(dos_header),
789 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x1000,
790 0x1f00,
791 0x1000,
792 { ERROR_SUCCESS }
793 },
794 { sizeof(dos_header),
795 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x200,
796 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x200,
797 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
798 { ERROR_SUCCESS, ERROR_INVALID_ADDRESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
799 },
800 { sizeof(dos_header),
801 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x1000,
802 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
803 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
804 { ERROR_BAD_EXE_FORMAT } /* XP doesn't like alignments */
805 },
806 { sizeof(dos_header),
807 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
808 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
809 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER),
810 { ERROR_SUCCESS }
811 },
812 { sizeof(dos_header),
813 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x1000, 0x200,
814 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
815 0x200,
816 { ERROR_SUCCESS }
817 },
818 /* Mandatory are all fields up to SizeOfHeaders, everything else
819 * is really optional (at least that's true for XP).
820 */
821#if 0 /* 32-bit Windows 8 crashes inside of LoadLibrary */
822 { sizeof(dos_header),
823 1, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
824 sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER) + 0x10,
825 sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER),
826 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT, ERROR_INVALID_ADDRESS,
827 ERROR_NOACCESS }
828 },
829#endif
830 { sizeof(dos_header),
831 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
832 0xd0, /* beyond of the end of file */
833 0xc0, /* beyond of the end of file */
834 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
835 },
836 { sizeof(dos_header),
837 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
838 0x1000,
839 0,
840 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
841 },
842 { sizeof(dos_header),
843 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
844 1,
845 0,
846 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
847 },
848#if 0 /* not power of 2 alignments need more test cases */
849 { sizeof(dos_header),
850 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x300, 0x300,
851 1,
852 0,
853 { ERROR_BAD_EXE_FORMAT } /* alignment is not power of 2 */
854 },
855#endif
856 { sizeof(dos_header),
857 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 4, 4,
858 1,
859 0,
860 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
861 },
862 { sizeof(dos_header),
863 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 1, 1,
864 1,
865 0,
866 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
867 },
868 { sizeof(dos_header),
869 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
870 0,
871 0,
872 { ERROR_BAD_EXE_FORMAT } /* image size == 0 -> failure */
873 },
874 /* the following data mimics the PE image which upack creates */
875 { 0x10,
876 1, 0x148, 0x1000, 0x200,
877 sizeof(dos_header) + sizeof(nt_header_template) + sizeof(IMAGE_SECTION_HEADER) + 0x1000,
878 0x200,
879 { ERROR_SUCCESS }
880 },
881 /* Minimal PE image that XP is able to load: 92 bytes */
882 { 0x04,
883 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum),
884 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
885 1,
886 0,
887 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* vista is more strict */
888 },
889 /* Minimal PE image initially created for Windows 7 and accepted from
890 * Vista up to Windows 10 1709 with some unexplained exceptions:
891 * 268 bytes
892 */
893 { 0x04,
894 0, 0xf0, /* optional header size just forces 0xf0 bytes to be written,
895 0 or another number don't change the behaviour, what really
896 matters is file size regardless of values in the headers */
897 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
898 0x40, /* minimal image size that Windows7 accepts */
899 0,
900 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT } /* rejected by win10 1809+ */
901 },
902 /* the following data mimics the PE image which 8k demos have */
903 { 0x04,
904 0, 0x08,
905 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
906 0x2000,
907 0x40,
908 { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT }
909 }
910 };
911 int i;
912 DWORD file_size;
913 HANDLE h;
914 HMODULE hlib, hlib_as_data_file;
915 char dll_name[MAX_PATH];
916 SIZE_T size;
917 BOOL ret;
918 NTSTATUS status;
919 WORD orig_machine = nt_header_template.FileHeader.Machine;
920 IMAGE_NT_HEADERS nt_header;
921 IMAGE_COR20_HEADER cor_header;
922
923 /* prevent displaying of the "Unable to load this DLL" message box */
924 SetErrorMode(SEM_FAILCRITICALERRORS);
925
926 for (i = 0; i < ARRAY_SIZE(td); i++)
927 {
928 winetest_push_context("%d", i);
929 nt_header = nt_header_template;
930 nt_header.FileHeader.NumberOfSections = td[i].number_of_sections;
931 nt_header.FileHeader.SizeOfOptionalHeader = td[i].size_of_optional_header;
932
933 nt_header.OptionalHeader.SectionAlignment = td[i].section_alignment;
934 nt_header.OptionalHeader.FileAlignment = td[i].file_alignment;
935 nt_header.OptionalHeader.SizeOfImage = td[i].size_of_image;
936 nt_header.OptionalHeader.SizeOfHeaders = td[i].size_of_headers;
937
938 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
939 file_size = create_test_dll( &dos_header, td[i].size_of_dos_header, &nt_header, dll_name );
940
941 SetLastError(0xdeadbeef);
942 hlib = LoadLibraryA(dll_name);
943 if (hlib)
944 {
945 MEMORY_BASIC_INFORMATION info;
946 void *ptr;
947
948 ok( td[i].errors[0] == ERROR_SUCCESS, "should have failed\n" );
949
950 SetLastError(0xdeadbeef);
951 size = VirtualQuery(hlib, &info, sizeof(info));
952 ok(size == sizeof(info),
953 "%d: VirtualQuery error %ld\n", i, GetLastError());
954 ok(info.BaseAddress == hlib, "%p != %p\n", info.BaseAddress, hlib);
955 ok(info.AllocationBase == hlib, "%p != %p\n", info.AllocationBase, hlib);
956 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
957 ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "got %Ix != expected %x\n",
958 info.RegionSize, (UINT)ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
959 ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State);
960 if (nt_header.OptionalHeader.SectionAlignment < page_size)
961 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.Protect);
962 else
963 ok(info.Protect == PAGE_READONLY, "%lx != PAGE_READONLY\n", info.Protect);
964 ok(info.Type == SEC_IMAGE, "%lx != SEC_IMAGE\n", info.Type);
965
966 SetLastError(0xdeadbeef);
967 ptr = VirtualAlloc(hlib, page_size, MEM_COMMIT, info.Protect);
968 ok(!ptr, "VirtualAlloc should fail\n");
969 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
970
971 SetLastError(0xdeadbeef);
972 size = VirtualQuery((char *)hlib + info.RegionSize, &info, sizeof(info));
973 ok(size == sizeof(info), "VirtualQuery error %ld\n", GetLastError());
974 if (nt_header.OptionalHeader.SectionAlignment == page_size ||
975 nt_header.OptionalHeader.SectionAlignment == nt_header.OptionalHeader.FileAlignment)
976 {
977 ok(info.BaseAddress == (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "got %p != expected %p\n",
978 info.BaseAddress, (char *)hlib + ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
979 ok(info.AllocationBase == 0, "%p != 0\n", info.AllocationBase);
980 ok(info.AllocationProtect == 0, "%lx != 0\n", info.AllocationProtect);
981 /*ok(info.RegionSize == not_practical_value, "%d: %lx != not_practical_value\n", i, info.RegionSize);*/
982 ok(info.State == MEM_FREE, "%lx != MEM_FREE\n", info.State);
983 ok(info.Type == 0, "%lx != 0\n", info.Type);
984 ok(info.Protect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.Protect);
985 }
986 else
987 {
988 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.Protect);
989 ok(info.BaseAddress == hlib, "got %p != expected %p\n", info.BaseAddress, hlib);
990 ok(info.AllocationBase == hlib, "%p != %p\n", info.AllocationBase, hlib);
991 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
992 ok(info.RegionSize == ALIGN_SIZE(file_size, page_size), "got %Ix != expected %x\n",
993 info.RegionSize, (UINT)ALIGN_SIZE(file_size, page_size));
994 ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State);
995 ok(info.Protect == PAGE_READONLY, "%lx != PAGE_READONLY\n", info.Protect);
996 ok(info.Type == SEC_IMAGE, "%lx != SEC_IMAGE\n", info.Type);
997 }
998
999 /* header: check the zeroing of alignment */
1000 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
1001 {
1002 const char *start;
1003
1004 start = (const char *)hlib + nt_header.OptionalHeader.SizeOfHeaders;
1005 size = ALIGN_SIZE((ULONG_PTR)start, page_size) - (ULONG_PTR)start;
1006 ok(!memcmp(start, filler, size), "header alignment is not cleared\n");
1007 }
1008
1009 if (nt_header.FileHeader.NumberOfSections)
1010 {
1011 SetLastError(0xdeadbeef);
1012 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
1013 ok(size == sizeof(info),
1014 "VirtualQuery error %ld\n", GetLastError());
1015 if (nt_header.OptionalHeader.SectionAlignment < page_size)
1016 {
1017 ok(info.BaseAddress == hlib, "got %p != expected %p\n", info.BaseAddress, hlib);
1018 ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size), "got %Ix != expected %x\n",
1019 info.RegionSize, (UINT)ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, page_size));
1020 ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.Protect);
1021 }
1022 else
1023 {
1024 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)hlib + section.VirtualAddress);
1025 ok(info.RegionSize == ALIGN_SIZE(section.Misc.VirtualSize, page_size), "got %Ix != expected %x\n",
1026 info.RegionSize, (UINT)ALIGN_SIZE(section.Misc.VirtualSize, page_size));
1027 ok(info.Protect == PAGE_READONLY, "%lx != PAGE_READONLY\n", info.Protect);
1028 }
1029 ok(info.AllocationBase == hlib, "%p != %p\n", info.AllocationBase, hlib);
1030 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1031 ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State);
1032 ok(info.Type == SEC_IMAGE, "%lx != SEC_IMAGE\n", info.Type);
1033
1034 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
1035 ok(!memcmp((const char *)hlib + section.VirtualAddress + section.PointerToRawData, &nt_header, section.SizeOfRawData), "wrong section data\n");
1036 else
1037 ok(!memcmp((const char *)hlib + section.PointerToRawData, section_data, section.SizeOfRawData), "wrong section data\n");
1038
1039 /* check the zeroing of alignment */
1040 if (nt_header.OptionalHeader.SectionAlignment >= page_size)
1041 {
1042 const char *start;
1043
1044 start = (const char *)hlib + section.VirtualAddress + section.PointerToRawData + section.SizeOfRawData;
1045 size = ALIGN_SIZE((ULONG_PTR)start, page_size) - (ULONG_PTR)start;
1046 ok(memcmp(start, filler, size), "alignment should not be cleared\n");
1047 }
1048
1049 SetLastError(0xdeadbeef);
1050 ptr = VirtualAlloc((char *)hlib + section.VirtualAddress, page_size, MEM_COMMIT, info.Protect);
1051 ok(!ptr, "VirtualAlloc should fail\n");
1052 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_INVALID_ADDRESS,
1053 "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
1054 }
1055
1056 SetLastError(0xdeadbeef);
1057 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
1058 ok(hlib_as_data_file != 0, "LoadLibraryEx error %lu\n", GetLastError());
1059 ok(hlib_as_data_file == hlib, "hlib_as_file and hlib are different\n");
1060
1061 SetLastError(0xdeadbeef);
1062 ret = FreeLibrary(hlib);
1063 ok(ret, "FreeLibrary error %ld\n", GetLastError());
1064
1065 SetLastError(0xdeadbeef);
1066 hlib = GetModuleHandleA(dll_name);
1067 ok(hlib != 0, "GetModuleHandle error %lu\n", GetLastError());
1068
1069 SetLastError(0xdeadbeef);
1070 ret = FreeLibrary(hlib_as_data_file);
1071 ok(ret, "FreeLibrary error %ld\n", GetLastError());
1072
1073 hlib = GetModuleHandleA(dll_name);
1074 ok(!hlib, "GetModuleHandle should fail\n");
1075
1076 SetLastError(0xdeadbeef);
1077 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE);
1078 ok(hlib_as_data_file != 0, "LoadLibraryEx error %lu\n", GetLastError());
1079 ok(((ULONG_PTR)hlib_as_data_file & 3) == 1, "hlib_as_data_file got %p\n", hlib_as_data_file);
1080
1081 hlib = GetModuleHandleA(dll_name);
1082 ok(!hlib, "GetModuleHandle should fail\n");
1083
1084 SetLastError(0xdeadbeef);
1085 h = CreateFileA( dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1086 ok( h != INVALID_HANDLE_VALUE, "open failed err %lu\n", GetLastError() );
1087 CloseHandle( h );
1088
1089 SetLastError(0xdeadbeef);
1090 ret = FreeLibrary(hlib_as_data_file);
1091 ok(ret, "FreeLibrary error %ld\n", GetLastError());
1092
1093 SetLastError(0xdeadbeef);
1094 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE);
1095#ifdef __REACTOS__
1096 if (!hlib_as_data_file && GetLastError() == ERROR_INVALID_PARAMETER) {
1097 skip("LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE not supported\n");
1098 FreeLibrary(hlib_as_data_file);
1099 } else {
1100#endif
1101 ok(hlib_as_data_file != 0, "LoadLibraryEx error %lu\n", GetLastError());
1102
1103 SetLastError(0xdeadbeef);
1104 h = CreateFileA( dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1105 ok( h == INVALID_HANDLE_VALUE, "open succeeded\n" );
1106 ok( GetLastError() == ERROR_SHARING_VIOLATION, "wrong error %lu\n", GetLastError() );
1107 CloseHandle( h );
1108
1109 SetLastError(0xdeadbeef);
1110 h = CreateFileA( dll_name, GENERIC_READ | DELETE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1111 ok( h != INVALID_HANDLE_VALUE, "open failed err %lu\n", GetLastError() );
1112 CloseHandle( h );
1113
1114 SetLastError(0xdeadbeef);
1115 ret = FreeLibrary(hlib_as_data_file);
1116 ok(ret, "FreeLibrary error %ld\n", GetLastError());
1117#ifdef __REACTOS__
1118 }
1119#endif
1120
1121 SetLastError(0xdeadbeef);
1122 hlib_as_data_file = LoadLibraryExA(dll_name, 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE);
1123#ifdef __REACTOS__
1124 if (!hlib_as_data_file && GetLastError() == ERROR_INVALID_PARAMETER) {
1125 skip("LOAD_LIBRARY_AS_IMAGE_RESOURCE not supported\n");
1126 FreeLibrary(hlib_as_data_file);
1127 } else {
1128#endif
1129 ok(hlib_as_data_file != 0, "LoadLibraryEx error %lu\n", GetLastError());
1130 ok(((ULONG_PTR)hlib_as_data_file & 3) == 2, "hlib_as_data_file got %p\n",
1131 hlib_as_data_file);
1132
1133 hlib = GetModuleHandleA(dll_name);
1134 ok(!hlib, "GetModuleHandle should fail\n");
1135
1136 SetLastError(0xdeadbeef);
1137 ret = FreeLibrary(hlib_as_data_file);
1138 ok(ret, "FreeLibrary error %ld\n", GetLastError());
1139#ifdef __REACTOS__
1140 }
1141#endif
1142
1143 SetLastError(0xdeadbeef);
1144 ret = DeleteFileA(dll_name);
1145 ok(ret, "DeleteFile error %ld\n", GetLastError());
1146
1147 nt_header.OptionalHeader.AddressOfEntryPoint = 0x12345678;
1148 file_size = create_test_dll( &dos_header, td[i].size_of_dos_header, &nt_header, dll_name );
1149 if (!file_size)
1150 {
1151 ok(0, "could not create %s\n", dll_name);
1152 winetest_pop_context();
1153 break;
1154 }
1155
1156 query_image_section( i, dll_name, &nt_header, NULL );
1157 }
1158 else
1159 {
1160 BOOL error_match;
1161 int error_index;
1162
1163 error_match = FALSE;
1164 for (error_index = 0;
1165 ! error_match && error_index < ARRAY_SIZE(td[i].errors);
1166 error_index++)
1167 {
1168 error_match = td[i].errors[error_index] == GetLastError();
1169 }
1170 ok(error_match, "unexpected error %ld\n", GetLastError());
1171 }
1172
1173 SetLastError(0xdeadbeef);
1174 ret = DeleteFileA(dll_name);
1175 ok(ret, "DeleteFile error %ld\n", GetLastError());
1176 winetest_pop_context();
1177 }
1178
1179 nt_header = nt_header_template;
1180 nt_header.FileHeader.NumberOfSections = 1;
1181 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1182
1183 nt_header.OptionalHeader.SectionAlignment = page_size;
1184 nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
1185 nt_header.OptionalHeader.FileAlignment = page_size;
1186 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
1187 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
1188
1189 section.SizeOfRawData = sizeof(section_data);
1190 section.PointerToRawData = page_size;
1191 section.VirtualAddress = page_size;
1192 section.Misc.VirtualSize = page_size;
1193
1194 create_test_dll_sections( &dos_header, &nt_header, §ion, section_data, dll_name );
1195 init_load_path( dll_name );
1196
1197 nt_header.OptionalHeader.AddressOfEntryPoint = 0x1234;
1198 status = map_image_section( &nt_header, §ion, section_data, __LINE__ );
1199 ok( status == (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_SUCCESS),
1200 "NtCreateSection error %08lx\n", status );
1201
1202 nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
1203 status = map_image_section( &nt_header, §ion, section_data, __LINE__ );
1204 ok( status == (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_SUCCESS),
1205 "NtCreateSection error %08lx\n", status );
1206
1207 nt_header.OptionalHeader.SizeOfCode = 0x1000;
1208 status = map_image_section( &nt_header, §ion, section_data, __LINE__ );
1209 ok( status == (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_SUCCESS),
1210 "NtCreateSection error %08lx\n", status );
1211
1212 nt_header.OptionalHeader.SizeOfCode = 0;
1213 nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
1214
1215 dos_header.e_magic = 0;
1216 status = map_image_section( &nt_header, §ion, section_data, __LINE__ );
1217 ok( status == STATUS_INVALID_IMAGE_NOT_MZ, "NtCreateSection error %08lx\n", status );
1218
1219 dos_header.e_magic = IMAGE_DOS_SIGNATURE;
1220 nt_header.Signature = IMAGE_OS2_SIGNATURE;
1221 status = map_image_section( &nt_header, §ion, section_data, __LINE__ );
1222 ok( status == STATUS_INVALID_IMAGE_NE_FORMAT, "NtCreateSection error %08lx\n", status );
1223 for (i = 0; i < 16; i++)
1224 {
1225 ((IMAGE_OS2_HEADER *)&nt_header)->ne_exetyp = i;
1226 status = map_image_section( &nt_header, §ion, section_data, __LINE__ );
1227 switch (i)
1228 {
1229 case 2:
1230 ok( status == STATUS_INVALID_IMAGE_WIN_16, "NtCreateSection %u error %08lx\n", i, status );
1231 break;
1232 case 5:
1233 ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection %u error %08lx\n", i, status );
1234 break;
1235 default:
1236 ok( status == STATUS_INVALID_IMAGE_NE_FORMAT, "NtCreateSection %u error %08lx\n", i, status );
1237 break;
1238 }
1239 }
1240 ((IMAGE_OS2_HEADER *)&nt_header)->ne_exetyp = ((IMAGE_OS2_HEADER *)&nt_header_template)->ne_exetyp;
1241
1242 dos_header.e_lfanew = 0x98760000;
1243 status = map_image_section( &nt_header, §ion, section_data, __LINE__ );
1244 ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection error %08lx\n", status );
1245
1246 dos_header.e_lfanew = sizeof(dos_header);
1247 nt_header.Signature = 0xdeadbeef;
1248 status = map_image_section( &nt_header, §ion, section_data, __LINE__ );
1249 ok( status == STATUS_INVALID_IMAGE_PROTECT, "NtCreateSection error %08lx\n", status );
1250
1251 nt_header.Signature = IMAGE_NT_SIGNATURE;
1252 nt_header.OptionalHeader.Magic = 0xdead;
1253 status = map_image_section( &nt_header, §ion, section_data, __LINE__ );
1254 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08lx\n", status );
1255
1256 nt_header.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC;
1257 nt_header.FileHeader.Machine = 0xdead;
1258 status = map_image_section( &nt_header, §ion, section_data, __LINE__ );
1259 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08lx\n", status );
1260
1261 nt_header.FileHeader.Machine = IMAGE_FILE_MACHINE_UNKNOWN;
1262 status = map_image_section( &nt_header, §ion, section_data, __LINE__ );
1263 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08lx\n", status );
1264
1265 nt_header.FileHeader.Machine = get_alt_bitness_machine( orig_machine );
1266 status = map_image_section( &nt_header, §ion, section_data, __LINE__ );
1267 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08lx\n", status );
1268
1269 nt_header.FileHeader.Machine = orig_machine;
1270 nt_header.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
1271 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = page_size;
1272 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = sizeof(cor_header);
1273 section.SizeOfRawData = sizeof(cor_header);
1274
1275 memset( &cor_header, 0, sizeof(cor_header) );
1276 cor_header.cb = sizeof(cor_header);
1277 cor_header.MajorRuntimeVersion = 2;
1278 cor_header.MinorRuntimeVersion = 4;
1279 cor_header.Flags = COMIMAGE_FLAGS_ILONLY;
1280 cor_header.EntryPointToken = 0xbeef;
1281 status = map_image_section( &nt_header, §ion, &cor_header, __LINE__ );
1282 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1283
1284 cor_header.MinorRuntimeVersion = 5;
1285 status = map_image_section( &nt_header, §ion, &cor_header, __LINE__ );
1286 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1287
1288 cor_header.MajorRuntimeVersion = 3;
1289 cor_header.MinorRuntimeVersion = 0;
1290 status = map_image_section( &nt_header, §ion, &cor_header, __LINE__ );
1291 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1292
1293 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITREQUIRED;
1294 status = map_image_section( &nt_header, §ion, &cor_header, __LINE__ );
1295 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1296
1297 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITPREFERRED;
1298 status = map_image_section( &nt_header, §ion, &cor_header, __LINE__ );
1299 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1300
1301 cor_header.Flags = 0;
1302 status = map_image_section( &nt_header, §ion, &cor_header, __LINE__ );
1303 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1304
1305 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = 1;
1306 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = 1;
1307 status = map_image_section( &nt_header, §ion, &cor_header, __LINE__ );
1308 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1309
1310 if (nt_header.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
1311 {
1312 IMAGE_NT_HEADERS64 nt64;
1313
1314 memset( &nt64, 0, sizeof(nt64) );
1315 nt64.Signature = IMAGE_NT_SIGNATURE;
1316 nt64.FileHeader.Machine = orig_machine;
1317 nt64.FileHeader.NumberOfSections = 1;
1318 nt64.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
1319 nt64.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL;
1320 nt64.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
1321 nt64.OptionalHeader.MajorLinkerVersion = 1;
1322 nt64.OptionalHeader.SizeOfCode = 0x1000;
1323 nt64.OptionalHeader.AddressOfEntryPoint = 0x1000;
1324 nt64.OptionalHeader.ImageBase = 0x10000000;
1325 nt64.OptionalHeader.SectionAlignment = 0x1000;
1326 nt64.OptionalHeader.FileAlignment = 0x1000;
1327 nt64.OptionalHeader.MajorOperatingSystemVersion = 4;
1328 nt64.OptionalHeader.MajorImageVersion = 1;
1329 nt64.OptionalHeader.MajorSubsystemVersion = 4;
1330 nt64.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt64) + sizeof(IMAGE_SECTION_HEADER);
1331 nt64.OptionalHeader.SizeOfImage = nt64.OptionalHeader.SizeOfHeaders + 0x1000;
1332 nt64.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
1333 nt64.OptionalHeader.SizeOfStackReserve = 0x321000;
1334 nt64.OptionalHeader.SizeOfStackCommit = 0x123000;
1335 section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
1336
1337 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, section_data, __LINE__ );
1338 ok( status == (is_wow64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_INVALID_IMAGE_WIN_64),
1339 "NtCreateSection error %08lx\n", status );
1340
1341 switch (orig_machine)
1342 {
1343 case IMAGE_FILE_MACHINE_I386: nt64.FileHeader.Machine = IMAGE_FILE_MACHINE_ARM64; break;
1344 case IMAGE_FILE_MACHINE_ARMNT: nt64.FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64; break;
1345 }
1346 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, section_data, __LINE__ );
1347 ok( status == (is_wow64 ? STATUS_INVALID_IMAGE_FORMAT : STATUS_INVALID_IMAGE_WIN_64),
1348 "NtCreateSection error %08lx\n", status );
1349
1350 nt64.FileHeader.Machine = get_alt_bitness_machine( orig_machine );
1351 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, section_data, __LINE__ );
1352 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1353 "NtCreateSection error %08lx\n", status );
1354
1355 nt64.OptionalHeader.SizeOfCode = 0;
1356 nt64.OptionalHeader.AddressOfEntryPoint = 0x1000;
1357 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1358 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, section_data, __LINE__ );
1359 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1360 "NtCreateSection error %08lx\n", status );
1361
1362 nt64.OptionalHeader.SizeOfCode = 0;
1363 nt64.OptionalHeader.AddressOfEntryPoint = 0;
1364 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE;
1365 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, section_data, __LINE__ );
1366 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1367 "NtCreateSection error %08lx\n", status );
1368
1369 nt64.OptionalHeader.SizeOfCode = 0x1000;
1370 nt64.OptionalHeader.AddressOfEntryPoint = 0;
1371 nt64.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
1372 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1373 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, section_data, __LINE__ );
1374 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1375 "NtCreateSection error %08lx\n", status );
1376
1377 nt64.OptionalHeader.SizeOfCode = 0;
1378 nt64.OptionalHeader.AddressOfEntryPoint = 0;
1379 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1380 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, section_data, __LINE__ );
1381 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1382 "NtCreateSection error %08lx\n", status );
1383
1384 nt64.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
1385 nt64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = page_size;
1386 nt64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = sizeof(cor_header);
1387 cor_header.MajorRuntimeVersion = 2;
1388 cor_header.MinorRuntimeVersion = 4;
1389 cor_header.Flags = COMIMAGE_FLAGS_ILONLY;
1390 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, &cor_header, __LINE__ );
1391 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1392 "NtCreateSection error %08lx\n", status );
1393
1394 nt64.OptionalHeader.SizeOfCode = 0x1000;
1395 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, &cor_header, __LINE__ );
1396 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1397 "NtCreateSection error %08lx\n", status );
1398
1399 cor_header.MinorRuntimeVersion = 5;
1400 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, &cor_header, __LINE__ );
1401 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1402 "NtCreateSection error %08lx\n", status );
1403
1404 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITREQUIRED;
1405 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, &cor_header, __LINE__ );
1406 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1407 "NtCreateSection error %08lx\n", status );
1408
1409 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITPREFERRED;
1410 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, &cor_header, __LINE__ );
1411 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1412 "NtCreateSection error %08lx\n", status );
1413
1414 cor_header.Flags = 0;
1415 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, &cor_header, __LINE__ );
1416 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1417 "NtCreateSection error %08lx\n", status );
1418
1419 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = 1;
1420 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = 1;
1421 status = map_image_section( (IMAGE_NT_HEADERS *)&nt64, §ion, &cor_header, __LINE__ );
1422 ok( status == (is_wow64 ? STATUS_SUCCESS : STATUS_INVALID_IMAGE_WIN_64),
1423 "NtCreateSection error %08lx\n", status );
1424 }
1425#ifdef __REACTOS__
1426 else if (is_reactos() && orig_machine == IMAGE_FILE_MACHINE_AMD64)
1427 {
1428 ok(FALSE, "FIXME: These tests crash on ReactOS x64!\n");
1429 }
1430 else
1431#else
1432 else
1433#endif
1434 {
1435 IMAGE_NT_HEADERS32 nt32;
1436
1437 memset( &nt32, 0, sizeof(nt32) );
1438 nt32.Signature = IMAGE_NT_SIGNATURE;
1439 nt32.FileHeader.Machine = orig_machine;
1440 nt32.FileHeader.NumberOfSections = 1;
1441 nt32.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32);
1442 nt32.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL;
1443 nt32.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
1444 nt32.OptionalHeader.MajorLinkerVersion = 1;
1445 nt32.OptionalHeader.SizeOfCode = 0x1000;
1446 nt32.OptionalHeader.AddressOfEntryPoint = 0x1000;
1447 nt32.OptionalHeader.ImageBase = 0x10000000;
1448 nt32.OptionalHeader.SectionAlignment = 0x1000;
1449 nt32.OptionalHeader.FileAlignment = 0x1000;
1450 nt32.OptionalHeader.MajorOperatingSystemVersion = 4;
1451 nt32.OptionalHeader.MajorImageVersion = 1;
1452 nt32.OptionalHeader.MajorSubsystemVersion = 4;
1453 nt32.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt32) + sizeof(IMAGE_SECTION_HEADER);
1454 nt32.OptionalHeader.SizeOfImage = nt32.OptionalHeader.SizeOfHeaders + 0x1000;
1455 nt32.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
1456 nt32.OptionalHeader.SizeOfStackReserve = 0x321000;
1457 nt32.OptionalHeader.SizeOfStackCommit = 0x123000;
1458 section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
1459
1460 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, section_data, __LINE__ );
1461 ok( status == STATUS_INVALID_IMAGE_FORMAT, "NtCreateSection error %08lx\n", status );
1462
1463 if (orig_machine == IMAGE_FILE_MACHINE_AMD64)
1464 {
1465 nt32.FileHeader.Machine = IMAGE_FILE_MACHINE_ARMNT;
1466 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, section_data, __LINE__ );
1467 ok( status == STATUS_INVALID_IMAGE_FORMAT || broken(!status) /* win8 */,
1468 "NtCreateSection error %08lx\n", status );
1469 }
1470
1471 nt32.FileHeader.Machine = IMAGE_FILE_MACHINE_I386;
1472 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, section_data, __LINE__ );
1473 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1474
1475 nt32.OptionalHeader.SizeOfCode = 0;
1476 nt32.OptionalHeader.AddressOfEntryPoint = 0x1000;
1477 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1478 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, section_data, __LINE__ );
1479 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1480
1481 nt32.OptionalHeader.SizeOfCode = 0;
1482 nt32.OptionalHeader.AddressOfEntryPoint = 0;
1483 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE;
1484 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, section_data, __LINE__ );
1485 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1486
1487 nt32.OptionalHeader.SizeOfCode = 0x1000;
1488 nt32.OptionalHeader.AddressOfEntryPoint = 0;
1489 nt32.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
1490 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1491 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, section_data, __LINE__ );
1492 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1493
1494 nt32.OptionalHeader.SizeOfCode = 0;
1495 nt32.OptionalHeader.AddressOfEntryPoint = 0;
1496 section.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
1497 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, section_data, __LINE__ );
1498 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1499
1500 nt32.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
1501 nt32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = page_size;
1502 nt32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = sizeof(cor_header);
1503 cor_header.MajorRuntimeVersion = 2;
1504 cor_header.MinorRuntimeVersion = 4;
1505 cor_header.Flags = COMIMAGE_FLAGS_ILONLY;
1506 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, &cor_header, __LINE__ );
1507 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1508
1509 nt32.OptionalHeader.SizeOfCode = 0x1000;
1510 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, &cor_header, __LINE__ );
1511 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1512
1513 cor_header.MinorRuntimeVersion = 5;
1514 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, &cor_header, __LINE__ );
1515 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1516
1517 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITREQUIRED;
1518 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, &cor_header, __LINE__ );
1519 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1520
1521 cor_header.Flags = COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_32BITPREFERRED;
1522 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, &cor_header, __LINE__ );
1523 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1524
1525 cor_header.Flags = 0;
1526 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, &cor_header, __LINE__ );
1527 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1528
1529 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = 1;
1530 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = 1;
1531 status = map_image_section( (IMAGE_NT_HEADERS *)&nt32, §ion, &cor_header, __LINE__ );
1532 ok( status == STATUS_SUCCESS, "NtCreateSection error %08lx\n", status );
1533 }
1534
1535 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
1536 delete_load_path();
1537}
1538
1539static void test_filenames(void)
1540{
1541 IMAGE_NT_HEADERS nt_header = nt_header_template;
1542 char dll_name[MAX_PATH], long_path[MAX_PATH], short_path[MAX_PATH], buffer[MAX_PATH];
1543 HMODULE mod, mod2;
1544 BOOL ret;
1545
1546 nt_header.FileHeader.NumberOfSections = 1;
1547 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
1548
1549 nt_header.OptionalHeader.SectionAlignment = page_size;
1550 nt_header.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
1551 nt_header.OptionalHeader.FileAlignment = page_size;
1552 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
1553 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
1554
1555 create_test_dll( &dos_header, sizeof(dos_header), &nt_header, dll_name );
1556 strcpy( long_path, dll_name );
1557 strcpy( strrchr( long_path, '\\' ), "\\this-is-a-long-name.dll" );
1558 ret = MoveFileA( dll_name, long_path );
1559 ok( ret, "MoveFileA failed err %lu\n", GetLastError() );
1560 GetShortPathNameA( long_path, short_path, MAX_PATH );
1561
1562 mod = LoadLibraryA( short_path );
1563 ok( mod != NULL, "loading failed err %lu\n", GetLastError() );
1564 GetModuleFileNameA( mod, buffer, MAX_PATH );
1565 ok( !lstrcmpiA( buffer, short_path ), "got wrong path %s / %s\n", buffer, short_path );
1566 mod2 = GetModuleHandleA( short_path );
1567 ok( mod == mod2, "wrong module %p for %s\n", mod2, short_path );
1568 mod2 = GetModuleHandleA( long_path );
1569 ok( mod == mod2, "wrong module %p for %s\n", mod2, long_path );
1570 mod2 = LoadLibraryA( long_path );
1571 ok( mod2 != NULL, "loading failed err %lu\n", GetLastError() );
1572 ok( mod == mod2, "library loaded twice\n" );
1573 GetModuleFileNameA( mod2, buffer, MAX_PATH );
1574 ok( !lstrcmpiA( buffer, short_path ), "got wrong path %s / %s\n", buffer, short_path );
1575 FreeLibrary( mod2 );
1576 FreeLibrary( mod );
1577
1578 mod = LoadLibraryA( long_path );
1579 ok( mod != NULL, "loading failed err %lu\n", GetLastError() );
1580 GetModuleFileNameA( mod, buffer, MAX_PATH );
1581 ok( !lstrcmpiA( buffer, long_path ), "got wrong path %s / %s\n", buffer, long_path );
1582 mod2 = GetModuleHandleA( short_path );
1583 ok( mod == mod2, "wrong module %p for %s\n", mod2, short_path );
1584 mod2 = GetModuleHandleA( long_path );
1585 ok( mod == mod2, "wrong module %p for %s\n", mod2, long_path );
1586 mod2 = LoadLibraryA( short_path );
1587 ok( mod2 != NULL, "loading failed err %lu\n", GetLastError() );
1588 ok( mod == mod2, "library loaded twice\n" );
1589 GetModuleFileNameA( mod2, buffer, MAX_PATH );
1590 ok( !lstrcmpiA( buffer, long_path ), "got wrong path %s / %s\n", buffer, long_path );
1591 FreeLibrary( mod2 );
1592 FreeLibrary( mod );
1593
1594 strcpy( dll_name, long_path );
1595 strcpy( strrchr( dll_name, '\\' ), "\\this-is-another-name.dll" );
1596 ret = CreateHardLinkA( dll_name, long_path, NULL );
1597 ok( ret, "CreateHardLinkA failed err %lu\n", GetLastError() );
1598 if (ret)
1599 {
1600 mod = LoadLibraryA( dll_name );
1601 ok( mod != NULL, "loading failed err %lu\n", GetLastError() );
1602 GetModuleFileNameA( mod, buffer, MAX_PATH );
1603 ok( !lstrcmpiA( buffer, dll_name ), "got wrong path %s / %s\n", buffer, dll_name );
1604 mod2 = GetModuleHandleA( long_path );
1605 ok( mod == mod2, "wrong module %p for %s\n", mod2, long_path );
1606 mod2 = LoadLibraryA( long_path );
1607 ok( mod2 != NULL, "loading failed err %lu\n", GetLastError() );
1608 ok( mod == mod2, "library loaded twice\n" );
1609 GetModuleFileNameA( mod2, buffer, MAX_PATH );
1610 ok( !lstrcmpiA( buffer, dll_name ), "got wrong path %s / %s\n", buffer, short_path );
1611 FreeLibrary( mod2 );
1612 FreeLibrary( mod );
1613 DeleteFileA( dll_name );
1614 }
1615 DeleteFileA( long_path );
1616}
1617
1618/* Verify linking style of import descriptors */
1619static void test_ImportDescriptors(void)
1620{
1621 HMODULE kernel32_module = NULL;
1622 PIMAGE_DOS_HEADER d_header;
1623 PIMAGE_NT_HEADERS nt_headers;
1624 DWORD import_dir_size;
1625 DWORD_PTR dir_offset;
1626 PIMAGE_IMPORT_DESCRIPTOR import_chunk;
1627
1628 /* Load kernel32 module */
1629 kernel32_module = GetModuleHandleA("kernel32.dll");
1630 assert( kernel32_module != NULL );
1631
1632 /* Get PE header info from module image */
1633 d_header = (PIMAGE_DOS_HEADER) kernel32_module;
1634 nt_headers = (PIMAGE_NT_HEADERS) (((char*) d_header) +
1635 d_header->e_lfanew);
1636
1637 /* Get size of import entry directory */
1638 import_dir_size = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
1639 if (!import_dir_size)
1640 {
1641 skip("Unable to continue testing due to missing import directory.\n");
1642 return;
1643 }
1644
1645 /* Get address of first import chunk */
1646 dir_offset = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
1647 import_chunk = RVAToAddr(dir_offset, kernel32_module);
1648 ok(import_chunk != 0, "Invalid import_chunk: %p\n", import_chunk);
1649 if (!import_chunk) return;
1650
1651 /* Iterate through import descriptors and verify set name,
1652 * OriginalFirstThunk, and FirstThunk. Core Windows DLLs, such as
1653 * kernel32.dll, don't use Borland-style linking, where the table of
1654 * imported names is stored directly in FirstThunk and overwritten
1655 * by the relocation, instead of being stored in OriginalFirstThunk.
1656 * */
1657 for (; import_chunk->FirstThunk; import_chunk++)
1658 {
1659 LPCSTR module_name = RVAToAddr(import_chunk->Name, kernel32_module);
1660 PIMAGE_THUNK_DATA name_table = RVAToAddr(
1661 import_chunk->OriginalFirstThunk, kernel32_module);
1662 PIMAGE_THUNK_DATA iat = RVAToAddr(
1663 import_chunk->FirstThunk, kernel32_module);
1664 ok(module_name != NULL, "Imported module name should not be NULL\n");
1665 ok(name_table != NULL,
1666 "Name table for imported module %s should not be NULL\n",
1667 module_name);
1668 ok(iat != NULL, "IAT for imported module %s should not be NULL\n",
1669 module_name);
1670 }
1671}
1672
1673static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL is_dll)
1674{
1675 HANDLE hfile, hmap;
1676 NTSTATUS status;
1677 LARGE_INTEGER offset;
1678 SIZE_T size;
1679 void *addr1, *addr2;
1680 MEMORY_BASIC_INFORMATION info;
1681
1682 if (!pNtMapViewOfSection) return;
1683
1684 SetLastError(0xdeadbeef);
1685 hfile = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
1686 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile error %ld\n", GetLastError());
1687
1688 SetLastError(0xdeadbeef);
1689 hmap = CreateFileMappingW(hfile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, 0);
1690 ok(hmap != 0, "CreateFileMapping error %ld\n", GetLastError());
1691
1692 offset.u.LowPart = 0;
1693 offset.u.HighPart = 0;
1694
1695 addr1 = NULL;
1696 size = 0;
1697 status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr1, 0, 0, &offset,
1698 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1699 ok(NT_SUCCESS(status), "NtMapViewOfSection error %lx\n", status);
1700 ok(addr1 != 0, "mapped address should be valid\n");
1701
1702 SetLastError(0xdeadbeef);
1703 size = VirtualQuery((char *)addr1 + section.VirtualAddress, &info, sizeof(info));
1704 ok(size == sizeof(info), "VirtualQuery error %ld\n", GetLastError());
1705 ok(info.BaseAddress == (char *)addr1 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr1 + section.VirtualAddress);
1706 ok(info.RegionSize == page_size, "got %#Ix != expected %#lx\n", info.RegionSize, page_size);
1707 ok(info.Protect == scn_page_access, "got %#lx != expected %#lx\n", info.Protect, scn_page_access);
1708 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1709 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1710 ok(info.State == MEM_COMMIT, "%#lx != MEM_COMMIT\n", info.State);
1711 ok(info.Type == SEC_IMAGE, "%#lx != SEC_IMAGE\n", info.Type);
1712
1713 addr2 = NULL;
1714 size = 0;
1715 status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr2, 0, 0, &offset,
1716 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
1717 ok(status == STATUS_IMAGE_NOT_AT_BASE, "expected STATUS_IMAGE_NOT_AT_BASE, got %lx\n", status);
1718 ok(addr2 != 0, "mapped address should be valid\n");
1719 ok(addr2 != addr1, "mapped addresses should be different\n");
1720
1721 SetLastError(0xdeadbeef);
1722 size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info));
1723 ok(size == sizeof(info), "VirtualQuery error %ld\n", GetLastError());
1724 ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress);
1725 ok(info.RegionSize == page_size, "got %#Ix != expected %#lx\n", info.RegionSize, page_size);
1726 ok(info.Protect == scn_page_access, "got %#lx != expected %#lx\n", info.Protect, scn_page_access);
1727 ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2);
1728 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1729 ok(info.State == MEM_COMMIT, "%#lx != MEM_COMMIT\n", info.State);
1730 ok(info.Type == SEC_IMAGE, "%#lx != SEC_IMAGE\n", info.Type);
1731
1732 status = pNtUnmapViewOfSection(GetCurrentProcess(), addr2);
1733 ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %lx\n", status);
1734
1735 addr2 = MapViewOfFile(hmap, 0, 0, 0, 0);
1736 ok(addr2 != 0, "mapped address should be valid\n");
1737 ok(addr2 != addr1, "mapped addresses should be different\n");
1738
1739 SetLastError(0xdeadbeef);
1740 size = VirtualQuery((char *)addr2 + section.VirtualAddress, &info, sizeof(info));
1741 ok(size == sizeof(info), "VirtualQuery error %ld\n", GetLastError());
1742 ok(info.BaseAddress == (char *)addr2 + section.VirtualAddress, "got %p != expected %p\n", info.BaseAddress, (char *)addr2 + section.VirtualAddress);
1743 ok(info.RegionSize == page_size, "got %#Ix != expected %#lx\n", info.RegionSize, page_size);
1744 ok(info.Protect == scn_page_access, "got %#lx != expected %#lx\n", info.Protect, scn_page_access);
1745 ok(info.AllocationBase == addr2, "%p != %p\n", info.AllocationBase, addr2);
1746 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%#lx != PAGE_EXECUTE_WRITECOPY\n", info.AllocationProtect);
1747 ok(info.State == MEM_COMMIT, "%#lx != MEM_COMMIT\n", info.State);
1748 ok(info.Type == SEC_IMAGE, "%#lx != SEC_IMAGE\n", info.Type);
1749
1750 UnmapViewOfFile(addr2);
1751
1752 SetLastError(0xdeadbeef);
1753 addr2 = LoadLibraryA(dll_name);
1754 if (!addr2)
1755 {
1756 ok(is_dll, "LoadLibrary should fail, is_dll %d\n", is_dll);
1757 ok(GetLastError() == ERROR_INVALID_ADDRESS, "expected ERROR_INVALID_ADDRESS, got %ld\n", GetLastError());
1758 }
1759 else
1760 {
1761 BOOL ret;
1762 ok(addr2 != 0, "LoadLibrary error %ld, is_dll %d\n", GetLastError(), is_dll);
1763 ok(addr2 != addr1, "mapped addresses should be different\n");
1764
1765 SetLastError(0xdeadbeef);
1766 ret = FreeLibrary(addr2);
1767 ok(ret, "FreeLibrary error %ld\n", GetLastError());
1768 }
1769
1770 status = pNtUnmapViewOfSection(GetCurrentProcess(), addr1);
1771 ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %lx\n", status);
1772
1773 CloseHandle(hmap);
1774 CloseHandle(hfile);
1775}
1776
1777static BOOL is_mem_writable(DWORD prot)
1778{
1779 switch (prot & 0xff)
1780 {
1781 case PAGE_READWRITE:
1782 case PAGE_WRITECOPY:
1783 case PAGE_EXECUTE_READWRITE:
1784 case PAGE_EXECUTE_WRITECOPY:
1785 return TRUE;
1786
1787 default:
1788 return FALSE;
1789 }
1790}
1791
1792static void test_VirtualProtect(void *base, void *section)
1793{
1794 static const struct test_data
1795 {
1796 DWORD prot_set, prot_get;
1797 } td[] =
1798 {
1799 { 0, 0 }, /* 0x00 */
1800 { PAGE_NOACCESS, PAGE_NOACCESS }, /* 0x01 */
1801 { PAGE_READONLY, PAGE_READONLY }, /* 0x02 */
1802 { PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x03 */
1803 { PAGE_READWRITE, PAGE_WRITECOPY }, /* 0x04 */
1804 { PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x05 */
1805 { PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x06 */
1806 { PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x07 */
1807 { PAGE_WRITECOPY, PAGE_WRITECOPY }, /* 0x08 */
1808 { PAGE_WRITECOPY | PAGE_NOACCESS, 0 }, /* 0x09 */
1809 { PAGE_WRITECOPY | PAGE_READONLY, 0 }, /* 0x0a */
1810 { PAGE_WRITECOPY | PAGE_NOACCESS | PAGE_READONLY, 0 }, /* 0x0b */
1811 { PAGE_WRITECOPY | PAGE_READWRITE, 0 }, /* 0x0c */
1812 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x0d */
1813 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x0e */
1814 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x0f */
1815
1816 { PAGE_EXECUTE, PAGE_EXECUTE }, /* 0x10 */
1817 { PAGE_EXECUTE_READ, PAGE_EXECUTE_READ }, /* 0x20 */
1818 { PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x30 */
1819 { PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY }, /* 0x40 */
1820 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0x50 */
1821 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0x60 */
1822 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x70 */
1823 { PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_WRITECOPY }, /* 0x80 */
1824 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE, 0 }, /* 0x90 */
1825 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ, 0 }, /* 0xa0 */
1826 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0xb0 */
1827 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE, 0 }, /* 0xc0 */
1828 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0xd0 */
1829 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0xe0 */
1830 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 } /* 0xf0 */
1831 };
1832 DWORD ret, orig_prot, old_prot, rw_prot, exec_prot, i, j;
1833 MEMORY_BASIC_INFORMATION info;
1834
1835 SetLastError(0xdeadbeef);
1836 ret = VirtualProtect(section, page_size, PAGE_NOACCESS, &old_prot);
1837 ok(ret, "VirtualProtect error %ld\n", GetLastError());
1838
1839 orig_prot = old_prot;
1840
1841 for (i = 0; i < ARRAY_SIZE(td); i++)
1842 {
1843 SetLastError(0xdeadbeef);
1844 ret = VirtualQuery(section, &info, sizeof(info));
1845 ok(ret, "VirtualQuery failed %ld\n", GetLastError());
1846 ok(info.BaseAddress == section, "%ld: got %p != expected %p\n", i, info.BaseAddress, section);
1847 ok(info.RegionSize == page_size, "%ld: got %#Ix != expected %#lx\n", i, info.RegionSize, page_size);
1848 ok(info.Protect == PAGE_NOACCESS, "%ld: got %#lx != expected PAGE_NOACCESS\n", i, info.Protect);
1849 ok(info.AllocationBase == base, "%ld: %p != %p\n", i, info.AllocationBase, base);
1850 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%ld: %#lx != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1851 ok(info.State == MEM_COMMIT, "%ld: %#lx != MEM_COMMIT\n", i, info.State);
1852 ok(info.Type == SEC_IMAGE, "%ld: %#lx != SEC_IMAGE\n", i, info.Type);
1853
1854 old_prot = 0xdeadbeef;
1855 SetLastError(0xdeadbeef);
1856 ret = VirtualProtect(section, page_size, td[i].prot_set, &old_prot);
1857 if (td[i].prot_get)
1858 {
1859 ok(ret, "%ld: VirtualProtect error %ld, requested prot %#lx\n", i, GetLastError(), td[i].prot_set);
1860 ok(old_prot == PAGE_NOACCESS, "%ld: got %#lx != expected PAGE_NOACCESS\n", i, old_prot);
1861
1862 SetLastError(0xdeadbeef);
1863 ret = VirtualQuery(section, &info, sizeof(info));
1864 ok(ret, "VirtualQuery failed %ld\n", GetLastError());
1865 ok(info.BaseAddress == section, "%ld: got %p != expected %p\n", i, info.BaseAddress, section);
1866 ok(info.RegionSize == page_size, "%ld: got %#Ix != expected %#lx\n", i, info.RegionSize, page_size);
1867 ok(info.Protect == td[i].prot_get, "%ld: got %#lx != expected %#lx\n", i, info.Protect, td[i].prot_get);
1868 ok(info.AllocationBase == base, "%ld: %p != %p\n", i, info.AllocationBase, base);
1869 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%ld: %#lx != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
1870 ok(info.State == MEM_COMMIT, "%ld: %#lx != MEM_COMMIT\n", i, info.State);
1871 ok(info.Type == SEC_IMAGE, "%ld: %#lx != SEC_IMAGE\n", i, info.Type);
1872 }
1873 else
1874 {
1875 ok(!ret, "%ld: VirtualProtect should fail\n", i);
1876 ok(GetLastError() == ERROR_INVALID_PARAMETER, "%ld: expected ERROR_INVALID_PARAMETER, got %ld\n", i, GetLastError());
1877 }
1878
1879 old_prot = 0xdeadbeef;
1880 SetLastError(0xdeadbeef);
1881 ret = VirtualProtect(section, page_size, PAGE_NOACCESS, &old_prot);
1882 ok(ret, "%ld: VirtualProtect error %ld\n", i, GetLastError());
1883 if (td[i].prot_get)
1884 ok(old_prot == td[i].prot_get, "%ld: got %#lx != expected %#lx\n", i, old_prot, td[i].prot_get);
1885 else
1886 ok(old_prot == PAGE_NOACCESS, "%ld: got %#lx != expected PAGE_NOACCESS\n", i, old_prot);
1887 }
1888
1889 exec_prot = 0;
1890
1891 for (i = 0; i <= 4; i++)
1892 {
1893 rw_prot = 0;
1894
1895 for (j = 0; j <= 4; j++)
1896 {
1897 DWORD prot = exec_prot | rw_prot;
1898
1899 SetLastError(0xdeadbeef);
1900 ret = VirtualProtect(section, page_size, prot, &old_prot);
1901 if ((rw_prot && exec_prot) || (!rw_prot && !exec_prot))
1902 {
1903 ok(!ret, "VirtualProtect(%02lx) should fail\n", prot);
1904 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
1905 }
1906 else
1907 ok(ret, "VirtualProtect(%02lx) error %ld\n", prot, GetLastError());
1908
1909 rw_prot = 1 << j;
1910 }
1911
1912 exec_prot = 1 << (i + 4);
1913 }
1914
1915 SetLastError(0xdeadbeef);
1916 ret = VirtualProtect(section, page_size, orig_prot, &old_prot);
1917 ok(ret, "VirtualProtect error %ld\n", GetLastError());
1918}
1919
1920static void test_section_access(void)
1921{
1922 static const struct test_data
1923 {
1924 DWORD scn_file_access, scn_page_access, scn_page_access_after_write;
1925 } td[] =
1926 {
1927 { 0, PAGE_NOACCESS, 0 },
1928 { IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1929 { IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1930 { IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1931 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1932 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ },
1933 { IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1934 { IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1935
1936 { IMAGE_SCN_CNT_INITIALIZED_DATA, PAGE_NOACCESS, 0 },
1937 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1938 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1939 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1940 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1941 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
1942 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1943 { IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1944
1945 { IMAGE_SCN_CNT_UNINITIALIZED_DATA, PAGE_NOACCESS, 0 },
1946 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ, PAGE_READONLY, 0 },
1947 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1948 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE, 0 },
1949 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, PAGE_WRITECOPY, PAGE_READWRITE },
1950 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_READ, 0 },
1951 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE },
1952 { IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READWRITE }
1953 };
1954 char buf[256];
1955 int i;
1956 DWORD dummy;
1957 HANDLE hfile;
1958 HMODULE hlib;
1959 char temp_path[MAX_PATH];
1960 char dll_name[MAX_PATH];
1961 SIZE_T size;
1962 PEB child_peb;
1963 PROCESS_BASIC_INFORMATION pbi;
1964 SECTION_IMAGE_INFORMATION image_info;
1965 MEMORY_BASIC_INFORMATION info;
1966 STARTUPINFOA sti;
1967 PROCESS_INFORMATION pi;
1968 NTSTATUS status;
1969 DWORD ret;
1970
1971 /* prevent displaying of the "Unable to load this DLL" message box */
1972 SetErrorMode(SEM_FAILCRITICALERRORS);
1973
1974 GetTempPathA(MAX_PATH, temp_path);
1975
1976 for (i = 0; i < ARRAY_SIZE(td); i++)
1977 {
1978 IMAGE_NT_HEADERS nt_header;
1979
1980 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
1981
1982 /*trace("creating %s\n", dll_name);*/
1983 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
1984 if (hfile == INVALID_HANDLE_VALUE)
1985 {
1986 ok(0, "could not create %s\n", dll_name);
1987 return;
1988 }
1989
1990 SetLastError(0xdeadbeef);
1991 ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
1992 ok(ret, "WriteFile error %ld\n", GetLastError());
1993
1994 nt_header = nt_header_template;
1995 nt_header.OptionalHeader.SectionAlignment = page_size;
1996 nt_header.OptionalHeader.FileAlignment = 0x200;
1997 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + page_size;
1998 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
1999
2000 section.SizeOfRawData = sizeof(section_data);
2001 section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
2002 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
2003 section.Misc.VirtualSize = section.SizeOfRawData;
2004 section.Characteristics = td[i].scn_file_access;
2005 SetLastError(0xdeadbeef);
2006
2007 SetLastError(0xdeadbeef);
2008 ret = WriteFile(hfile, &nt_header, sizeof(nt_header), &dummy, NULL);
2009 ok(ret, "WriteFile error %ld\n", GetLastError());
2010
2011 ret = WriteFile(hfile, §ion, sizeof(section), &dummy, NULL);
2012 ok(ret, "WriteFile error %ld\n", GetLastError());
2013
2014 /* section data */
2015 SetFilePointer( hfile, nt_header.OptionalHeader.FileAlignment, NULL, FILE_BEGIN );
2016 SetLastError(0xdeadbeef);
2017 ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
2018 ok(ret, "WriteFile error %ld\n", GetLastError());
2019
2020 CloseHandle(hfile);
2021 SetLastError(0xdeadbeef);
2022 hlib = LoadLibraryExA(dll_name, NULL, DONT_RESOLVE_DLL_REFERENCES);
2023 ok(hlib != 0, "LoadLibrary error %ld\n", GetLastError());
2024
2025 SetLastError(0xdeadbeef);
2026 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
2027 ok(size == sizeof(info),
2028 "%d: VirtualQuery error %ld\n", i, GetLastError());
2029 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
2030 ok(info.RegionSize == page_size, "%d: got %#Ix != expected %#lx\n", i, info.RegionSize, page_size);
2031 ok(info.Protect == td[i].scn_page_access, "%d: got %#lx != expected %#lx\n", i, info.Protect, td[i].scn_page_access);
2032 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
2033 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#lx != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
2034 ok(info.State == MEM_COMMIT, "%d: %#lx != MEM_COMMIT\n", i, info.State);
2035 ok(info.Type == SEC_IMAGE, "%d: %#lx != SEC_IMAGE\n", i, info.Type);
2036 if (info.Protect != PAGE_NOACCESS)
2037 ok(!memcmp((const char *)info.BaseAddress, section_data, section.SizeOfRawData), "wrong section data\n");
2038
2039 test_VirtualProtect(hlib, (char *)hlib + section.VirtualAddress);
2040
2041 /* Windows changes the WRITECOPY to WRITE protection on an image section write (for a changed page only) */
2042 if (is_mem_writable(info.Protect))
2043 {
2044 char *p = info.BaseAddress;
2045 *p = 0xfe;
2046 SetLastError(0xdeadbeef);
2047 size = VirtualQuery((char *)hlib + section.VirtualAddress, &info, sizeof(info));
2048 ok(size == sizeof(info), "%d: VirtualQuery error %ld\n", i, GetLastError());
2049 /* FIXME: remove the condition below once Wine is fixed */
2050 todo_wine_if (info.Protect == PAGE_WRITECOPY || info.Protect == PAGE_EXECUTE_WRITECOPY)
2051 ok(info.Protect == td[i].scn_page_access_after_write, "%d: got %#lx != expected %#lx\n", i, info.Protect, td[i].scn_page_access_after_write);
2052 }
2053
2054 SetLastError(0xdeadbeef);
2055 ret = FreeLibrary(hlib);
2056 ok(ret, "FreeLibrary error %ld\n", GetLastError());
2057
2058 test_image_mapping(dll_name, td[i].scn_page_access, TRUE);
2059
2060 /* reset IMAGE_FILE_DLL otherwise CreateProcess fails */
2061 nt_header.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
2062 SetLastError(0xdeadbeef);
2063 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2064 /* LoadLibrary called on an already memory-mapped file in
2065 * test_image_mapping() above leads to a file handle leak
2066 * under nt4, and inability to overwrite and delete the file
2067 * due to sharing violation error. Ignore it and skip the test,
2068 * but leave a not deletable temporary file.
2069 */
2070 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile error %ld\n", GetLastError());
2071 SetFilePointer(hfile, sizeof(dos_header), NULL, FILE_BEGIN);
2072 SetLastError(0xdeadbeef);
2073 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
2074 ok(ret, "WriteFile error %ld\n", GetLastError());
2075 CloseHandle(hfile);
2076
2077 memset(&sti, 0, sizeof(sti));
2078 sti.cb = sizeof(sti);
2079 SetLastError(0xdeadbeef);
2080 ret = CreateProcessA(dll_name, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &sti, &pi);
2081 ok(ret, "CreateProcess() error %ld\n", GetLastError());
2082
2083 status = pNtQueryInformationProcess( pi.hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL );
2084 ok( !status, "ProcessBasicInformation got %lx\n", status );
2085 ret = ReadProcessMemory( pi.hProcess, pbi.PebBaseAddress, &child_peb, sizeof(child_peb), NULL );
2086 ok( ret, "ReadProcessMemory failed err %lu\n", GetLastError() );
2087 hlib = child_peb.ImageBaseAddress;
2088
2089 SetLastError(0xdeadbeef);
2090 size = VirtualQueryEx(pi.hProcess, (char *)hlib + section.VirtualAddress, &info, sizeof(info));
2091 ok(size == sizeof(info),
2092 "%d: VirtualQuery error %ld\n", i, GetLastError());
2093 ok(info.BaseAddress == (char *)hlib + section.VirtualAddress, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib + section.VirtualAddress);
2094 ok(info.RegionSize == page_size, "%d: got %#Ix != expected %#lx\n", i, info.RegionSize, page_size);
2095 ok(info.Protect == td[i].scn_page_access, "%d: got %#lx != expected %#lx\n", i, info.Protect, td[i].scn_page_access);
2096 ok(info.AllocationBase == hlib, "%d: %p != %p\n", i, info.AllocationBase, hlib);
2097 ok(info.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "%d: %#lx != PAGE_EXECUTE_WRITECOPY\n", i, info.AllocationProtect);
2098 ok(info.State == MEM_COMMIT, "%d: %#lx != MEM_COMMIT\n", i, info.State);
2099 ok(info.Type == SEC_IMAGE, "%d: %#lx != SEC_IMAGE\n", i, info.Type);
2100 if (info.Protect != PAGE_NOACCESS)
2101 {
2102 SetLastError(0xdeadbeef);
2103 ret = ReadProcessMemory(pi.hProcess, info.BaseAddress, buf, section.SizeOfRawData, NULL);
2104 ok(ret, "ReadProcessMemory() error %ld\n", GetLastError());
2105 ok(!memcmp(buf, section_data, section.SizeOfRawData), "wrong section data\n");
2106 }
2107
2108#ifdef __REACTOS__
2109 if (GetNTVersion() >= _WIN32_WINNT_VISTA) { // Crashes on WS03
2110#endif
2111 status = NtQueryInformationProcess(pi.hProcess, ProcessImageInformation,
2112 &image_info, sizeof(image_info), NULL );
2113 ok(!status, "Got unexpected status %#lx.\n", status);
2114 ok(!(image_info.ImageCharacteristics & IMAGE_FILE_DLL),
2115 "Got unexpected characteristics %#x.\n", nt_header.FileHeader.Characteristics);
2116 status = NtUnmapViewOfSection(pi.hProcess, info.BaseAddress);
2117 ok(!status, "Got unexpected status %#lx.\n", status);
2118 status = NtQueryInformationProcess(pi.hProcess, ProcessImageInformation,
2119 &image_info, sizeof(image_info), NULL );
2120 ok(!status, "Got unexpected status %#lx.\n", status);
2121 ok(!(image_info.ImageCharacteristics & IMAGE_FILE_DLL),
2122 "Got unexpected characteristics %#x.\n", nt_header.FileHeader.Characteristics);
2123#ifdef __REACTOS__
2124 }
2125#endif
2126
2127 SetLastError(0xdeadbeef);
2128 ret = TerminateProcess(pi.hProcess, 0);
2129 ok(ret, "TerminateProcess() error %ld\n", GetLastError());
2130 ret = WaitForSingleObject(pi.hProcess, 3000);
2131 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %lx\n", ret);
2132
2133 CloseHandle(pi.hThread);
2134 CloseHandle(pi.hProcess);
2135
2136 test_image_mapping(dll_name, td[i].scn_page_access, FALSE);
2137
2138 DeleteFileA(dll_name);
2139 }
2140}
2141
2142static void check_tls_index(HANDLE dll, BOOL tls_initialized)
2143{
2144 BOOL found_dll = FALSE;
2145 LIST_ENTRY *root = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
2146 for (LIST_ENTRY *entry = root->Flink; entry != root; entry = entry->Flink)
2147 {
2148 LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2149 if (wcsicmp(L"ntdll.dll", mod->BaseDllName.Buffer) == 0)
2150 {
2151 /* Pick ntdll as a dll that definitely won't have TLS */
2152 ok(mod->TlsIndex == 0, "ntdll.dll TlsIndex: %d instead of 0\n", mod->TlsIndex);
2153 }
2154 else if (mod->DllBase == dll)
2155 {
2156 SHORT expected = tls_initialized ? -1 : 0;
2157 ok(mod->TlsIndex == expected, "Test exe TlsIndex: %d instead of %d\n", mod->TlsIndex, expected);
2158 found_dll = TRUE;
2159 }
2160 else
2161 {
2162 ok(mod->TlsIndex == 0 || mod->TlsIndex == -1, "%s TlsIndex: %d\n",
2163 debugstr_w(mod->BaseDllName.Buffer), mod->TlsIndex);
2164 }
2165 }
2166 ok(found_dll, "Couldn't find dll %p in module list\n", dll);
2167}
2168
2169static int tls_init_fn_output;
2170
2171static DWORD WINAPI tls_thread_fn(void* tlsidx_v)
2172{
2173 int tls_index = (int)(DWORD_PTR)(tlsidx_v);
2174 const char* str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[tls_index];
2175 ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str );
2176 ok( tls_init_fn_output == DLL_THREAD_ATTACH,
2177 "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_THREAD_ATTACH );
2178 tls_init_fn_output = 9999;
2179 return 0;
2180}
2181
2182static void test_import_resolution(void)
2183{
2184 char temp_path[MAX_PATH];
2185 char dll_name[MAX_PATH];
2186 DWORD dummy;
2187 void *expect, *tmp;
2188 char *str;
2189 SIZE_T size;
2190 HANDLE hfile, mapping;
2191 HMODULE mod, mod2;
2192 NTSTATUS status;
2193 LARGE_INTEGER offset;
2194 struct imports
2195 {
2196 IMAGE_IMPORT_DESCRIPTOR descr[2];
2197 IMAGE_THUNK_DATA original_thunks[2];
2198 IMAGE_THUNK_DATA thunks[2];
2199 char module[16];
2200 struct { WORD hint; char name[32]; } function;
2201 IMAGE_TLS_DIRECTORY tls;
2202 UINT_PTR tls_init_fn_list[2];
2203 char tls_data[16];
2204 SHORT tls_index;
2205 SHORT tls_index_hi;
2206 int* tls_init_fn_output;
2207 UCHAR tls_init_fn[64]; /* Note: Uses rip-relative address of tls_init_fn_output, don't separate */
2208 UCHAR entry_point_fn[16];
2209 struct
2210 {
2211 IMAGE_BASE_RELOCATION reloc;
2212 USHORT type_off[32];
2213 } rel;
2214 } data, *ptr;
2215 IMAGE_NT_HEADERS nt, *pnt;
2216 IMAGE_SECTION_HEADER section;
2217 SECTION_IMAGE_INFORMATION image;
2218 int test, tls_index_save, nb_rel;
2219#if defined(__i386__)
2220 static const UCHAR tls_init_code[] = {
2221 0xE8, 0x00, 0x00, 0x00, 0x00, /* call 1f */
2222 0x59, /* 1: pop ecx */
2223 0x8B, 0x49, 0xF7, /* mov ecx, [ecx - 9] ; mov ecx, [tls_init_fn_output] */
2224 0x8B, 0x54, 0x24, 0x08, /* mov edx, [esp + 8] */
2225 0x89, 0x11, /* mov [ecx], edx */
2226 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */
2227 0xC2, 0x0C, 0x00, /* ret 12 */
2228 };
2229 static const UCHAR entry_point_code[] = {
2230 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */
2231 0xC2, 0x0C, 0x00, /* ret 12 */
2232 };
2233#elif defined(__x86_64__)
2234 static const UCHAR tls_init_code[] = {
2235 0x48, 0x8B, 0x0D, 0xF1, 0xFF, 0xFF, 0xFF, /* mov rcx, [rip + tls_init_fn_output] */
2236 0x89, 0x11, /* mov [rcx], edx */
2237 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */
2238 0xC3, /* ret */
2239 };
2240 static const UCHAR entry_point_code[] = {
2241 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */
2242 0xC3, /* ret */
2243 };
2244#else
2245 static const UCHAR tls_init_code[] = { 0x00 };
2246 static const UCHAR entry_point_code[] = { 0x00 };
2247#endif
2248
2249 for (test = 0; test < 7; test++)
2250 {
2251#define DATA_RVA(ptr) (page_size + ((char *)(ptr) - (char *)&data))
2252#ifdef _WIN64
2253#define ADD_RELOC(field) data.rel.type_off[nb_rel++] = (IMAGE_REL_BASED_DIR64 << 12) + offsetof( struct imports, field )
2254#else
2255#define ADD_RELOC(field) data.rel.type_off[nb_rel++] = (IMAGE_REL_BASED_HIGHLOW << 12) + offsetof( struct imports, field )
2256#endif
2257 winetest_push_context( "%u", test );
2258 nt = nt_header_template;
2259 nt.FileHeader.NumberOfSections = 1;
2260 nt.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
2261 nt.FileHeader.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
2262 if (test != 2 && test != 5) nt.FileHeader.Characteristics |= IMAGE_FILE_DLL;
2263 nt.OptionalHeader.SectionAlignment = page_size;
2264 nt.OptionalHeader.FileAlignment = 0x200;
2265 nt.OptionalHeader.SizeOfImage = 2 * page_size;
2266 nt.OptionalHeader.SizeOfHeaders = nt.OptionalHeader.FileAlignment;
2267 nt.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
2268 if (test < 6) nt.OptionalHeader.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
2269 nt.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
2270 memset( nt.OptionalHeader.DataDirectory, 0, sizeof(nt.OptionalHeader.DataDirectory) );
2271 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = sizeof(data.descr);
2272 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = DATA_RVA(data.descr);
2273 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = sizeof(data.tls);
2274 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = DATA_RVA(&data.tls);
2275
2276 memset( &data, 0, sizeof(data) );
2277 data.descr[0].OriginalFirstThunk = DATA_RVA( data.original_thunks );
2278 data.descr[0].FirstThunk = DATA_RVA( data.thunks );
2279 data.descr[0].Name = DATA_RVA( data.module );
2280 strcpy( data.module, "kernel32.dll" );
2281 strcpy( data.function.name, "CreateEventA" );
2282 data.original_thunks[0].u1.AddressOfData = DATA_RVA( &data.function );
2283 data.thunks[0].u1.AddressOfData = 0xdeadbeef;
2284 nb_rel = 0;
2285
2286 data.tls.StartAddressOfRawData = nt.OptionalHeader.ImageBase + DATA_RVA( data.tls_data );
2287 ADD_RELOC( tls.StartAddressOfRawData );
2288 data.tls.EndAddressOfRawData = data.tls.StartAddressOfRawData + sizeof(data.tls_data);
2289 ADD_RELOC( tls.EndAddressOfRawData );
2290 data.tls.AddressOfIndex = nt.OptionalHeader.ImageBase + DATA_RVA( &data.tls_index );
2291 ADD_RELOC( tls.AddressOfIndex );
2292 strcpy( data.tls_data, "hello world" );
2293 data.tls_index = 9999;
2294 data.tls_index_hi = 9999;
2295
2296 if (test == 3 && sizeof(tls_init_code) > 1)
2297 {
2298 /* Windows doesn't consistently call tls init functions on dlls without entry points */
2299 assert(sizeof(tls_init_code) <= sizeof(data.tls_init_fn));
2300 assert(sizeof(entry_point_code) <= sizeof(data.entry_point_fn));
2301 memcpy(data.tls_init_fn, tls_init_code, sizeof(tls_init_code));
2302 memcpy(data.entry_point_fn, entry_point_code, sizeof(entry_point_code));
2303 tls_init_fn_output = 9999;
2304 data.tls_init_fn_output = &tls_init_fn_output;
2305 data.tls_init_fn_list[0] = nt.OptionalHeader.ImageBase + DATA_RVA(&data.tls_init_fn);
2306 ADD_RELOC( tls_init_fn_list[0] );
2307 data.tls.AddressOfCallBacks = nt.OptionalHeader.ImageBase + DATA_RVA(&data.tls_init_fn_list);
2308 ADD_RELOC( tls.AddressOfCallBacks );
2309 nt.OptionalHeader.AddressOfEntryPoint = DATA_RVA(&data.entry_point_fn);
2310 }
2311
2312 if (nb_rel % 2) nb_rel++;
2313 data.rel.reloc.VirtualAddress = nt.OptionalHeader.SectionAlignment;
2314 data.rel.reloc.SizeOfBlock = (char *)&data.rel.type_off[nb_rel] - (char *)&data.rel.reloc;
2315 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = data.rel.reloc.SizeOfBlock;
2316 nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = DATA_RVA(&data.rel);
2317
2318 GetTempPathA(MAX_PATH, temp_path);
2319 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
2320
2321 hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
2322 ok( hfile != INVALID_HANDLE_VALUE, "creation failed\n" );
2323
2324 memset( §ion, 0, sizeof(section) );
2325 memcpy( section.Name, ".text", sizeof(".text") );
2326 section.PointerToRawData = nt.OptionalHeader.FileAlignment;
2327 section.VirtualAddress = nt.OptionalHeader.SectionAlignment;
2328 section.Misc.VirtualSize = sizeof(data);
2329 section.SizeOfRawData = sizeof(data);
2330 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
2331 if (test == 3) section.Characteristics |= IMAGE_SCN_MEM_EXECUTE;
2332
2333 WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
2334 WriteFile(hfile, &nt, sizeof(nt), &dummy, NULL);
2335 WriteFile(hfile, §ion, sizeof(section), &dummy, NULL);
2336
2337 SetFilePointer( hfile, section.PointerToRawData, NULL, SEEK_SET );
2338 WriteFile(hfile, &data, sizeof(data), &dummy, NULL);
2339
2340 CloseHandle( hfile );
2341
2342 switch (test)
2343 {
2344 case 0: /* normal load */
2345 mod = LoadLibraryA( dll_name );
2346 ok( mod != NULL, "failed to load err %lu\n", GetLastError() );
2347 if (!mod) break;
2348 ptr = (struct imports *)((char *)mod + page_size);
2349 expect = GetProcAddress( GetModuleHandleA( data.module ), data.function.name );
2350 ok( (void *)ptr->thunks[0].u1.Function == expect, "thunk %p instead of %p for %s.%s\n",
2351 (void *)ptr->thunks[0].u1.Function, expect, data.module, data.function.name );
2352#ifdef __REACTOS__
2353 ok( ptr->tls_index < 32 || broken(ptr->tls_index == 9999) /* WS03 */, "wrong tls index %d\n", ptr->tls_index );
2354 if (ptr->tls_index != 9999) {
2355#else
2356 ok( ptr->tls_index < 32, "wrong tls index %d\n", ptr->tls_index );
2357#endif
2358 str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index];
2359 ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str );
2360 ok(ptr->tls_index_hi == 0, "TLS Index written as a short, high half: %d\n", ptr->tls_index_hi);
2361#ifdef __REACTOS__
2362 }
2363#endif
2364 check_tls_index(mod, ptr->tls_index != 9999);
2365 FreeLibrary( mod );
2366 break;
2367 case 1: /* load with DONT_RESOLVE_DLL_REFERENCES doesn't resolve imports */
2368 mod = LoadLibraryExA( dll_name, 0, DONT_RESOLVE_DLL_REFERENCES );
2369 ok( mod != NULL, "failed to load err %lu\n", GetLastError() );
2370 if (!mod) break;
2371 ptr = (struct imports *)((char *)mod + page_size);
2372 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
2373 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
2374 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
2375
2376 mod2 = LoadLibraryA( dll_name );
2377 ok( mod2 == mod, "loaded twice %p / %p\n", mod, mod2 );
2378 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
2379 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
2380 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
2381 check_tls_index(mod, ptr->tls_index != 9999);
2382 FreeLibrary( mod2 );
2383 FreeLibrary( mod );
2384 break;
2385 case 2: /* load without IMAGE_FILE_DLL doesn't resolve imports */
2386 mod = LoadLibraryA( dll_name );
2387 ok( mod != NULL, "failed to load err %lu\n", GetLastError() );
2388 if (!mod) break;
2389 ptr = (struct imports *)((char *)mod + page_size);
2390 ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
2391 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
2392 ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
2393 check_tls_index(mod, ptr->tls_index != 9999);
2394 FreeLibrary( mod );
2395 break;
2396 case 3: /* load with tls init function */
2397 mod = LoadLibraryA( dll_name );
2398 ok( mod != NULL, "failed to load err %lu\n", GetLastError() );
2399 if (!mod) break;
2400 ptr = (struct imports *)((char *)mod + page_size);
2401 tls_index_save = ptr->tls_index;
2402#ifdef __REACTOS__
2403 ok( ptr->tls_index < 32 || broken(ptr->tls_index == 9999) /* WS03 */, "wrong tls index %d\n", ptr->tls_index );
2404 if (sizeof(tls_init_code) > 1 && ptr->tls_index != 9999)
2405#else
2406 ok( ptr->tls_index < 32, "wrong tls index %d\n", ptr->tls_index );
2407 if (sizeof(tls_init_code) > 1)
2408#endif
2409 {
2410 str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index];
2411 ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str );
2412 /* tls init function will write the reason to *tls_init_fn_output */
2413 ok( tls_init_fn_output == DLL_PROCESS_ATTACH,
2414 "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_PROCESS_ATTACH );
2415 tls_init_fn_output = 9999;
2416 WaitForSingleObject(CreateThread(NULL, 0, tls_thread_fn, (void*)(DWORD_PTR)ptr->tls_index, 0, NULL), INFINITE);
2417 ok( tls_init_fn_output == DLL_THREAD_DETACH,
2418 "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_THREAD_DETACH );
2419 }
2420 check_tls_index(mod, ptr->tls_index != 9999);
2421 tls_init_fn_output = 9999;
2422 FreeLibrary( mod );
2423 if (tls_index_save != 9999 && sizeof(tls_init_code) > 1)
2424 ok( tls_init_fn_output == DLL_PROCESS_DETACH,
2425 "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_PROCESS_DETACH );
2426 break;
2427 case 4: /* map with ntdll */
2428 case 5: /* map with ntdll, without IMAGE_FILE_DLL */
2429 case 6: /* map with ntdll, without IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE */
2430 hfile = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
2431 ok( hfile != INVALID_HANDLE_VALUE, "CreateFile failed err %lu\n", GetLastError() );
2432 mapping = CreateFileMappingA( hfile, NULL, SEC_IMAGE | PAGE_READONLY, 0, 0, NULL );
2433 CloseHandle( hfile );
2434 if (test == 6 &&
2435 (nt_header_template.FileHeader.Machine == IMAGE_FILE_MACHINE_ARMNT ||
2436 nt_header_template.FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64))
2437 {
2438 ok( !mapping, "CreateFileMappingA succeeded\n" );
2439 ok( GetLastError() == ERROR_BAD_EXE_FORMAT, "wrong error %lu\n", GetLastError() );
2440 break;
2441 }
2442 status = pNtQuerySection( mapping, SectionImageInformation, &image, sizeof(image), &size );
2443 ok( !status, "NtQuerySection failed %lx\n", status );
2444#ifdef __REACTOS__
2445 ok( test == 6 ? !image.ImageDynamicallyRelocated : image.ImageDynamicallyRelocated || broken(GetNTVersion() < _WIN32_WINNT_VISTA),
2446#else
2447 ok( test == 6 ? !image.ImageDynamicallyRelocated : image.ImageDynamicallyRelocated,
2448#endif
2449 "image flags %x\n", image.ImageFlags);
2450 ok( !image.ImageContainsCode, "contains code %x\n", image.ImageContainsCode);
2451 ok( mapping != 0, "CreateFileMappingA failed err %lu\n", GetLastError() );
2452 /* make sure that the address is not available */
2453 tmp = VirtualAlloc( (void *)nt.OptionalHeader.ImageBase, 0x10000,
2454 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
2455 mod = NULL;
2456 size = 0;
2457 offset.QuadPart = 0;
2458 status = pNtMapViewOfSection( mapping, GetCurrentProcess(), (void **)&mod, 0, 0, &offset,
2459 &size, 1 /* ViewShare */, 0, PAGE_READONLY );
2460 todo_wine_if (test == 5)
2461#ifdef __REACTOS__
2462 ok( status == (test == 6 ? STATUS_IMAGE_NOT_AT_BASE : STATUS_SUCCESS) || broken(GetNTVersion() < _WIN32_WINNT_VISTA),
2463#else
2464 ok( status == (test == 6 ? STATUS_IMAGE_NOT_AT_BASE : STATUS_SUCCESS),
2465#endif
2466 "NtMapViewOfSection failed %lx\n", status );
2467 ok( mod != (void *)nt.OptionalHeader.ImageBase, "loaded at image base %p\n", mod );
2468 pnt = pRtlImageNtHeader( mod );
2469 ptr = (void *)((char *)mod + page_size);
2470 if (test == 6)
2471 {
2472 ok( (void *)pnt->OptionalHeader.ImageBase != mod, "not relocated from %p\n", mod );
2473 ok( (char *)ptr->tls.StartAddressOfRawData == (char *)nt.OptionalHeader.ImageBase + DATA_RVA( data.tls_data ),
2474 "tls relocated %p / %p\n", (void *)ptr->tls.StartAddressOfRawData,
2475 (char *)nt.OptionalHeader.ImageBase + DATA_RVA( data.tls_data ));
2476 }
2477 else todo_wine_if (test == 5)
2478 {
2479#ifdef __REACTOS__
2480 if (GetNTVersion() >= _WIN32_WINNT_VISTA) {
2481#endif
2482 ok( (void *)pnt->OptionalHeader.ImageBase == mod, "not at base %p / %p\n",
2483 (void *)pnt->OptionalHeader.ImageBase, mod );
2484 ok( (char *)ptr->tls.StartAddressOfRawData == (char *)mod + DATA_RVA( data.tls_data ),
2485 "tls not relocated %p / %p\n", (void *)ptr->tls.StartAddressOfRawData,
2486 (char *)mod + DATA_RVA( data.tls_data ));
2487#ifdef __REACTOS__
2488 }
2489#endif
2490 }
2491 UnmapViewOfFile( mod );
2492 CloseHandle( mapping );
2493 if (tmp) VirtualFree( tmp, 0, MEM_RELEASE );
2494 break;
2495 }
2496 DeleteFileA( dll_name );
2497 winetest_pop_context();
2498#undef DATA_RVA
2499 }
2500}
2501
2502static HANDLE gen_forward_chain_testdll( char testdll_path[MAX_PATH],
2503 const char source_dll[MAX_PATH],
2504 BOOL is_export, BOOL is_import,
2505 DWORD *exp_func_base_rva,
2506 DWORD *imp_thunk_base_rva )
2507{
2508 DWORD text_rva = page_size; /* assumes that the PE/COFF headers fit in a page */
2509 DWORD text_size = page_size;
2510 DWORD edata_rva = text_rva + text_size;
2511 DWORD edata_size = page_size;
2512 DWORD idata_rva = edata_rva + text_size;
2513 DWORD idata_size = page_size;
2514 DWORD eof_rva = idata_rva + edata_size;
2515 const IMAGE_SECTION_HEADER sections[3] = {
2516 {
2517 .Name = ".text",
2518 .Misc = { .VirtualSize = text_size },
2519 .VirtualAddress = text_rva,
2520 .SizeOfRawData = text_size,
2521 .PointerToRawData = text_rva,
2522 .Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE,
2523 },
2524 {
2525 .Name = ".edata",
2526 .Misc = { .VirtualSize = edata_size },
2527 .VirtualAddress = edata_rva,
2528 .SizeOfRawData = edata_size,
2529 .PointerToRawData = edata_rva,
2530 .Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,
2531 },
2532 {
2533 .Name = ".idata",
2534 .Misc = { .VirtualSize = edata_size },
2535 .VirtualAddress = idata_rva,
2536 .SizeOfRawData = idata_size,
2537 .PointerToRawData = idata_rva,
2538 .Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE,
2539 },
2540 };
2541 struct expdesc
2542 {
2543 const IMAGE_EXPORT_DIRECTORY dir;
2544
2545 DWORD functions[2];
2546
2547 const DWORD names[2];
2548 const WORD name_ords[2];
2549 const char str_forward_test_func[32];
2550 const char str_forward_test_func2[32];
2551
2552 char dll_name[MAX_PATH]; /* dynamically populated */
2553 char strpool[2][MAX_PATH + 16]; /* for names of export forwarders */
2554 } expdesc = {
2555 .dir = {
2556 .Characteristics = 0,
2557 .TimeDateStamp = 0x12345678,
2558 .Name = edata_rva + offsetof(struct expdesc, dll_name),
2559 .Base = 1,
2560 .NumberOfFunctions = ARRAY_SIZE(expdesc.functions),
2561 .NumberOfNames = ARRAY_SIZE(expdesc.names),
2562 .AddressOfFunctions = edata_rva + offsetof(struct expdesc, functions),
2563 .AddressOfNames = edata_rva + offsetof(struct expdesc, names),
2564 .AddressOfNameOrdinals = edata_rva + offsetof(struct expdesc, name_ords),
2565 },
2566 .functions = {
2567 text_rva + 0x4, /* may be overwritten */
2568 text_rva + 0x8, /* may be overwritten */
2569 },
2570 .names = {
2571 edata_rva + offsetof(struct expdesc, str_forward_test_func),
2572 edata_rva + offsetof(struct expdesc, str_forward_test_func2),
2573 },
2574 .name_ords = {
2575 0,
2576 1,
2577 },
2578 .str_forward_test_func = "forward_test_func",
2579 .str_forward_test_func2 = "forward_test_func2",
2580 };
2581 struct impdesc
2582 {
2583 const IMAGE_IMPORT_DESCRIPTOR descr[2];
2584 const IMAGE_THUNK_DATA original_thunks[3];
2585 const IMAGE_THUNK_DATA thunks[3];
2586 const struct { WORD hint; char name[32]; } impname_forward_test_func;
2587
2588 char module[MAX_PATH]; /* dynamically populated */
2589 } impdesc = {
2590 .descr = {
2591 {
2592 .OriginalFirstThunk = idata_rva + offsetof(struct impdesc, original_thunks),
2593 .TimeDateStamp = 0,
2594 .ForwarderChain = -1,
2595 .Name = idata_rva + offsetof(struct impdesc, module),
2596 .FirstThunk = idata_rva + offsetof(struct impdesc, thunks),
2597 },
2598 {{ 0 }},
2599 },
2600 .original_thunks = {
2601 {{ idata_rva + offsetof(struct impdesc, impname_forward_test_func) }},
2602 {{ IMAGE_ORDINAL_FLAG | 2 }},
2603 {{ 0 }},
2604 },
2605 .thunks = {
2606 {{ idata_rva + offsetof(struct impdesc, impname_forward_test_func) }},
2607 {{ IMAGE_ORDINAL_FLAG | 2 }},
2608 {{ 0 }},
2609 },
2610 .impname_forward_test_func = { 0, "forward_test_func" },
2611 };
2612 IMAGE_NT_HEADERS nt_header;
2613 char temp_path[MAX_PATH];
2614 HANDLE file, file_w;
2615 LARGE_INTEGER qpc;
2616 DWORD outlen;
2617 BOOL ret;
2618 int res;
2619
2620 QueryPerformanceCounter( &qpc );
2621 res = snprintf( expdesc.dll_name, ARRAY_SIZE(expdesc.dll_name),
2622 "ldr%05lx.dll", qpc.LowPart & 0xfffffUL );
2623 ok( res > 0 && res < ARRAY_SIZE(expdesc.dll_name), "snprintf failed\n" );
2624
2625 if (source_dll)
2626 {
2627 const char *export_names[2] = {
2628 "forward_test_func",
2629 "#2",
2630 };
2631 const char *backslash = strrchr( source_dll, '\\' );
2632 const char *dllname = backslash ? backslash + 1 : source_dll;
2633 const char *dot = strrchr( dllname, '.' );
2634 size_t ext_start = dot ? dot - dllname : strlen(dllname);
2635 size_t i;
2636
2637 res = snprintf( impdesc.module, ARRAY_SIZE(impdesc.module), "%s", dllname );
2638 ok( res > 0 && res < ARRAY_SIZE(impdesc.module), "snprintf() failed\n" );
2639
2640 for (i = 0; i < ARRAY_SIZE(export_names); i++)
2641 {
2642 char *buf;
2643 size_t buf_size;
2644
2645 assert( i < ARRAY_SIZE(expdesc.strpool) );
2646 buf = expdesc.strpool[i];
2647 buf_size = ARRAY_SIZE(expdesc.strpool[i]);
2648
2649 assert( ext_start < buf_size );
2650 memcpy( buf, dllname, ext_start );
2651 buf += ext_start;
2652 buf_size -= ext_start;
2653
2654 res = snprintf( buf, buf_size, ".%s", export_names[i] );
2655 ok( res > 0 && res < buf_size, "snprintf() failed\n" );
2656
2657 assert( i < ARRAY_SIZE(expdesc.functions) );
2658 expdesc.functions[i] = edata_rva + (expdesc.strpool[i] - (char *)&expdesc);
2659 }
2660 }
2661
2662 nt_header = nt_header_template;
2663 nt_header.FileHeader.TimeDateStamp = 0x12345678;
2664 nt_header.FileHeader.NumberOfSections = ARRAY_SIZE(sections);
2665 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
2666
2667 nt_header.OptionalHeader.SizeOfCode = text_size;
2668 nt_header.OptionalHeader.SectionAlignment = page_size;
2669 nt_header.OptionalHeader.FileAlignment = page_size;
2670 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(sections);
2671 nt_header.OptionalHeader.SizeOfImage = eof_rva;
2672 if (is_export)
2673 {
2674 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = edata_rva;
2675 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sizeof(expdesc);
2676 }
2677 /* Always have an import descriptor (even if empty) just like a real DLL */
2678 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = idata_rva;
2679 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = is_import ? sizeof(impdesc) : sizeof(IMAGE_IMPORT_DESCRIPTOR);
2680
2681 ok( nt_header.OptionalHeader.SizeOfHeaders <= text_rva,
2682 "headers (size %#lx) should not overlap with text area (RVA %#lx)\n",
2683 nt_header.OptionalHeader.SizeOfHeaders, text_rva );
2684
2685 outlen = GetTempPathA( ARRAY_SIZE(temp_path), temp_path );
2686 ok( outlen > 0 && outlen < ARRAY_SIZE(temp_path), "GetTempPathA() err=%lu\n", GetLastError() );
2687
2688 res = snprintf( testdll_path, MAX_PATH, "%s\\%s", temp_path, expdesc.dll_name );
2689 ok( res > 0 && res < MAX_PATH, "snprintf failed\n" );
2690
2691 /* Open file handle that will be deleted on close or process termination */
2692 file = CreateFileA( testdll_path,
2693 DELETE,
2694 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2695 NULL,
2696 CREATE_NEW,
2697 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
2698 NULL );
2699 ok( file != INVALID_HANDLE_VALUE, "CreateFile(%s) for delete returned error %lu\n",
2700 wine_dbgstr_a( testdll_path ), GetLastError() );
2701
2702 /* Open file again with write access */
2703 file_w = CreateFileA( testdll_path,
2704 GENERIC_WRITE,
2705 FILE_SHARE_READ | FILE_SHARE_DELETE,
2706 NULL,
2707 OPEN_EXISTING,
2708 FILE_ATTRIBUTE_NORMAL,
2709 NULL );
2710 ok( file_w != INVALID_HANDLE_VALUE, "CreateFile(%s) for write returned error %lu\n",
2711 wine_dbgstr_a( testdll_path ), GetLastError() );
2712
2713 ret = WriteFile( file_w, &dos_header, sizeof(dos_header), &outlen, NULL );
2714 ok( ret && outlen == sizeof(dos_header), "write dos_header: err=%lu outlen=%lu\n", GetLastError(), outlen );
2715
2716 ret = WriteFile( file_w, &nt_header, sizeof(nt_header), &outlen, NULL );
2717 ok( ret && outlen == sizeof(nt_header), "write nt_header: err=%lu outlen=%lu\n", GetLastError(), outlen );
2718
2719 ret = WriteFile( file_w, sections, sizeof(sections), &outlen, NULL );
2720 ok( ret && outlen == sizeof(sections), "write sections: err=%lu outlen=%lu\n", GetLastError(), outlen );
2721
2722 if (is_export)
2723 {
2724 SetFilePointer( file_w, edata_rva, NULL, FILE_BEGIN );
2725 ret = WriteFile( file_w, &expdesc, sizeof(expdesc), &outlen, NULL );
2726 ok( ret && outlen == sizeof(expdesc), "write expdesc: err=%lu outlen=%lu\n", GetLastError(), outlen );
2727 }
2728
2729 if (is_import)
2730 {
2731 SetFilePointer( file_w, idata_rva, NULL, FILE_BEGIN );
2732 ret = WriteFile( file_w, &impdesc, sizeof(impdesc), &outlen, NULL );
2733 ok( ret && outlen == sizeof(impdesc), "write impdesc: err=%lu outlen=%lu\n", GetLastError(), outlen );
2734 }
2735
2736 ret = SetFilePointer( file_w, eof_rva, NULL, FILE_BEGIN );
2737 ok( ret, "%lu\n", GetLastError() );
2738 ret = SetEndOfFile( file_w );
2739 ok( ret, "%lu\n", GetLastError() );
2740
2741 ret = CloseHandle( file_w );
2742 ok( ret, "%lu\n", GetLastError() );
2743
2744 if (exp_func_base_rva)
2745 {
2746 *exp_func_base_rva = is_export ? edata_rva + ((char *)&expdesc.functions - (char *)&expdesc) : 0;
2747 }
2748
2749 if (imp_thunk_base_rva)
2750 {
2751 *imp_thunk_base_rva = is_import ? idata_rva + ((char *)&impdesc.thunks - (char *)&impdesc) : 0;
2752 }
2753
2754 return file;
2755}
2756
2757static void subtest_export_forwarder_dep_chain( size_t num_chained_export_modules,
2758 size_t exporter_index,
2759 BOOL test_static_import )
2760{
2761 size_t num_modules = num_chained_export_modules + !!test_static_import;
2762 size_t importer_index = test_static_import ? num_modules - 1 : 0;
2763 DWORD imp_thunk_base_rva, exp_func_base_rva;
2764 size_t ultimate_depender_index = 0; /* latest module depending on modules earlier in chain */
2765 char temp_paths[4][MAX_PATH];
2766 HANDLE temp_files[4];
2767 UINT_PTR exports[2];
2768 HMODULE modules[4];
2769 BOOL res;
2770 size_t i;
2771
2772 assert(exporter_index < num_chained_export_modules);
2773 assert(num_modules > 1);
2774 assert(num_modules <= ARRAY_SIZE(temp_paths));
2775 assert(num_modules <= ARRAY_SIZE(temp_files));
2776 assert(num_modules <= ARRAY_SIZE(modules));
2777
2778 if (winetest_debug > 1)
2779 trace( "Generate a chain of test DLL fixtures\n" );
2780
2781 for (i = 0; i < num_modules; i++)
2782 {
2783 temp_files[i] = gen_forward_chain_testdll( temp_paths[i],
2784 i >= 1 ? temp_paths[i - 1] : NULL,
2785 i < num_chained_export_modules,
2786 importer_index && i == importer_index,
2787 i == 0 ? &exp_func_base_rva : NULL,
2788 i == importer_index ? &imp_thunk_base_rva : NULL );
2789 }
2790
2791 if (winetest_debug > 1)
2792 trace( "Load the entire test DLL chain\n" );
2793
2794 for (i = 0; i < num_modules; i++)
2795 {
2796 HMODULE module;
2797
2798 ok( !GetModuleHandleA( temp_paths[i] ), "%s already loaded\n",
2799 wine_dbgstr_a( temp_paths[i] ) );
2800
2801 modules[i] = LoadLibraryA( temp_paths[i] );
2802 ok( !!modules[i], "LoadLibraryA(temp_paths[%Iu] = %s) err=%lu\n",
2803 i, wine_dbgstr_a( temp_paths[i] ), GetLastError() );
2804
2805 if (i == importer_index)
2806 {
2807 /* Statically importing export forwarder introduces a load-time dependency */
2808 ultimate_depender_index = max( ultimate_depender_index, importer_index );
2809 }
2810
2811 module = GetModuleHandleA( temp_paths[i] );
2812 ok( module == modules[i], "modules[%Iu] expected %p, got %p err=%lu\n",
2813 i, modules[i], module, GetLastError() );
2814 }
2815
2816 if (winetest_debug > 1)
2817 trace( "Get address of exported functions from the source module\n" );
2818
2819 for (i = 0; i < ARRAY_SIZE(exports); i++)
2820 {
2821 char *mod_base = (char *)modules[0]; /* source (non-forward) DLL */
2822 exports[i] = (UINT_PTR)(mod_base + ((DWORD *)(mod_base + exp_func_base_rva))[i]);
2823 }
2824
2825 if (winetest_debug > 1)
2826 trace( "Check import address table of the importer DLL, if any\n" );
2827
2828 if (importer_index)
2829 {
2830 UINT_PTR *imp_thunk_base = (UINT_PTR *)((char *)modules[importer_index] + imp_thunk_base_rva);
2831 for (i = 0; i < ARRAY_SIZE(exports); i++)
2832 {
2833 ok( imp_thunk_base[i] == exports[i], "import thunk mismatch [%Iu]: (%#Ix, %#Ix)\n",
2834 i, imp_thunk_base[i], exports[i] );
2835 }
2836 }
2837
2838 if (winetest_debug > 1)
2839 trace( "Call GetProcAddress() on the exporter DLL, if any\n" );
2840
2841 if (exporter_index)
2842 {
2843 UINT_PTR proc;
2844
2845 proc = (UINT_PTR)GetProcAddress( modules[exporter_index], "forward_test_func" );
2846 ok( proc == exports[0], "GetProcAddress mismatch [0]: (%#Ix, %#Ix)\n", proc, exports[0] );
2847
2848 proc = (UINT_PTR)GetProcAddress( modules[exporter_index], (LPSTR)2 );
2849 ok( proc == exports[1], "GetProcAddress mismatch [1]: (%#Ix, %#Ix)\n", proc, exports[1] );
2850
2851 /* Dynamically importing export forwarder introduces a runtime dependency */
2852 ultimate_depender_index = max( ultimate_depender_index, exporter_index );
2853 }
2854
2855 if (winetest_debug > 1)
2856 trace( "Unreference modules except the ultimate dependant DLL\n" );
2857
2858 for (i = 0; i < ultimate_depender_index; i++)
2859 {
2860 HMODULE module;
2861
2862 res = FreeLibrary( modules[i] );
2863 ok( res, "FreeLibrary(modules[%Iu]) err=%lu\n", i, GetLastError() );
2864
2865 /* FreeLibrary() should *not* unload the DLL immediately */
2866 module = GetModuleHandleA( temp_paths[i] );
2867 todo_wine_if(i < ultimate_depender_index && i + 1 != importer_index)
2868 ok( module == modules[i], "modules[%Iu] expected %p, got %p (unloaded?) err=%lu\n",
2869 i, modules[i], module, GetLastError() );
2870 }
2871
2872 if (winetest_debug > 1)
2873 trace( "The ultimate dependant DLL should keep other DLLs from being unloaded\n" );
2874
2875 for (i = 0; i < num_modules; i++)
2876 {
2877 HMODULE module = GetModuleHandleA( temp_paths[i] );
2878
2879 todo_wine_if(i < ultimate_depender_index && i + 1 != importer_index)
2880 ok( module == modules[i], "modules[%Iu] expected %p, got %p (unloaded?) err=%lu\n",
2881 i, modules[i], module, GetLastError() );
2882 }
2883
2884 if (winetest_debug > 1)
2885 trace( "Unreference the remaining modules (including the dependant DLL)\n" );
2886
2887 for (i = ultimate_depender_index; i < num_modules; i++)
2888 {
2889 res = FreeLibrary( modules[i] );
2890 ok( res, "FreeLibrary(modules[%Iu]) err=%lu\n", i, GetLastError() );
2891
2892 /* FreeLibrary() should unload the DLL immediately */
2893 ok( !GetModuleHandleA( temp_paths[i] ), "modules[%Iu] should not be kept loaded (2)\n", i );
2894 }
2895
2896 if (winetest_debug > 1)
2897 trace( "All modules should be unloaded; the unloading process should not reload any DLL\n" );
2898
2899#ifdef __REACTOS__
2900 if (GetNTVersion() >= _WIN32_WINNT_VISTA) {
2901#endif
2902 for (i = 0; i < num_modules; i++)
2903 {
2904 ok( !GetModuleHandleA( temp_paths[i] ), "modules[%Iu] should not be kept loaded (3)\n", i );
2905 }
2906#ifdef __REACTOS__
2907 }
2908#endif
2909
2910 if (winetest_debug > 1)
2911 trace( "Close and delete temp files\n" );
2912
2913 for (i = 0; i < num_modules; i++)
2914 {
2915 /* handles should be delete-on-close */
2916 CloseHandle( temp_files[i] );
2917 }
2918}
2919
2920static void test_export_forwarder_dep_chain(void)
2921{
2922 winetest_push_context( "no import" );
2923 /* export forwarder does not introduce a dependency on its own */
2924 subtest_export_forwarder_dep_chain( 2, 0, FALSE );
2925 winetest_pop_context();
2926
2927 winetest_push_context( "static import of export forwarder" );
2928 subtest_export_forwarder_dep_chain( 2, 0, TRUE );
2929 winetest_pop_context();
2930
2931 winetest_push_context( "static import of chained export forwarder" );
2932 subtest_export_forwarder_dep_chain( 3, 0, TRUE );
2933 winetest_pop_context();
2934
2935 winetest_push_context( "dynamic import of export forwarder" );
2936 subtest_export_forwarder_dep_chain( 2, 1, FALSE );
2937 winetest_pop_context();
2938
2939 winetest_push_context( "dynamic import of chained export forwarder" );
2940 subtest_export_forwarder_dep_chain( 3, 2, FALSE );
2941 winetest_pop_context();
2942}
2943
2944#define MAX_COUNT 10
2945static HANDLE attached_thread[MAX_COUNT];
2946static DWORD attached_thread_count;
2947static HANDLE event, mutex, semaphore;
2948static HANDLE stop_event, loader_lock_event, peb_lock_event, heap_lock_event, cs_lock_event, ack_event;
2949static CRITICAL_SECTION cs_lock;
2950static int test_dll_phase, inside_loader_lock, inside_peb_lock, inside_heap_lock, inside_cs_lock;
2951static LONG fls_callback_count;
2952
2953static DWORD WINAPI mutex_thread_proc(void *param)
2954{
2955 HANDLE wait_list[5];
2956 DWORD ret;
2957
2958 ret = WaitForSingleObject(mutex, 0);
2959 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret);
2960
2961 SetEvent(param);
2962
2963 wait_list[0] = stop_event;
2964 wait_list[1] = loader_lock_event;
2965 wait_list[2] = peb_lock_event;
2966 wait_list[3] = heap_lock_event;
2967 wait_list[4] = cs_lock_event;
2968
2969 trace("%04lx: mutex_thread_proc: starting\n", GetCurrentThreadId());
2970 while (1)
2971 {
2972 ret = WaitForMultipleObjects(ARRAY_SIZE(wait_list), wait_list, FALSE, 50);
2973 if (ret == WAIT_OBJECT_0) break;
2974 else if (ret == WAIT_OBJECT_0 + 1)
2975 {
2976 ULONG_PTR loader_lock_magic;
2977 trace("%04lx: mutex_thread_proc: Entering loader lock\n", GetCurrentThreadId());
2978 ret = pLdrLockLoaderLock(0, NULL, &loader_lock_magic);
2979 ok(!ret, "LdrLockLoaderLock error %#lx\n", ret);
2980 inside_loader_lock++;
2981 SetEvent(ack_event);
2982 }
2983 else if (ret == WAIT_OBJECT_0 + 2)
2984 {
2985 trace("%04lx: mutex_thread_proc: Entering PEB lock\n", GetCurrentThreadId());
2986 pRtlAcquirePebLock();
2987 inside_peb_lock++;
2988 SetEvent(ack_event);
2989 }
2990 else if (ret == WAIT_OBJECT_0 + 3)
2991 {
2992 trace("%04lx: mutex_thread_proc: Entering heap lock\n", GetCurrentThreadId());
2993 HeapLock(GetProcessHeap());
2994 inside_heap_lock++;
2995 SetEvent(ack_event);
2996 }
2997 else if (ret == WAIT_OBJECT_0 + 4)
2998 {
2999 trace("%04lx: mutex_thread_proc: Entering CS lock\n", GetCurrentThreadId());
3000 EnterCriticalSection(&cs_lock);
3001 inside_cs_lock++;
3002 SetEvent(ack_event);
3003 }
3004 }
3005
3006 trace("%04lx: mutex_thread_proc: exiting\n", GetCurrentThreadId());
3007 return 196;
3008}
3009
3010static DWORD WINAPI semaphore_thread_proc(void *param)
3011{
3012 DWORD ret;
3013
3014 ret = WaitForSingleObject(semaphore, 0);
3015 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret);
3016
3017 SetEvent(param);
3018
3019 while (1)
3020 {
3021 if (winetest_debug > 1)
3022 trace("%04lx: semaphore_thread_proc: still alive\n", GetCurrentThreadId());
3023 if (WaitForSingleObject(stop_event, 50) != WAIT_TIMEOUT) break;
3024 }
3025
3026 trace("%04lx: semaphore_thread_proc: exiting\n", GetCurrentThreadId());
3027 return 196;
3028}
3029
3030static DWORD WINAPI noop_thread_proc(void *param)
3031{
3032 if (param)
3033 {
3034 LONG *noop_thread_started = param;
3035 InterlockedIncrement(noop_thread_started);
3036 }
3037
3038 trace("%04lx: noop_thread_proc: exiting\n", GetCurrentThreadId());
3039 return 195;
3040}
3041
3042static VOID WINAPI fls_callback(PVOID lpFlsData)
3043{
3044 ok(lpFlsData == (void*) 0x31415, "lpFlsData is %p, expected %p\n", lpFlsData, (void*) 0x31415);
3045 InterlockedIncrement(&fls_callback_count);
3046}
3047
3048static LIST_ENTRY *fls_list_head;
3049
3050static unsigned int check_linked_list(const LIST_ENTRY *le, const LIST_ENTRY *search_entry, unsigned int *index_found)
3051{
3052 unsigned int count = 0;
3053 LIST_ENTRY *entry;
3054
3055 *index_found = ~0;
3056
3057 for (entry = le->Flink; entry != le; entry = entry->Flink)
3058 {
3059 if (entry == search_entry)
3060 {
3061 ok(*index_found == ~0, "Duplicate list entry.\n");
3062 *index_found = count;
3063 }
3064 ++count;
3065 }
3066 return count;
3067}
3068
3069static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param)
3070{
3071 static LONG noop_thread_started;
3072 static DWORD fls_index = FLS_OUT_OF_INDEXES, fls_index2 = FLS_OUT_OF_INDEXES;
3073 static int fls_count = 0;
3074 static int thread_detach_count = 0;
3075 static int thread_count;
3076 DWORD ret;
3077
3078 ok(!inside_loader_lock, "inside_loader_lock should not be set\n");
3079 ok(!inside_peb_lock, "inside_peb_lock should not be set\n");
3080
3081 switch (reason)
3082 {
3083 case DLL_PROCESS_ATTACH:
3084 trace("dll: %p, DLL_PROCESS_ATTACH, %p\n", hinst, param);
3085
3086 ret = pRtlDllShutdownInProgress();
3087 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3088
3089 /* Set up the FLS slot, if FLS is available */
3090 if (pFlsGetValue)
3091 {
3092 void* value;
3093 BOOL bret;
3094 ret = pFlsAlloc(&fls_callback);
3095 ok(ret != FLS_OUT_OF_INDEXES, "FlsAlloc returned %ld\n", ret);
3096 fls_index = ret;
3097 SetLastError(0xdeadbeef);
3098 value = pFlsGetValue(fls_index);
3099 ok(!value, "FlsGetValue returned %p, expected NULL\n", value);
3100 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %lu\n", GetLastError());
3101 bret = pFlsSetValue(fls_index, (void*) 0x31415);
3102 ok(bret, "FlsSetValue failed\n");
3103 fls_count++;
3104
3105 fls_index2 = pFlsAlloc(&fls_callback);
3106 ok(fls_index2 != FLS_OUT_OF_INDEXES, "FlsAlloc returned %ld\n", ret);
3107 }
3108 ++thread_count;
3109 break;
3110 case DLL_PROCESS_DETACH:
3111 {
3112 DWORD code, expected_code, i;
3113 HANDLE handle, process;
3114 void *addr;
3115 SIZE_T size;
3116 LARGE_INTEGER offset;
3117 DEBUG_EVENT de;
3118
3119 trace("dll: %p, DLL_PROCESS_DETACH, %p\n", hinst, param);
3120
3121 if (test_dll_phase == 4 || test_dll_phase == 5)
3122 {
3123 ok(0, "dll_entry_point(DLL_PROCESS_DETACH) should not be called\n");
3124 break;
3125 }
3126
3127 /* The process should already deadlock at this point */
3128 if (test_dll_phase == 6)
3129 {
3130 /* In reality, code below never gets executed, probably some other
3131 * code tries to access process heap and deadlocks earlier, even XP
3132 * doesn't call the DLL entry point on process detach either.
3133 */
3134 HeapLock(GetProcessHeap());
3135 todo_wine
3136 ok(0, "dll_entry_point: process should already deadlock\n");
3137 break;
3138 }
3139 else if (test_dll_phase == 7)
3140 {
3141 EnterCriticalSection(&cs_lock);
3142 }
3143
3144 if (test_dll_phase == 0 || test_dll_phase == 1 || test_dll_phase == 3 || test_dll_phase == 7)
3145 ok(param != NULL, "dll: param %p\n", param);
3146 else
3147 ok(!param, "dll: param %p\n", param);
3148
3149 if (test_dll_phase == 0 || test_dll_phase == 1) expected_code = 195;
3150 else if (test_dll_phase == 3) expected_code = 196;
3151 else if (test_dll_phase == 7) expected_code = 199;
3152 else expected_code = STILL_ACTIVE;
3153
3154 ret = pRtlDllShutdownInProgress();
3155 if (test_dll_phase == 0 || test_dll_phase == 1 || test_dll_phase == 3)
3156 {
3157 ok(ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3158 }
3159 else
3160 {
3161 /* FIXME: remove once Wine is fixed */
3162 todo_wine_if (!(expected_code == STILL_ACTIVE || expected_code == 196))
3163#ifdef __REACTOS__
3164 ok(!ret || broken(GetNTVersion() < _WIN32_WINNT_VISTA), "RtlDllShutdownInProgress returned %ld\n", ret);
3165#else
3166 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3167#endif
3168 }
3169
3170 /* In the case that the process is terminating, FLS slots should still be accessible, but
3171 * the callback should be already run for this thread and the contents already NULL.
3172 */
3173 if (param && pFlsGetValue)
3174 {
3175 void* value;
3176 SetLastError(0xdeadbeef);
3177 value = pFlsGetValue(fls_index);
3178#ifdef __REACTOS__
3179 ok(value == NULL || broken(value == (void*)0x31415) /* WS03 */, "FlsGetValue returned %p, expected NULL\n", value);
3180#else
3181 ok(value == NULL, "FlsGetValue returned %p, expected NULL\n", value);
3182#endif
3183 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %lu\n", GetLastError());
3184#ifdef __REACTOS__
3185 ok(fls_callback_count == thread_detach_count + 1 || broken(GetNTVersion() < _WIN32_WINNT_VISTA),
3186 "wrong FLS callback count %ld, expected %d\n", fls_callback_count, thread_detach_count + 1);
3187#else
3188 ok(fls_callback_count == thread_detach_count + 1,
3189 "wrong FLS callback count %ld, expected %d\n", fls_callback_count, thread_detach_count + 1);
3190#endif
3191 }
3192 if (pFlsFree)
3193 {
3194 BOOL ret;
3195 /* Call FlsFree now and run the remaining callbacks from uncleanly terminated threads */
3196 ret = pFlsFree(fls_index);
3197 ok(ret, "FlsFree failed with error %lu\n", GetLastError());
3198 fls_index = FLS_OUT_OF_INDEXES;
3199#ifdef __REACTOS__
3200 if (GetNTVersion() >= _WIN32_WINNT_VISTA)
3201#endif
3202 ok(fls_callback_count == fls_count,
3203 "wrong FLS callback count %ld, expected %d\n", fls_callback_count, fls_count);
3204 }
3205
3206 ok(attached_thread_count >= 2, "attached thread count should be >= 2\n");
3207
3208 for (i = 0; i < attached_thread_count; i++)
3209 {
3210 /* Calling GetExitCodeThread() without waiting for thread termination
3211 * leads to different results due to a race condition.
3212 */
3213 if (expected_code != STILL_ACTIVE)
3214 {
3215 ret = WaitForSingleObject(attached_thread[i], 1000);
3216 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret);
3217 }
3218 ret = GetExitCodeThread(attached_thread[i], &code);
3219 trace("dll: GetExitCodeThread(%lu) => %ld,%lu\n", i, ret, code);
3220 ok(ret == 1, "GetExitCodeThread returned %ld, expected 1\n", ret);
3221 ok(code == expected_code, "expected thread exit code %lu, got %lu\n", expected_code, code);
3222 }
3223
3224 ret = WaitForSingleObject(event, 0);
3225 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3226
3227 ret = WaitForSingleObject(mutex, 0);
3228 if (expected_code == STILL_ACTIVE)
3229 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3230 else
3231 ok(ret == WAIT_ABANDONED, "expected WAIT_ABANDONED, got %#lx\n", ret);
3232
3233 /* semaphore is not abandoned on thread termination */
3234 ret = WaitForSingleObject(semaphore, 0);
3235 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3236
3237 if (expected_code == STILL_ACTIVE)
3238 {
3239 ret = WaitForSingleObject(attached_thread[0], 0);
3240 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3241 ret = WaitForSingleObject(attached_thread[1], 0);
3242 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3243 }
3244 else
3245 {
3246 ret = WaitForSingleObject(attached_thread[0], 0);
3247 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret);
3248 ret = WaitForSingleObject(attached_thread[1], 0);
3249 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret);
3250 }
3251
3252 /* win7 doesn't allow creating a thread during process shutdown but
3253 * earlier Windows versions allow it.
3254 */
3255 noop_thread_started = 0;
3256 SetLastError(0xdeadbeef);
3257 handle = CreateThread(NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
3258 if (param)
3259 {
3260#ifdef __REACTOS__
3261 ok(!handle || broken(handle != 0) /* Pre-Win7 */, "CreateThread should fail\n");
3262
3263 if (!handle)
3264 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
3265 else
3266 {
3267 ret = WaitForSingleObject(handle, 1000);
3268 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
3269 CloseHandle(handle);
3270 }
3271#else
3272 ok(!handle, "CreateThread should fail\n");
3273 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
3274#endif
3275 }
3276 else
3277 {
3278 ok(handle != 0, "CreateThread error %ld\n", GetLastError());
3279 ret = WaitForSingleObject(handle, 1000);
3280 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3281 ok(!noop_thread_started, "thread shouldn't start yet\n");
3282 CloseHandle(handle);
3283 }
3284
3285 SetLastError(0xdeadbeef);
3286 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, GetCurrentProcessId());
3287 ok(process != NULL, "OpenProcess error %ld\n", GetLastError());
3288
3289 noop_thread_started = 0;
3290 SetLastError(0xdeadbeef);
3291 handle = CreateRemoteThread(process, NULL, 0, noop_thread_proc, &noop_thread_started, 0, &ret);
3292 if (param)
3293 {
3294#ifdef __REACTOS__
3295 ok(!handle || broken(handle != 0) /* Pre-Win7 */, "CreateRemoteThread should fail\n");
3296
3297 if (!handle)
3298 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
3299 else
3300 {
3301 ret = WaitForSingleObject(handle, 1000);
3302 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#x\n", ret);
3303 CloseHandle(handle);
3304 }
3305#else
3306 ok(!handle, "CreateRemoteThread should fail\n");
3307 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
3308#endif
3309 }
3310 else
3311 {
3312 ok(handle != 0, "CreateRemoteThread error %ld\n", GetLastError());
3313 ret = WaitForSingleObject(handle, 1000);
3314 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3315 ok(!noop_thread_started, "thread shouldn't start yet\n");
3316 CloseHandle(handle);
3317 }
3318
3319 SetLastError(0xdeadbeef);
3320 handle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
3321 ok(handle != 0, "CreateFileMapping error %ld\n", GetLastError());
3322
3323 offset.u.LowPart = 0;
3324 offset.u.HighPart = 0;
3325 addr = NULL;
3326 size = 0;
3327 ret = pNtMapViewOfSection(handle, process, &addr, 0, 0, &offset,
3328 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
3329 ok(ret == STATUS_SUCCESS, "NtMapViewOfSection error %#lx\n", ret);
3330 ret = pNtUnmapViewOfSection(process, addr);
3331 ok(ret == STATUS_SUCCESS, "NtUnmapViewOfSection error %#lx\n", ret);
3332
3333 CloseHandle(handle);
3334 CloseHandle(process);
3335
3336 handle = GetModuleHandleA("winver.exe");
3337 ok(!handle, "winver.exe shouldn't be loaded yet\n");
3338 SetLastError(0xdeadbeef);
3339 handle = LoadLibraryA("winver.exe");
3340 ok(handle != 0, "LoadLibrary error %ld\n", GetLastError());
3341 SetLastError(0xdeadbeef);
3342 ret = FreeLibrary(handle);
3343 ok(ret, "FreeLibrary error %ld\n", GetLastError());
3344 handle = GetModuleHandleA("winver.exe");
3345 if (param)
3346 ok(handle != 0, "winver.exe should not be unloaded\n");
3347 else
3348 todo_wine
3349 ok(!handle, "winver.exe should be unloaded\n");
3350
3351 SetLastError(0xdeadbeef);
3352 ret = WaitForDebugEvent(&de, 0);
3353 ok(!ret, "WaitForDebugEvent should fail\n");
3354 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
3355
3356 SetLastError(0xdeadbeef);
3357 ret = DebugActiveProcess(GetCurrentProcessId());
3358 ok(!ret, "DebugActiveProcess should fail\n");
3359 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
3360
3361 SetLastError(0xdeadbeef);
3362 ret = WaitForDebugEvent(&de, 0);
3363 ok(!ret, "WaitForDebugEvent should fail\n");
3364 ok(GetLastError() == ERROR_SEM_TIMEOUT, "expected ERROR_SEM_TIMEOUT, got %ld\n", GetLastError());
3365
3366 if (test_dll_phase == 2)
3367 {
3368 trace("dll: call ExitProcess()\n");
3369 *child_failures = winetest_get_failures();
3370 ExitProcess(197);
3371 }
3372 trace("dll: %p, DLL_PROCESS_DETACH, %p => DONE\n", hinst, param);
3373 break;
3374 }
3375 case DLL_THREAD_ATTACH:
3376 trace("dll: %p, DLL_THREAD_ATTACH, %p\n", hinst, param);
3377
3378 ++thread_count;
3379
3380 ret = pRtlDllShutdownInProgress();
3381 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3382
3383 if (attached_thread_count < MAX_COUNT)
3384 {
3385 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &attached_thread[attached_thread_count],
3386 0, TRUE, DUPLICATE_SAME_ACCESS);
3387 attached_thread_count++;
3388 }
3389
3390 /* Make sure the FLS slot is empty, if FLS is available */
3391 if (pFlsGetValue)
3392 {
3393 void* value;
3394 BOOL ret;
3395 SetLastError(0xdeadbeef);
3396 value = pFlsGetValue(fls_index);
3397 ok(!value, "FlsGetValue returned %p, expected NULL\n", value);
3398 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %lu\n", GetLastError());
3399 ret = pFlsSetValue(fls_index, (void*) 0x31415);
3400 ok(ret, "FlsSetValue failed\n");
3401 fls_count++;
3402 }
3403
3404 break;
3405 case DLL_THREAD_DETACH:
3406 trace("dll: %p, DLL_THREAD_DETACH, %p\n", hinst, param);
3407 --thread_count;
3408 thread_detach_count++;
3409
3410 ret = pRtlDllShutdownInProgress();
3411 /* win7 doesn't allow creating a thread during process shutdown but
3412 * earlier Windows versions allow it. In that case DLL_THREAD_DETACH is
3413 * sent on thread exit, but DLL_THREAD_ATTACH is never received.
3414 */
3415 if (noop_thread_started)
3416 ok(ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3417 else
3418 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3419
3420 /* FLS data should already be destroyed, if FLS is available.
3421 */
3422 if (pFlsGetValue && fls_index != FLS_OUT_OF_INDEXES)
3423 {
3424 unsigned int index, count;
3425 void* value;
3426 BOOL bret;
3427
3428 SetLastError(0xdeadbeef);
3429 value = pFlsGetValue(fls_index);
3430#ifdef __REACTOS__
3431 ok(!value || broken(value == (void*)0x31415) /* WS03 */, "FlsGetValue returned %p, expected NULL\n", value);
3432#else
3433 ok(!value, "FlsGetValue returned %p, expected NULL\n", value);
3434#endif
3435 ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %lu\n", GetLastError());
3436
3437 bret = pFlsSetValue(fls_index2, (void*) 0x31415);
3438 ok(bret, "FlsSetValue failed\n");
3439
3440 if (fls_list_head)
3441 {
3442 count = check_linked_list(fls_list_head, &NtCurrentTeb()->FlsSlots->fls_list_entry, &index);
3443#ifdef __REACTOS__
3444 if (GetNTVersion() >= _WIN32_WINNT_VISTA) {
3445#endif
3446 ok(count <= thread_count, "Got unexpected count %u, thread_count %u.\n", count, thread_count);
3447 ok(index == ~0, "Got unexpected index %u.\n", index);
3448#ifdef __REACTOS__
3449 }
3450#endif
3451 }
3452 }
3453
3454 break;
3455 default:
3456 trace("dll: %p, %ld, %p\n", hinst, reason, param);
3457 break;
3458 }
3459
3460 *child_failures = winetest_get_failures();
3461
3462 return TRUE;
3463}
3464
3465static void CALLBACK ldr_notify_callback(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
3466{
3467 /* If some DLL happens to be loaded during process shutdown load notification is called but never unload
3468 * notification. */
3469 ok(reason == LDR_DLL_NOTIFICATION_REASON_LOADED, "got reason %lu.\n", reason);
3470}
3471
3472static void child_process(const char *dll_name, DWORD target_offset)
3473{
3474 void *target;
3475 DWORD ret, dummy, i, code, expected_code;
3476 HANDLE file, thread, process;
3477 HMODULE hmod;
3478 struct PROCESS_BASIC_INFORMATION_PRIVATE pbi;
3479 DWORD_PTR affinity;
3480 void *cookie;
3481
3482 trace("phase %d: writing %p at %#lx\n", test_dll_phase, dll_entry_point, target_offset);
3483
3484 if (pFlsAlloc)
3485 {
3486 fls_list_head = NtCurrentTeb()->Peb->FlsListHead.Flink ? &NtCurrentTeb()->Peb->FlsListHead
3487 : NtCurrentTeb()->FlsSlots->fls_list_entry.Flink;
3488 }
3489
3490 SetLastError(0xdeadbeef);
3491 mutex = CreateMutexW(NULL, FALSE, NULL);
3492 ok(mutex != 0, "CreateMutex error %ld\n", GetLastError());
3493
3494 SetLastError(0xdeadbeef);
3495 semaphore = CreateSemaphoreW(NULL, 1, 1, NULL);
3496 ok(semaphore != 0, "CreateSemaphore error %ld\n", GetLastError());
3497
3498 SetLastError(0xdeadbeef);
3499 event = CreateEventW(NULL, TRUE, FALSE, NULL);
3500 ok(event != 0, "CreateEvent error %ld\n", GetLastError());
3501
3502 SetLastError(0xdeadbeef);
3503 loader_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
3504 ok(loader_lock_event != 0, "CreateEvent error %ld\n", GetLastError());
3505
3506 SetLastError(0xdeadbeef);
3507 peb_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
3508 ok(peb_lock_event != 0, "CreateEvent error %ld\n", GetLastError());
3509
3510 SetLastError(0xdeadbeef);
3511 heap_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
3512 ok(heap_lock_event != 0, "CreateEvent error %ld\n", GetLastError());
3513
3514 InitializeCriticalSection(&cs_lock);
3515 SetLastError(0xdeadbeef);
3516 cs_lock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
3517 ok(cs_lock_event != 0, "CreateEvent error %ld\n", GetLastError());
3518
3519 SetLastError(0xdeadbeef);
3520 ack_event = CreateEventW(NULL, FALSE, FALSE, NULL);
3521 ok(ack_event != 0, "CreateEvent error %ld\n", GetLastError());
3522
3523 file = CreateFileA(dll_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3524 if (file == INVALID_HANDLE_VALUE)
3525 {
3526 ok(0, "could not open %s\n", dll_name);
3527 return;
3528 }
3529 SetFilePointer(file, target_offset, NULL, FILE_BEGIN);
3530 SetLastError(0xdeadbeef);
3531 target = dll_entry_point;
3532 ret = WriteFile(file, &target, sizeof(target), &dummy, NULL);
3533 ok(ret, "WriteFile error %ld\n", GetLastError());
3534 CloseHandle(file);
3535
3536 SetLastError(0xdeadbeef);
3537 hmod = LoadLibraryA(dll_name);
3538 ok(hmod != 0, "LoadLibrary error %ld\n", GetLastError());
3539
3540 SetLastError(0xdeadbeef);
3541 stop_event = CreateEventW(NULL, TRUE, FALSE, NULL);
3542 ok(stop_event != 0, "CreateEvent error %ld\n", GetLastError());
3543
3544 SetLastError(0xdeadbeef);
3545 thread = CreateThread(NULL, 0, mutex_thread_proc, event, 0, &dummy);
3546 ok(thread != 0, "CreateThread error %ld\n", GetLastError());
3547 WaitForSingleObject(event, 3000);
3548 CloseHandle(thread);
3549
3550 ResetEvent(event);
3551
3552 SetLastError(0xdeadbeef);
3553 thread = CreateThread(NULL, 0, semaphore_thread_proc, event, 0, &dummy);
3554 ok(thread != 0, "CreateThread error %ld\n", GetLastError());
3555 WaitForSingleObject(event, 3000);
3556 CloseHandle(thread);
3557
3558 ResetEvent(event);
3559 Sleep(100);
3560
3561 ok(attached_thread_count == 2, "attached thread count should be 2\n");
3562 for (i = 0; i < attached_thread_count; i++)
3563 {
3564 ret = GetExitCodeThread(attached_thread[i], &code);
3565 trace("child: GetExitCodeThread(%lu) => %ld,%lu\n", i, ret, code);
3566 ok(ret == 1, "GetExitCodeThread returned %ld, expected 1\n", ret);
3567 ok(code == STILL_ACTIVE, "expected thread exit code STILL_ACTIVE, got %lu\n", code);
3568 }
3569
3570 ret = WaitForSingleObject(attached_thread[0], 0);
3571 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3572 ret = WaitForSingleObject(attached_thread[1], 0);
3573 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3574
3575 ret = WaitForSingleObject(event, 0);
3576 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3577 ret = WaitForSingleObject(mutex, 0);
3578 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3579 ret = WaitForSingleObject(semaphore, 0);
3580 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3581
3582 ret = pRtlDllShutdownInProgress();
3583 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3584
3585 SetLastError(0xdeadbeef);
3586 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, GetCurrentProcessId());
3587 ok(process != NULL, "OpenProcess error %ld\n", GetLastError());
3588
3589 SetLastError(0xdeadbeef);
3590 ret = TerminateProcess(0, 195);
3591 ok(!ret, "TerminateProcess(0) should fail\n");
3592 ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
3593
3594 Sleep(100);
3595
3596 affinity = 1;
3597 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
3598 ok(!ret, "NtSetInformationProcess error %#lx\n", ret);
3599
3600 switch (test_dll_phase)
3601 {
3602 case 0:
3603 ret = pRtlDllShutdownInProgress();
3604 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3605
3606 trace("call NtTerminateProcess(0, 195)\n");
3607 ret = pNtTerminateProcess(0, 195);
3608 ok(!ret, "NtTerminateProcess error %#lx\n", ret);
3609
3610 memset(&pbi, 0, sizeof(pbi));
3611 ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
3612 ok(!ret, "NtQueryInformationProcess error %#lx\n", ret);
3613 ok(pbi.ExitStatus == STILL_ACTIVE || pbi.ExitStatus == 195,
3614 "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus);
3615 affinity = 1;
3616 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
3617 ok(!ret, "NtSetInformationProcess error %#lx\n", ret);
3618
3619 ret = pRtlDllShutdownInProgress();
3620 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3621
3622 hmod = GetModuleHandleA(dll_name);
3623 ok(hmod != 0, "DLL should not be unloaded\n");
3624
3625#ifdef __REACTOS__
3626 if (GetNTVersion() >= _WIN32_WINNT_VISTA) {
3627#endif
3628 SetLastError(0xdeadbeef);
3629 thread = CreateThread(NULL, 0, noop_thread_proc, &dummy, 0, &ret);
3630 ok(!thread, "CreateThread should fail\n");
3631 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
3632#ifdef __REACTOS__
3633 }
3634#endif
3635
3636 trace("call LdrShutdownProcess()\n");
3637 pLdrRegisterDllNotification(0, ldr_notify_callback, NULL, &cookie);
3638 pLdrShutdownProcess();
3639
3640 ret = pRtlDllShutdownInProgress();
3641 ok(ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3642
3643 hmod = GetModuleHandleA(dll_name);
3644 ok(hmod != 0, "DLL should not be unloaded\n");
3645
3646 memset(&pbi, 0, sizeof(pbi));
3647 ret = pNtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
3648 ok(!ret, "NtQueryInformationProcess error %#lx\n", ret);
3649 ok(pbi.ExitStatus == STILL_ACTIVE || pbi.ExitStatus == 195,
3650 "expected STILL_ACTIVE, got %lu\n", pbi.ExitStatus);
3651 affinity = 1;
3652 ret = pNtSetInformationProcess(process, ProcessAffinityMask, &affinity, sizeof(affinity));
3653 ok(!ret, "NtSetInformationProcess error %#lx\n", ret);
3654 break;
3655
3656 case 1: /* normal ExitProcess */
3657 ret = pRtlDllShutdownInProgress();
3658 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3659 break;
3660
3661 case 2: /* ExitProcess will be called by the PROCESS_DETACH handler */
3662 ret = pRtlDllShutdownInProgress();
3663 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3664
3665 trace("call FreeLibrary(%p)\n", hmod);
3666 SetLastError(0xdeadbeef);
3667 ret = FreeLibrary(hmod);
3668 ok(ret, "FreeLibrary error %ld\n", GetLastError());
3669 hmod = GetModuleHandleA(dll_name);
3670 ok(!hmod, "DLL should be unloaded\n");
3671
3672 if (test_dll_phase == 2)
3673 ok(0, "FreeLibrary+ExitProcess should never return\n");
3674
3675 ret = pRtlDllShutdownInProgress();
3676 ok(!ret, "RtlDllShutdownInProgress returned %ld\n", ret);
3677
3678 break;
3679
3680 case 3:
3681 trace("signalling thread exit\n");
3682 SetEvent(stop_event);
3683 break;
3684
3685 case 4:
3686 trace("setting loader_lock_event\n");
3687 SetEvent(loader_lock_event);
3688 WaitForSingleObject(ack_event, 1000);
3689 ok(inside_loader_lock != 0, "inside_loader_lock is not set\n");
3690
3691 /* calling NtTerminateProcess should not cause a deadlock */
3692 trace("call NtTerminateProcess(0, 198)\n");
3693 ret = pNtTerminateProcess(0, 198);
3694 ok(!ret, "NtTerminateProcess error %#lx\n", ret);
3695
3696 *child_failures = winetest_get_failures();
3697
3698 /* Windows fails to release loader lock acquired from another thread,
3699 * so the LdrUnlockLoaderLock call fails here and ExitProcess deadlocks
3700 * later on, so NtTerminateProcess is used instead.
3701 */
3702 trace("call NtTerminateProcess(GetCurrentProcess(), 198)\n");
3703 pNtTerminateProcess(GetCurrentProcess(), 198);
3704 ok(0, "NtTerminateProcess should not return\n");
3705 break;
3706
3707 case 5:
3708 trace("setting peb_lock_event\n");
3709 SetEvent(peb_lock_event);
3710 WaitForSingleObject(ack_event, 1000);
3711 ok(inside_peb_lock != 0, "inside_peb_lock is not set\n");
3712
3713 *child_failures = winetest_get_failures();
3714
3715 /* calling ExitProcess should cause a deadlock */
3716 trace("call ExitProcess(198)\n");
3717 ExitProcess(198);
3718 ok(0, "ExitProcess should not return\n");
3719 break;
3720
3721 case 6:
3722 trace("setting heap_lock_event\n");
3723 SetEvent(heap_lock_event);
3724 WaitForSingleObject(ack_event, 1000);
3725 ok(inside_heap_lock != 0, "inside_heap_lock is not set\n");
3726
3727 *child_failures = winetest_get_failures();
3728
3729 /* calling ExitProcess should cause a deadlock */
3730 trace("call ExitProcess(1)\n");
3731 ExitProcess(1);
3732 ok(0, "ExitProcess should not return\n");
3733 break;
3734
3735 case 7:
3736 trace("setting cs_lock_event\n");
3737 SetEvent(cs_lock_event);
3738 WaitForSingleObject(ack_event, 1000);
3739 ok(inside_cs_lock != 0, "inside_cs_lock is not set\n");
3740
3741 *child_failures = winetest_get_failures();
3742
3743 /* calling ExitProcess should not cause a deadlock */
3744 trace("call ExitProcess(199)\n");
3745 ExitProcess(199);
3746 ok(0, "ExitProcess should not return\n");
3747 break;
3748
3749 default:
3750 assert(0);
3751 break;
3752 }
3753
3754 if (test_dll_phase == 0) expected_code = 195;
3755 else if (test_dll_phase == 3) expected_code = 196;
3756 else if (test_dll_phase == 4) expected_code = 198;
3757 else expected_code = STILL_ACTIVE;
3758
3759 if (expected_code == STILL_ACTIVE)
3760 {
3761 ret = WaitForSingleObject(attached_thread[0], 100);
3762 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3763 ret = WaitForSingleObject(attached_thread[1], 100);
3764 ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %#lx\n", ret);
3765 }
3766 else
3767 {
3768 ret = WaitForSingleObject(attached_thread[0], 2000);
3769 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret);
3770 ret = WaitForSingleObject(attached_thread[1], 2000);
3771 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %#lx\n", ret);
3772 }
3773
3774 for (i = 0; i < attached_thread_count; i++)
3775 {
3776 ret = GetExitCodeThread(attached_thread[i], &code);
3777 trace("child: GetExitCodeThread(%lu) => %ld,%lu\n", i, ret, code);
3778 ok(ret == 1, "GetExitCodeThread returned %ld, expected 1\n", ret);
3779 ok(code == expected_code, "expected thread exit code %lu, got %lu\n", expected_code, code);
3780 }
3781
3782 *child_failures = winetest_get_failures();
3783
3784 trace("call ExitProcess(195)\n");
3785 ExitProcess(195);
3786}
3787
3788static void test_ExitProcess(void)
3789{
3790#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
3791#include "pshpack1.h"
3792#ifdef __x86_64__
3793 static struct section_data
3794 {
3795 BYTE mov_rax[2];
3796 void *target;
3797 BYTE jmp_rax[2];
3798 } section_data = { { 0x48,0xb8 }, dll_entry_point, { 0xff,0xe0 } };
3799#elif defined(__i386__)
3800 static struct section_data
3801 {
3802 BYTE mov_eax;
3803 void *target;
3804 BYTE jmp_eax[2];
3805 } section_data = { 0xb8, dll_entry_point, { 0xff,0xe0 } };
3806#elif defined(__aarch64__)
3807 static struct section_data
3808 {
3809 DWORD ldr; /* ldr x0,target */
3810 DWORD br; /* br x0 */
3811 void *target;
3812 } section_data = { 0x58000040, 0xd61f0000, dll_entry_point };
3813#endif
3814#include "poppack.h"
3815 DWORD dummy, file_align;
3816 HANDLE file, thread, process, hmap, hmap_dup;
3817 char temp_path[MAX_PATH], dll_name[MAX_PATH], cmdline[MAX_PATH * 2];
3818 DWORD ret, target_offset, old_prot;
3819 char **argv, buf[256];
3820 PROCESS_INFORMATION pi;
3821 STARTUPINFOA si = { sizeof(si) };
3822 CONTEXT ctx;
3823 struct PROCESS_BASIC_INFORMATION_PRIVATE pbi;
3824 MEMORY_BASIC_INFORMATION mbi;
3825 DWORD_PTR affinity;
3826 void *addr;
3827 LARGE_INTEGER offset;
3828 SIZE_T size;
3829 IMAGE_NT_HEADERS nt_header;
3830
3831 if (!pRtlDllShutdownInProgress)
3832 {
3833 win_skip("RtlDllShutdownInProgress is not available on this platform (XP+)\n");
3834 return;
3835 }
3836 if (!pNtQueryInformationProcess || !pNtSetInformationProcess)
3837 {
3838 win_skip("NtQueryInformationProcess/NtSetInformationProcess are not available on this platform\n");
3839 return;
3840 }
3841 if (!pNtAllocateVirtualMemory || !pNtFreeVirtualMemory)
3842 {
3843 win_skip("NtAllocateVirtualMemory/NtFreeVirtualMemory are not available on this platform\n");
3844 return;
3845 }
3846
3847 /* prevent displaying of the "Unable to load this DLL" message box */
3848 SetErrorMode(SEM_FAILCRITICALERRORS);
3849
3850 GetTempPathA(MAX_PATH, temp_path);
3851 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
3852
3853 /*trace("creating %s\n", dll_name);*/
3854 file = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
3855 if (file == INVALID_HANDLE_VALUE)
3856 {
3857 ok(0, "could not create %s\n", dll_name);
3858 return;
3859 }
3860
3861 SetLastError(0xdeadbeef);
3862 ret = WriteFile(file, &dos_header, sizeof(dos_header), &dummy, NULL);
3863 ok(ret, "WriteFile error %ld\n", GetLastError());
3864
3865 nt_header = nt_header_template;
3866 nt_header.OptionalHeader.AddressOfEntryPoint = 0x1000;
3867 nt_header.OptionalHeader.SectionAlignment = 0x1000;
3868 nt_header.OptionalHeader.FileAlignment = 0x200;
3869 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x1000;
3870 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER);
3871 SetLastError(0xdeadbeef);
3872 ret = WriteFile(file, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
3873 ok(ret, "WriteFile error %ld\n", GetLastError());
3874 SetLastError(0xdeadbeef);
3875 ret = WriteFile(file, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
3876 ok(ret, "WriteFile error %ld\n", GetLastError());
3877
3878 section.SizeOfRawData = sizeof(section_data);
3879 section.PointerToRawData = nt_header.OptionalHeader.FileAlignment;
3880 section.VirtualAddress = nt_header.OptionalHeader.SectionAlignment;
3881 section.Misc.VirtualSize = sizeof(section_data);
3882 section.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
3883 SetLastError(0xdeadbeef);
3884 ret = WriteFile(file, §ion, sizeof(section), &dummy, NULL);
3885 ok(ret, "WriteFile error %ld\n", GetLastError());
3886
3887 file_align = nt_header.OptionalHeader.FileAlignment - nt_header.OptionalHeader.SizeOfHeaders;
3888 assert(file_align < sizeof(filler));
3889 SetLastError(0xdeadbeef);
3890 ret = WriteFile(file, filler, file_align, &dummy, NULL);
3891 ok(ret, "WriteFile error %ld\n", GetLastError());
3892
3893 target_offset = SetFilePointer(file, 0, NULL, FILE_CURRENT) + FIELD_OFFSET(struct section_data, target);
3894
3895 /* section data */
3896 SetLastError(0xdeadbeef);
3897 ret = WriteFile(file, §ion_data, sizeof(section_data), &dummy, NULL);
3898 ok(ret, "WriteFile error %ld\n", GetLastError());
3899
3900 CloseHandle(file);
3901
3902 winetest_get_mainargs(&argv);
3903
3904 /* phase 0 */
3905 *child_failures = -1;
3906 sprintf(cmdline, "\"%s\" loader %s %lu 0", argv[0], dll_name, target_offset);
3907 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3908 ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError());
3909 ret = WaitForSingleObject(pi.hProcess, 10000);
3910 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3911 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
3912 GetExitCodeProcess(pi.hProcess, &ret);
3913#ifdef __REACTOS__
3914 ok(ret == 195 || broken(ret == 0xc0000005) /* WS03 */, "expected exit code 195, got %lu\n", ret);
3915#else
3916 ok(ret == 195, "expected exit code 195, got %lu\n", ret);
3917#endif
3918 if (*child_failures)
3919 {
3920 trace("%ld failures in child process\n", *child_failures);
3921 winetest_add_failures(*child_failures);
3922 }
3923 CloseHandle(pi.hThread);
3924 CloseHandle(pi.hProcess);
3925
3926 /* phase 1 */
3927 *child_failures = -1;
3928 sprintf(cmdline, "\"%s\" loader %s %lu 1", argv[0], dll_name, target_offset);
3929 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3930 ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError());
3931 ret = WaitForSingleObject(pi.hProcess, 10000);
3932 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3933 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
3934 GetExitCodeProcess(pi.hProcess, &ret);
3935 ok(ret == 195, "expected exit code 195, got %lu\n", ret);
3936 if (*child_failures)
3937 {
3938 trace("%ld failures in child process\n", *child_failures);
3939 winetest_add_failures(*child_failures);
3940 }
3941 CloseHandle(pi.hThread);
3942 CloseHandle(pi.hProcess);
3943
3944 /* phase 2 */
3945 *child_failures = -1;
3946 sprintf(cmdline, "\"%s\" loader %s %lu 2", argv[0], dll_name, target_offset);
3947 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3948 ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError());
3949 ret = WaitForSingleObject(pi.hProcess, 10000);
3950 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3951 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
3952 GetExitCodeProcess(pi.hProcess, &ret);
3953 ok(ret == 197, "expected exit code 197, got %lu\n", ret);
3954 if (*child_failures)
3955 {
3956 trace("%ld failures in child process\n", *child_failures);
3957 winetest_add_failures(*child_failures);
3958 }
3959 CloseHandle(pi.hThread);
3960 CloseHandle(pi.hProcess);
3961
3962 /* phase 3 */
3963 *child_failures = -1;
3964 sprintf(cmdline, "\"%s\" loader %s %lu 3", argv[0], dll_name, target_offset);
3965 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3966 ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError());
3967 ret = WaitForSingleObject(pi.hProcess, 10000);
3968 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3969 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
3970 GetExitCodeProcess(pi.hProcess, &ret);
3971 ok(ret == 195, "expected exit code 195, got %lu\n", ret);
3972 if (*child_failures)
3973 {
3974 trace("%ld failures in child process\n", *child_failures);
3975 winetest_add_failures(*child_failures);
3976 }
3977 CloseHandle(pi.hThread);
3978 CloseHandle(pi.hProcess);
3979
3980 /* phase 4 */
3981 if (pLdrLockLoaderLock && pLdrUnlockLoaderLock)
3982 {
3983 *child_failures = -1;
3984 sprintf(cmdline, "\"%s\" loader %s %lu 4", argv[0], dll_name, target_offset);
3985 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3986 ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError());
3987 ret = WaitForSingleObject(pi.hProcess, 10000);
3988 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
3989 if (ret != WAIT_OBJECT_0) TerminateProcess(pi.hProcess, 0);
3990 GetExitCodeProcess(pi.hProcess, &ret);
3991 ok(ret == 198, "expected exit code 198, got %lu\n", ret);
3992 if (*child_failures)
3993 {
3994 trace("%ld failures in child process\n", *child_failures);
3995 winetest_add_failures(*child_failures);
3996 }
3997 CloseHandle(pi.hThread);
3998 CloseHandle(pi.hProcess);
3999 }
4000 else
4001 win_skip("LdrLockLoaderLock/LdrUnlockLoaderLock are not available on this platform\n");
4002
4003 /* phase 5 */
4004 if (pRtlAcquirePebLock && pRtlReleasePebLock)
4005 {
4006 *child_failures = -1;
4007 sprintf(cmdline, "\"%s\" loader %s %lu 5", argv[0], dll_name, target_offset);
4008 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
4009 ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError());
4010 ret = WaitForSingleObject(pi.hProcess, 5000);
4011 ok(ret == WAIT_TIMEOUT, "child process should fail to terminate\n");
4012 if (ret != WAIT_OBJECT_0)
4013 {
4014 trace("terminating child process\n");
4015 TerminateProcess(pi.hProcess, 199);
4016 }
4017 ret = WaitForSingleObject(pi.hProcess, 1000);
4018 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
4019 GetExitCodeProcess(pi.hProcess, &ret);
4020 ok(ret == 199, "expected exit code 199, got %lu\n", ret);
4021 if (*child_failures)
4022 {
4023 trace("%ld failures in child process\n", *child_failures);
4024 winetest_add_failures(*child_failures);
4025 }
4026 CloseHandle(pi.hThread);
4027 CloseHandle(pi.hProcess);
4028 }
4029 else
4030 win_skip("RtlAcquirePebLock/RtlReleasePebLock are not available on this platform\n");
4031
4032 /* phase 6 */
4033 *child_failures = -1;
4034 sprintf(cmdline, "\"%s\" loader %s %lu 6", argv[0], dll_name, target_offset);
4035 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
4036 ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError());
4037 ret = WaitForSingleObject(pi.hProcess, 5000);
4038 todo_wine
4039#ifdef __REACTOS__
4040 ok(ret == WAIT_TIMEOUT || broken(ret == WAIT_OBJECT_0) /* WS03 */, "child process should fail to terminate\n");
4041#else
4042 ok(ret == WAIT_TIMEOUT, "child process should fail to terminate\n");
4043#endif
4044 if (ret != WAIT_OBJECT_0)
4045 {
4046 trace("terminating child process\n");
4047 TerminateProcess(pi.hProcess, 201);
4048 }
4049 ret = WaitForSingleObject(pi.hProcess, 1000);
4050 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
4051 GetExitCodeProcess(pi.hProcess, &ret);
4052 todo_wine
4053#ifdef __REACTOS__
4054 ok(ret == 201 || broken(ret == 1) /* WS03 */, "expected exit code 201, got %lu\n", ret);
4055#else
4056 ok(ret == 201, "expected exit code 201, got %lu\n", ret);
4057#endif
4058 if (*child_failures)
4059 {
4060 trace("%ld failures in child process\n", *child_failures);
4061 winetest_add_failures(*child_failures);
4062 }
4063 CloseHandle(pi.hThread);
4064 CloseHandle(pi.hProcess);
4065
4066 /* phase 7 */
4067 *child_failures = -1;
4068 sprintf(cmdline, "\"%s\" loader %s %lu 7", argv[0], dll_name, target_offset);
4069 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
4070 ok(ret, "CreateProcess(%s) error %ld\n", cmdline, GetLastError());
4071 ret = WaitForSingleObject(pi.hProcess, 5000);
4072 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
4073 if (ret != WAIT_OBJECT_0)
4074 {
4075 trace("terminating child process\n");
4076 TerminateProcess(pi.hProcess, 199);
4077 }
4078 ret = WaitForSingleObject(pi.hProcess, 1000);
4079 ok(ret == WAIT_OBJECT_0, "child process failed to terminate\n");
4080 GetExitCodeProcess(pi.hProcess, &ret);
4081 ok(ret == 199, "expected exit code 199, got %lu\n", ret);
4082 if (*child_failures)
4083 {
4084 trace("%ld failures in child process\n", *child_failures);
4085 winetest_add_failures(*child_failures);
4086 }
4087 CloseHandle(pi.hThread);
4088 CloseHandle(pi.hProcess);
4089
4090 /* test remote process termination */
4091 SetLastError(0xdeadbeef);
4092 ret = CreateProcessA(argv[0], NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
4093 ok(ret, "CreateProcess(%s) error %ld\n", argv[0], GetLastError());
4094
4095 SetLastError(0xdeadbeef);
4096 addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
4097 ok(addr != NULL, "VirtualAllocEx error %ld\n", GetLastError());
4098 SetLastError(0xdeadbeef);
4099 ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READONLY, &old_prot);
4100 ok(ret, "VirtualProtectEx error %ld\n", GetLastError());
4101 ok(old_prot == PAGE_READWRITE, "expected PAGE_READWRITE, got %#lx\n", old_prot);
4102 SetLastError(0xdeadbeef);
4103 size = VirtualQueryEx(pi.hProcess, NULL, &mbi, sizeof(mbi));
4104 ok(size == sizeof(mbi), "VirtualQueryEx error %ld\n", GetLastError());
4105
4106 SetLastError(0xdeadbeef);
4107 ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size);
4108 ok(ret, "ReadProcessMemory error %ld\n", GetLastError());
4109 ok(size == 4, "expected 4, got %Iu\n", size);
4110
4111 SetLastError(0xdeadbeef);
4112 hmap = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
4113 ok(hmap != 0, "CreateFileMapping error %ld\n", GetLastError());
4114
4115 SetLastError(0xdeadbeef);
4116 ret = DuplicateHandle(GetCurrentProcess(), hmap, pi.hProcess, &hmap_dup,
4117 0, FALSE, DUPLICATE_SAME_ACCESS);
4118 ok(ret, "DuplicateHandle error %ld\n", GetLastError());
4119
4120 offset.u.LowPart = 0;
4121 offset.u.HighPart = 0;
4122 addr = NULL;
4123 size = 0;
4124 ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset,
4125 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
4126 ok(!ret, "NtMapViewOfSection error %#lx\n", ret);
4127 ret = pNtUnmapViewOfSection(pi.hProcess, addr);
4128 ok(!ret, "NtUnmapViewOfSection error %#lx\n", ret);
4129
4130 SetLastError(0xdeadbeef);
4131 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
4132 ok(thread != 0, "CreateRemoteThread error %ld\n", GetLastError());
4133 SetLastError(0xdeadbeef);
4134 ctx.ContextFlags = CONTEXT_INTEGER;
4135 ret = GetThreadContext(thread, &ctx);
4136 ok(ret, "GetThreadContext error %ld\n", GetLastError());
4137 SetLastError(0xdeadbeef);
4138 ctx.ContextFlags = CONTEXT_INTEGER;
4139 ret = SetThreadContext(thread, &ctx);
4140 ok(ret, "SetThreadContext error %ld\n", GetLastError());
4141 SetLastError(0xdeadbeef);
4142 ret = SetThreadPriority(thread, 0);
4143 ok(ret, "SetThreadPriority error %ld\n", GetLastError());
4144
4145 SetLastError(0xdeadbeef);
4146 ret = TerminateThread(thread, 199);
4147 ok(ret, "TerminateThread error %ld\n", GetLastError());
4148 /* Calling GetExitCodeThread() without waiting for thread termination
4149 * leads to different results due to a race condition.
4150 */
4151 ret = WaitForSingleObject(thread, 1000);
4152 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %lx\n", ret);
4153 GetExitCodeThread(thread, &ret);
4154 ok(ret == 199, "expected exit code 199, got %lu\n", ret);
4155
4156 SetLastError(0xdeadbeef);
4157 ret = TerminateProcess(pi.hProcess, 198);
4158 ok(ret, "TerminateProcess error %ld\n", GetLastError());
4159 /* Checking process state without waiting for process termination
4160 * leads to different results due to a race condition.
4161 */
4162 ret = WaitForSingleObject(pi.hProcess, 1000);
4163 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %lx\n", ret);
4164
4165 SetLastError(0xdeadbeef);
4166 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pi.dwProcessId);
4167 ok(process != NULL, "OpenProcess error %ld\n", GetLastError());
4168 CloseHandle(process);
4169
4170 memset(&pbi, 0, sizeof(pbi));
4171 ret = pNtQueryInformationProcess(pi.hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
4172 ok(!ret, "NtQueryInformationProcess error %#lx\n", ret);
4173 ok(pbi.ExitStatus == 198, "expected 198, got %lu\n", pbi.ExitStatus);
4174 affinity = 1;
4175 ret = pNtSetInformationProcess(pi.hProcess, ProcessAffinityMask, &affinity, sizeof(affinity));
4176 ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#lx\n", ret);
4177
4178 SetLastError(0xdeadbeef);
4179 ctx.ContextFlags = CONTEXT_INTEGER;
4180 ret = GetThreadContext(thread, &ctx);
4181 ok(!ret, "GetThreadContext should fail\n");
4182 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
4183 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
4184 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */ ||
4185 GetLastError() == ERROR_ACCESS_DENIED /* Win10 32-bit */,
4186 "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4187 SetLastError(0xdeadbeef);
4188 ctx.ContextFlags = CONTEXT_INTEGER;
4189 ret = SetThreadContext(thread, &ctx);
4190 ok(!ret, "SetThreadContext should fail\n");
4191 ok(GetLastError() == ERROR_ACCESS_DENIED ||
4192 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
4193 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
4194 "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4195 SetLastError(0xdeadbeef);
4196 ret = SetThreadPriority(thread, 0);
4197 ok(ret, "SetThreadPriority error %ld\n", GetLastError());
4198 CloseHandle(thread);
4199
4200 ret = WaitForSingleObject(pi.hThread, 1000);
4201 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed: %lx\n", ret);
4202 SetLastError(0xdeadbeef);
4203 ctx.ContextFlags = CONTEXT_INTEGER;
4204 ret = GetThreadContext(pi.hThread, &ctx);
4205 ok(!ret, "GetThreadContext should fail\n");
4206 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
4207 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
4208 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */ ||
4209 GetLastError() == ERROR_ACCESS_DENIED /* Win10 32-bit */,
4210 "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4211 SetLastError(0xdeadbeef);
4212 ctx.ContextFlags = CONTEXT_INTEGER;
4213 ret = SetThreadContext(pi.hThread, &ctx);
4214 ok(!ret, "SetThreadContext should fail\n");
4215 ok(GetLastError() == ERROR_ACCESS_DENIED ||
4216 GetLastError() == ERROR_GEN_FAILURE /* win7 64-bit */ ||
4217 GetLastError() == ERROR_INVALID_FUNCTION /* vista 64-bit */,
4218 "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4219 SetLastError(0xdeadbeef);
4220 ret = VirtualProtectEx(pi.hProcess, addr, 4096, PAGE_READWRITE, &old_prot);
4221 ok(!ret, "VirtualProtectEx should fail\n");
4222 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4223 SetLastError(0xdeadbeef);
4224 size = 0;
4225 ret = ReadProcessMemory(pi.hProcess, addr, buf, 4, &size);
4226 ok(!ret, "ReadProcessMemory should fail\n");
4227 ok(GetLastError() == ERROR_PARTIAL_COPY || GetLastError() == ERROR_ACCESS_DENIED,
4228 "expected ERROR_PARTIAL_COPY, got %ld\n", GetLastError());
4229 ok(!size, "expected 0, got %Iu\n", size);
4230 SetLastError(0xdeadbeef);
4231 ret = VirtualFreeEx(pi.hProcess, addr, 0, MEM_RELEASE);
4232 ok(!ret, "VirtualFreeEx should fail\n");
4233 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4234 SetLastError(0xdeadbeef);
4235 addr = VirtualAllocEx(pi.hProcess, NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
4236 ok(!addr, "VirtualAllocEx should fail\n");
4237 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4238 SetLastError(0xdeadbeef);
4239 size = VirtualQueryEx(pi.hProcess, NULL, &mbi, sizeof(mbi));
4240 ok(!size, "VirtualQueryEx should fail\n");
4241 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4242
4243 /* CloseHandle() call below leads to premature process termination
4244 * under some Windows versions.
4245 */
4246if (0)
4247{
4248 SetLastError(0xdeadbeef);
4249 ret = CloseHandle(hmap_dup);
4250 ok(ret, "CloseHandle should not fail\n");
4251}
4252
4253 SetLastError(0xdeadbeef);
4254 ret = DuplicateHandle(GetCurrentProcess(), hmap, pi.hProcess, &hmap_dup,
4255 0, FALSE, DUPLICATE_SAME_ACCESS);
4256 ok(!ret, "DuplicateHandle should fail\n");
4257 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4258
4259 offset.u.LowPart = 0;
4260 offset.u.HighPart = 0;
4261 addr = NULL;
4262 size = 0;
4263 ret = pNtMapViewOfSection(hmap, pi.hProcess, &addr, 0, 0, &offset,
4264 &size, 1 /* ViewShare */, 0, PAGE_READONLY);
4265 ok(ret == STATUS_PROCESS_IS_TERMINATING, "expected STATUS_PROCESS_IS_TERMINATING, got %#lx\n", ret);
4266
4267 SetLastError(0xdeadbeef);
4268 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
4269 ok(!thread, "CreateRemoteThread should fail\n");
4270 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4271
4272 SetLastError(0xdeadbeef);
4273 ret = DebugActiveProcess(pi.dwProcessId);
4274 ok(!ret, "DebugActiveProcess should fail\n");
4275 ok(GetLastError() == ERROR_ACCESS_DENIED /* 64-bit */ || GetLastError() == ERROR_NOT_SUPPORTED /* 32-bit */,
4276 "ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
4277
4278 GetExitCodeProcess(pi.hProcess, &ret);
4279 ok(ret == 198, "expected exit code 198, got %lu\n", ret);
4280 CloseHandle(pi.hThread);
4281 CloseHandle(pi.hProcess);
4282
4283 ret = DeleteFileA(dll_name);
4284 ok(ret, "DeleteFile error %ld\n", GetLastError());
4285#else
4286 skip("x86 specific ExitProcess test\n");
4287#endif
4288}
4289
4290static PVOID WINAPI failuredllhook(ULONG ul, DELAYLOAD_INFO* pd)
4291{
4292 ok(ul == 4, "expected 4, got %lu\n", ul);
4293 ok(!!pd, "no delayload info supplied\n");
4294 if (pd)
4295 {
4296 ok(pd->Size == sizeof(*pd), "got %lu\n", pd->Size);
4297 ok(!!pd->DelayloadDescriptor, "no DelayloadDescriptor supplied\n");
4298 if (pd->DelayloadDescriptor)
4299 {
4300 ok(pd->DelayloadDescriptor->Attributes.AllAttributes == 1,
4301 "expected 1, got %lu\n", pd->DelayloadDescriptor->Attributes.AllAttributes);
4302 ok(pd->DelayloadDescriptor->DllNameRVA == 0x2000,
4303 "expected 0x2000, got %lx\n", pd->DelayloadDescriptor->DllNameRVA);
4304 ok(pd->DelayloadDescriptor->ModuleHandleRVA == 0x201a,
4305 "expected 0x201a, got %lx\n", pd->DelayloadDescriptor->ModuleHandleRVA);
4306 ok(pd->DelayloadDescriptor->ImportAddressTableRVA > pd->DelayloadDescriptor->ModuleHandleRVA,
4307 "expected %lx > %lx\n", pd->DelayloadDescriptor->ImportAddressTableRVA,
4308 pd->DelayloadDescriptor->ModuleHandleRVA);
4309 ok(pd->DelayloadDescriptor->ImportNameTableRVA > pd->DelayloadDescriptor->ImportAddressTableRVA,
4310 "expected %lx > %lx\n", pd->DelayloadDescriptor->ImportNameTableRVA,
4311 pd->DelayloadDescriptor->ImportAddressTableRVA);
4312 ok(pd->DelayloadDescriptor->BoundImportAddressTableRVA == 0,
4313 "expected 0, got %lx\n", pd->DelayloadDescriptor->BoundImportAddressTableRVA);
4314 ok(pd->DelayloadDescriptor->UnloadInformationTableRVA == 0,
4315 "expected 0, got %lx\n", pd->DelayloadDescriptor->UnloadInformationTableRVA);
4316 ok(pd->DelayloadDescriptor->TimeDateStamp == 0,
4317 "expected 0, got %lx\n", pd->DelayloadDescriptor->TimeDateStamp);
4318 }
4319
4320 ok(!!pd->ThunkAddress, "no ThunkAddress supplied\n");
4321 if (pd->ThunkAddress)
4322 ok(pd->ThunkAddress->u1.Ordinal, "no ThunkAddress value supplied\n");
4323
4324 ok(!!pd->TargetDllName, "no TargetDllName supplied\n");
4325 if (pd->TargetDllName)
4326 ok(!strcmp(pd->TargetDllName, "secur32.dll"),
4327 "expected \"secur32.dll\", got \"%s\"\n", pd->TargetDllName);
4328
4329 ok(pd->TargetApiDescriptor.ImportDescribedByName == 0,
4330 "expected 0, got %lx\n", pd->TargetApiDescriptor.ImportDescribedByName);
4331 ok(pd->TargetApiDescriptor.Description.Ordinal == 0 ||
4332 pd->TargetApiDescriptor.Description.Ordinal == 999,
4333 "expected 0, got %lx\n", pd->TargetApiDescriptor.Description.Ordinal);
4334
4335 ok(!!pd->TargetModuleBase, "no TargetModuleBase supplied\n");
4336 ok(pd->Unused == NULL, "expected NULL, got %p\n", pd->Unused);
4337 ok(pd->LastError, "no LastError supplied\n");
4338 }
4339 cb_count++;
4340 return (void*)0xdeadbeef;
4341}
4342
4343static PVOID WINAPI failuresyshook(const char *dll, const char *function)
4344{
4345 ok(!strcmp(dll, "secur32.dll"), "wrong dll: %s\n", dll);
4346 ok(!((ULONG_PTR)function >> 16), "expected ordinal, got %p\n", function);
4347 cb_count_sys++;
4348 return (void*)0x12345678;
4349}
4350
4351static void test_ResolveDelayLoadedAPI(void)
4352{
4353 static const char test_dll[] = "secur32.dll";
4354 static const char test_func[] = "SealMessage";
4355 char temp_path[MAX_PATH];
4356 char dll_name[MAX_PATH];
4357 IMAGE_DELAYLOAD_DESCRIPTOR idd, *delaydir;
4358 IMAGE_THUNK_DATA itd32;
4359 HANDLE hfile;
4360 HMODULE hlib;
4361 DWORD dummy, file_size, i;
4362 WORD hint = 0;
4363 BOOL ret;
4364 IMAGE_NT_HEADERS nt_header;
4365
4366 static const struct test_data
4367 {
4368 BOOL func;
4369 UINT_PTR ordinal;
4370 BOOL succeeds;
4371 } td[] =
4372 {
4373 {
4374 TRUE, 0, TRUE
4375 },
4376 {
4377 FALSE, IMAGE_ORDINAL_FLAG | 2, TRUE
4378 },
4379 {
4380 FALSE, IMAGE_ORDINAL_FLAG | 5, TRUE
4381 },
4382 {
4383 FALSE, IMAGE_ORDINAL_FLAG | 0, FALSE
4384 },
4385 {
4386 FALSE, IMAGE_ORDINAL_FLAG | 999, FALSE
4387 },
4388 };
4389
4390 if (!pResolveDelayLoadedAPI)
4391 {
4392 win_skip("ResolveDelayLoadedAPI is not available\n");
4393 return;
4394 }
4395
4396 if (0) /* crashes on native */
4397 {
4398 SetLastError(0xdeadbeef);
4399 ok(!pResolveDelayLoadedAPI(NULL, NULL, NULL, NULL, NULL, 0),
4400 "ResolveDelayLoadedAPI succeeded\n");
4401 ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %lx\n", GetLastError());
4402
4403 cb_count = 0;
4404 SetLastError(0xdeadbeef);
4405 ok(!pResolveDelayLoadedAPI(NULL, NULL, failuredllhook, NULL, NULL, 0),
4406 "ResolveDelayLoadedAPI succeeded\n");
4407 ok(GetLastError() == 0xdeadbeef, "GetLastError changed to %lx\n", GetLastError());
4408 ok(cb_count == 1, "Wrong callback count: %d\n", cb_count);
4409 }
4410
4411 GetTempPathA(MAX_PATH, temp_path);
4412 GetTempFileNameA(temp_path, "ldr", 0, dll_name);
4413 trace("creating %s\n", dll_name);
4414 hfile = CreateFileA(dll_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
4415 if (hfile == INVALID_HANDLE_VALUE)
4416 {
4417 ok(0, "could not create %s\n", dll_name);
4418 return;
4419 }
4420
4421 SetLastError(0xdeadbeef);
4422 ret = WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL);
4423 ok(ret, "WriteFile error %ld\n", GetLastError());
4424
4425 nt_header = nt_header_template;
4426 nt_header.FileHeader.NumberOfSections = 2;
4427 nt_header.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
4428
4429 nt_header.OptionalHeader.SectionAlignment = 0x1000;
4430 nt_header.OptionalHeader.FileAlignment = 0x1000;
4431 nt_header.OptionalHeader.SizeOfImage = sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x2200;
4432 nt_header.OptionalHeader.SizeOfHeaders = sizeof(dos_header) + sizeof(nt_header) + 2 * sizeof(IMAGE_SECTION_HEADER);
4433 nt_header.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
4434 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress = 0x1000;
4435 nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size = 2 * sizeof(idd);
4436
4437 SetLastError(0xdeadbeef);
4438 ret = WriteFile(hfile, &nt_header, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), &dummy, NULL);
4439 ok(ret, "WriteFile error %ld\n", GetLastError());
4440
4441 SetLastError(0xdeadbeef);
4442 ret = WriteFile(hfile, &nt_header.OptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER), &dummy, NULL);
4443 ok(ret, "WriteFile error %ld\n", GetLastError());
4444
4445 /* sections */
4446 section.PointerToRawData = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
4447 section.VirtualAddress = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
4448 section.Misc.VirtualSize = 0x1000;
4449 section.SizeOfRawData = 2 * sizeof(idd);
4450 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
4451 SetLastError(0xdeadbeef);
4452 ret = WriteFile(hfile, §ion, sizeof(section), &dummy, NULL);
4453 ok(ret, "WriteFile error %ld\n", GetLastError());
4454
4455 section.PointerToRawData = 0x2000;
4456 section.VirtualAddress = 0x2000;
4457 i = ARRAY_SIZE(td);
4458 section.SizeOfRawData = sizeof(test_dll) + sizeof(hint) + sizeof(test_func) + sizeof(HMODULE) +
4459 2 * (i + 1) * sizeof(IMAGE_THUNK_DATA);
4460 ok(section.SizeOfRawData <= 0x1000, "Too much tests, add a new section!\n");
4461 section.Misc.VirtualSize = 0x1000;
4462 section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
4463 SetLastError(0xdeadbeef);
4464 ret = WriteFile(hfile, §ion, sizeof(section), &dummy, NULL);
4465 ok(ret, "WriteFile error %ld\n", GetLastError());
4466
4467 /* fill up to delay data */
4468 SetFilePointer( hfile, nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress, NULL, SEEK_SET );
4469
4470 /* delay data */
4471 idd.Attributes.AllAttributes = 1;
4472 idd.DllNameRVA = 0x2000;
4473 idd.ModuleHandleRVA = idd.DllNameRVA + sizeof(test_dll) + sizeof(hint) + sizeof(test_func);
4474 idd.ImportAddressTableRVA = idd.ModuleHandleRVA + sizeof(HMODULE);
4475 idd.ImportNameTableRVA = idd.ImportAddressTableRVA + (i + 1) * sizeof(IMAGE_THUNK_DATA);
4476 idd.BoundImportAddressTableRVA = 0;
4477 idd.UnloadInformationTableRVA = 0;
4478 idd.TimeDateStamp = 0;
4479
4480 SetLastError(0xdeadbeef);
4481 ret = WriteFile(hfile, &idd, sizeof(idd), &dummy, NULL);
4482 ok(ret, "WriteFile error %ld\n", GetLastError());
4483
4484 SetLastError(0xdeadbeef);
4485 ret = WriteFile(hfile, filler, sizeof(idd), &dummy, NULL);
4486 ok(ret, "WriteFile error %ld\n", GetLastError());
4487
4488 /* fill up to extended delay data */
4489 SetFilePointer( hfile, idd.DllNameRVA, NULL, SEEK_SET );
4490
4491 /* extended delay data */
4492 SetLastError(0xdeadbeef);
4493 ret = WriteFile(hfile, test_dll, sizeof(test_dll), &dummy, NULL);
4494 ok(ret, "WriteFile error %ld\n", GetLastError());
4495
4496 SetLastError(0xdeadbeef);
4497 ret = WriteFile(hfile, &hint, sizeof(hint), &dummy, NULL);
4498 ok(ret, "WriteFile error %ld\n", GetLastError());
4499
4500 SetLastError(0xdeadbeef);
4501 ret = WriteFile(hfile, test_func, sizeof(test_func), &dummy, NULL);
4502 ok(ret, "WriteFile error %ld\n", GetLastError());
4503
4504 SetFilePointer( hfile, idd.ImportAddressTableRVA, NULL, SEEK_SET );
4505
4506 for (i = 0; i < ARRAY_SIZE(td); i++)
4507 {
4508 /* 0x1a00 is an empty space between delay data and extended delay data, real thunks are not necessary */
4509 itd32.u1.Function = nt_header.OptionalHeader.ImageBase + 0x1a00 + i * 0x20;
4510 SetLastError(0xdeadbeef);
4511 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
4512 ok(ret, "WriteFile error %ld\n", GetLastError());
4513 }
4514
4515 itd32.u1.Function = 0;
4516 SetLastError(0xdeadbeef);
4517 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
4518 ok(ret, "WriteFile error %ld\n", GetLastError());
4519
4520 for (i = 0; i < ARRAY_SIZE(td); i++)
4521 {
4522 if (td[i].func)
4523 itd32.u1.AddressOfData = idd.DllNameRVA + sizeof(test_dll);
4524 else
4525 itd32.u1.Ordinal = td[i].ordinal;
4526 SetLastError(0xdeadbeef);
4527 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
4528 ok(ret, "WriteFile error %ld\n", GetLastError());
4529 }
4530
4531 itd32.u1.Ordinal = 0;
4532 SetLastError(0xdeadbeef);
4533 ret = WriteFile(hfile, &itd32, sizeof(itd32), &dummy, NULL);
4534 ok(ret, "WriteFile error %ld\n", GetLastError());
4535
4536 /* fill up to eof */
4537 SetFilePointer( hfile, section.VirtualAddress + section.Misc.VirtualSize, NULL, SEEK_SET );
4538 SetEndOfFile( hfile );
4539 CloseHandle(hfile);
4540
4541 SetLastError(0xdeadbeef);
4542 hlib = LoadLibraryA(dll_name);
4543 ok(hlib != NULL, "LoadLibrary error %lu\n", GetLastError());
4544 if (!hlib)
4545 {
4546 skip("couldn't load %s.\n", dll_name);
4547 DeleteFileA(dll_name);
4548 return;
4549 }
4550
4551 delaydir = pRtlImageDirectoryEntryToData(hlib, TRUE, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, &file_size);
4552 if (!delaydir)
4553 {
4554 skip("haven't found section for delay import directory.\n");
4555 FreeLibrary(hlib);
4556 DeleteFileA(dll_name);
4557 return;
4558 }
4559
4560 for (;;)
4561 {
4562 IMAGE_THUNK_DATA *itdn, *itda;
4563 HMODULE htarget;
4564
4565 if (!delaydir->DllNameRVA ||
4566 !delaydir->ImportAddressTableRVA ||
4567 !delaydir->ImportNameTableRVA) break;
4568
4569 itdn = RVAToAddr(delaydir->ImportNameTableRVA, hlib);
4570 itda = RVAToAddr(delaydir->ImportAddressTableRVA, hlib);
4571 htarget = LoadLibraryA(RVAToAddr(delaydir->DllNameRVA, hlib));
4572
4573 for (i = 0; i < ARRAY_SIZE(td); i++)
4574 {
4575 void *ret, *load;
4576
4577 /* relocate thunk address by hand since we don't generate reloc records */
4578 itda[i].u1.AddressOfData += (char *)hlib - (char *)nt_header.OptionalHeader.ImageBase;
4579
4580 if (IMAGE_SNAP_BY_ORDINAL(itdn[i].u1.Ordinal))
4581 load = (void *)GetProcAddress(htarget, (LPSTR)IMAGE_ORDINAL(itdn[i].u1.Ordinal));
4582 else
4583 {
4584 const IMAGE_IMPORT_BY_NAME* iibn = RVAToAddr(itdn[i].u1.AddressOfData, hlib);
4585 load = (void *)GetProcAddress(htarget, (char*)iibn->Name);
4586 }
4587
4588 /* test without failure dll callback */
4589 cb_count = cb_count_sys = 0;
4590 ret = pResolveDelayLoadedAPI(hlib, delaydir, NULL, failuresyshook, &itda[i], 0);
4591 if (td[i].succeeds)
4592 {
4593 ok(ret != NULL, "Test %lu: ResolveDelayLoadedAPI failed\n", i);
4594 ok(ret == load, "Test %lu: expected %p, got %p\n", i, load, ret);
4595 ok(ret == (void*)itda[i].u1.AddressOfData, "Test %lu: expected %p, got %p\n",
4596 i, ret, (void*)itda[i].u1.AddressOfData);
4597 ok(!cb_count, "Test %lu: Wrong callback count: %d\n", i, cb_count);
4598 ok(!cb_count_sys, "Test %lu: Wrong sys callback count: %d\n", i, cb_count_sys);
4599 }
4600 else
4601 {
4602 ok(ret == (void*)0x12345678, "Test %lu: ResolveDelayLoadedAPI succeeded with %p\n", i, ret);
4603 ok(!cb_count, "Test %lu: Wrong callback count: %d\n", i, cb_count);
4604 ok(cb_count_sys == 1, "Test %lu: Wrong sys callback count: %d\n", i, cb_count_sys);
4605 }
4606
4607 /* test with failure dll callback */
4608 cb_count = cb_count_sys = 0;
4609 ret = pResolveDelayLoadedAPI(hlib, delaydir, failuredllhook, failuresyshook, &itda[i], 0);
4610 if (td[i].succeeds)
4611 {
4612 ok(ret != NULL, "Test %lu: ResolveDelayLoadedAPI failed\n", i);
4613 ok(ret == load, "Test %lu: expected %p, got %p\n", i, load, ret);
4614 ok(ret == (void*)itda[i].u1.AddressOfData, "Test %lu: expected %p, got %p\n",
4615 i, ret, (void*)itda[i].u1.AddressOfData);
4616 ok(!cb_count, "Test %lu: Wrong callback count: %d\n", i, cb_count);
4617 ok(!cb_count_sys, "Test %lu: Wrong sys callback count: %d\n", i, cb_count_sys);
4618 }
4619 else
4620 {
4621 if (ret == (void*)0x12345678)
4622 {
4623 /* Win10+ sometimes buffers the address of the stub function */
4624 ok(!cb_count, "Test %lu: Wrong callback count: %d\n", i, cb_count);
4625 ok(!cb_count_sys, "Test %lu: Wrong sys callback count: %d\n", i, cb_count_sys);
4626 }
4627 else if (ret == (void*)0xdeadbeef)
4628 {
4629 ok(cb_count == 1, "Test %lu: Wrong callback count: %d\n", i, cb_count);
4630 ok(!cb_count_sys, "Test %lu: Wrong sys callback count: %d\n", i, cb_count_sys);
4631 }
4632 else
4633 ok(0, "Test %lu: ResolveDelayLoadedAPI succeeded with %p\n", i, ret);
4634 }
4635 }
4636 delaydir++;
4637 }
4638
4639 FreeLibrary(hlib);
4640 trace("deleting %s\n", dll_name);
4641 DeleteFileA(dll_name);
4642}
4643
4644static void test_InMemoryOrderModuleList(void)
4645{
4646 PEB_LDR_DATA *ldr = NtCurrentTeb()->Peb->LdrData;
4647 LIST_ENTRY *entry1, *mark1 = &ldr->InLoadOrderModuleList;
4648 LIST_ENTRY *entry2, *mark2 = &ldr->InMemoryOrderModuleList;
4649 LDR_DATA_TABLE_ENTRY *module1, *module2;
4650
4651 ok(ldr->Initialized == TRUE, "expected TRUE, got %u\n", ldr->Initialized);
4652
4653 for (entry1 = mark1->Flink, entry2 = mark2->Flink;
4654 entry1 != mark1 && entry2 != mark2;
4655 entry1 = entry1->Flink, entry2 = entry2->Flink)
4656 {
4657 module1 = CONTAINING_RECORD(entry1, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
4658 module2 = CONTAINING_RECORD(entry2, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
4659 ok(module1 == module2, "expected module1 == module2, got %p and %p\n", module1, module2);
4660 }
4661 ok(entry1 == mark1, "expected entry1 == mark1, got %p and %p\n", entry1, mark1);
4662 ok(entry2 == mark2, "expected entry2 == mark2, got %p and %p\n", entry2, mark2);
4663}
4664
4665static BOOL is_path_made_of(const char *filename, const char *pfx, const char *sfx)
4666{
4667 const size_t len = strlen(pfx);
4668 return !strncasecmp(filename, pfx, len) && filename[len] == '\\' &&
4669 !strcasecmp(filename + len + 1, sfx);
4670}
4671
4672static void test_wow64_redirection_for_dll(const char *libname, BOOL will_fail)
4673{
4674 HMODULE lib;
4675 char buf[256];
4676 const char *modname;
4677
4678 if (!GetModuleHandleA(libname))
4679 {
4680 lib = LoadLibraryExA(libname, NULL, 0);
4681 ok(lib != NULL, "Loading %s should succeed with WOW64 redirection disabled\n", libname);
4682 /* Win 7/2008R2 return the un-redirected path (i.e. c:\windows\system32\dwrite.dll), test loading it. */
4683 GetModuleFileNameA(lib, buf, sizeof(buf));
4684 FreeLibrary(lib);
4685 lib = LoadLibraryExA(buf, NULL, 0);
4686 ok(lib != NULL, "Loading %s from full path should succeed with WOW64 redirection disabled\n", libname);
4687 if (lib)
4688 FreeLibrary(lib);
4689 modname = strrchr(libname, '\\');
4690 modname = modname ? modname + 1 : libname;
4691 todo_wine_if(will_fail)
4692 ok(is_path_made_of(buf, system_dir, modname) ||
4693 /* Win7 report from syswow64 */ broken(is_path_made_of(buf, syswow_dir, modname)),
4694 "Unexpected loaded DLL name %s for %s\n", buf, libname);
4695 }
4696 else
4697 {
4698 skip("%s was already loaded in the process\n", libname);
4699 }
4700}
4701
4702static void test_wow64_redirection(void)
4703{
4704 void *OldValue;
4705 char buffer[MAX_PATH];
4706 static const char *dlls[] = {"wlanapi.dll", "dxgi.dll", "dwrite.dll"};
4707 unsigned i;
4708
4709 if (!is_wow64)
4710 return;
4711
4712 /* Disable FS redirection, then test loading system libraries (pick ones that shouldn't
4713 * already be loaded in this process).
4714 */
4715 ok(pWow64DisableWow64FsRedirection(&OldValue), "Disabling FS redirection failed\n");
4716 for (i = 0; i < ARRAY_SIZE(dlls); i++)
4717 {
4718 test_wow64_redirection_for_dll(dlls[i], FALSE);
4719 /* even absolute paths to syswow64 are loaded with path to system32 */
4720 snprintf(buffer, ARRAY_SIZE(buffer), "%s\\%s", syswow_dir, dlls[i]);
4721 test_wow64_redirection_for_dll(buffer, TRUE);
4722 }
4723
4724 ok(pWow64RevertWow64FsRedirection(OldValue), "Re-enabling FS redirection failed\n");
4725 /* and results don't depend whether redirection is enabled or not */
4726 for (i = 0; i < ARRAY_SIZE(dlls); i++)
4727 {
4728 test_wow64_redirection_for_dll(dlls[i], FALSE);
4729 snprintf(buffer, ARRAY_SIZE(buffer), "%s\\%s", syswow_dir, dlls[i]);
4730 test_wow64_redirection_for_dll(buffer, TRUE);
4731 }
4732}
4733
4734static void test_dll_file( const char *name )
4735{
4736 HMODULE module = GetModuleHandleA( name );
4737 IMAGE_NT_HEADERS *nt, *nt_file;
4738 IMAGE_SECTION_HEADER *sec, *sec_file;
4739 char path[MAX_PATH];
4740 HANDLE file, mapping;
4741 int i = 0;
4742 void *ptr;
4743
4744 GetModuleFileNameA( module, path, MAX_PATH );
4745 file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
4746 ok( file != INVALID_HANDLE_VALUE, "can't open '%s': %lu\n", path, GetLastError() );
4747
4748 mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 0, NULL );
4749 ok( mapping != NULL, "%s: CreateFileMappingW failed err %lu\n", name, GetLastError() );
4750 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
4751 ok( ptr != NULL, "%s: MapViewOfFile failed err %lu\n", name, GetLastError() );
4752 CloseHandle( mapping );
4753 CloseHandle( file );
4754
4755 nt = pRtlImageNtHeader( module );
4756 nt_file = pRtlImageNtHeader( ptr );
4757 ok( nt_file != NULL, "%s: invalid header\n", path );
4758#define OK_FIELD(x, f) ok( nt->x == nt_file->x, "%s:%u: wrong " #x " " f " / " f "\n", name, i, nt->x, nt_file->x )
4759 OK_FIELD( FileHeader.NumberOfSections, "%x" );
4760 OK_FIELD( OptionalHeader.AddressOfEntryPoint, "%lx" );
4761 OK_FIELD( OptionalHeader.NumberOfRvaAndSizes, "%lx" );
4762 for (i = 0; i < nt->OptionalHeader.NumberOfRvaAndSizes; i++)
4763 {
4764 OK_FIELD( OptionalHeader.DataDirectory[i].VirtualAddress, "%lx" );
4765 OK_FIELD( OptionalHeader.DataDirectory[i].Size, "%lx" );
4766 }
4767 sec = IMAGE_FIRST_SECTION( nt );
4768 sec_file = IMAGE_FIRST_SECTION( nt_file );
4769 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
4770 ok( !memcmp( sec + i, sec_file + i, sizeof(*sec) ), "%s: wrong section %d\n", name, i );
4771 UnmapViewOfFile( ptr );
4772#undef OK_FIELD
4773}
4774
4775static void test_LoadPackagedLibrary(void)
4776{
4777 HMODULE h;
4778
4779 if (!pLoadPackagedLibrary)
4780 {
4781 win_skip("LoadPackagedLibrary is not available.\n");
4782 return;
4783 }
4784
4785 SetLastError( 0xdeadbeef );
4786 h = pLoadPackagedLibrary(L"kernel32.dll", 0);
4787 ok(!h && GetLastError() == APPMODEL_ERROR_NO_PACKAGE, "Got unexpected handle %p, GetLastError() %lu.\n",
4788 h, GetLastError());
4789}
4790
4791static void test_Wow64Transition(void)
4792{
4793 char buffer[400];
4794 MEMORY_SECTION_NAME *name = (MEMORY_SECTION_NAME *)buffer;
4795 const WCHAR *filepart;
4796 void **pWow64Transition;
4797 NTSTATUS status;
4798
4799 if (!(pWow64Transition = (void *)GetProcAddress(GetModuleHandleA("ntdll"), "Wow64Transition")))
4800 {
4801 skip("Wow64Transition is not present\n");
4802 return;
4803 }
4804 if (!is_wow64)
4805 {
4806 skip("Wow64Transition is not patched\n");
4807 return;
4808 }
4809
4810 status = NtQueryVirtualMemory(GetCurrentProcess(), *pWow64Transition,
4811 MemoryMappedFilenameInformation, name, sizeof(buffer), NULL);
4812 ok(!status, "got %#lx\n", status);
4813 filepart = name->SectionFileName.Buffer + name->SectionFileName.Length / sizeof(WCHAR);
4814 while (*filepart != '\\') --filepart;
4815 ok(!wcsnicmp(filepart, L"\\wow64cpu.dll", wcslen(L"\\wow64cpu.dll")), "got file name %s\n",
4816 debugstr_wn(name->SectionFileName.Buffer, name->SectionFileName.Length / sizeof(WCHAR)));
4817}
4818
4819START_TEST(loader)
4820{
4821 int argc;
4822 char **argv;
4823 HANDLE ntdll, mapping, kernel32;
4824 SYSTEM_INFO si;
4825 DWORD len;
4826
4827 ntdll = GetModuleHandleA("ntdll.dll");
4828 kernel32 = GetModuleHandleA("kernel32.dll");
4829 pNtCreateSection = (void *)GetProcAddress(ntdll, "NtCreateSection");
4830 pNtQuerySection = (void *)GetProcAddress(ntdll, "NtQuerySection");
4831 pNtMapViewOfSection = (void *)GetProcAddress(ntdll, "NtMapViewOfSection");
4832 pNtUnmapViewOfSection = (void *)GetProcAddress(ntdll, "NtUnmapViewOfSection");
4833 pNtTerminateProcess = (void *)GetProcAddress(ntdll, "NtTerminateProcess");
4834 pNtQueryInformationProcess = (void *)GetProcAddress(ntdll, "NtQueryInformationProcess");
4835 pNtSetInformationProcess = (void *)GetProcAddress(ntdll, "NtSetInformationProcess");
4836 pLdrShutdownProcess = (void *)GetProcAddress(ntdll, "LdrShutdownProcess");
4837 pRtlDllShutdownInProgress = (void *)GetProcAddress(ntdll, "RtlDllShutdownInProgress");
4838 pNtAllocateVirtualMemory = (void *)GetProcAddress(ntdll, "NtAllocateVirtualMemory");
4839 pNtFreeVirtualMemory = (void *)GetProcAddress(ntdll, "NtFreeVirtualMemory");
4840 pLdrLockLoaderLock = (void *)GetProcAddress(ntdll, "LdrLockLoaderLock");
4841 pLdrUnlockLoaderLock = (void *)GetProcAddress(ntdll, "LdrUnlockLoaderLock");
4842 pLdrLoadDll = (void *)GetProcAddress(ntdll, "LdrLoadDll");
4843 pLdrUnloadDll = (void *)GetProcAddress(ntdll, "LdrUnloadDll");
4844 pRtlInitUnicodeString = (void *)GetProcAddress(ntdll, "RtlInitUnicodeString");
4845 pRtlAcquirePebLock = (void *)GetProcAddress(ntdll, "RtlAcquirePebLock");
4846 pRtlReleasePebLock = (void *)GetProcAddress(ntdll, "RtlReleasePebLock");
4847 pRtlImageDirectoryEntryToData = (void *)GetProcAddress(ntdll, "RtlImageDirectoryEntryToData");
4848 pRtlImageNtHeader = (void *)GetProcAddress(ntdll, "RtlImageNtHeader");
4849 pLdrRegisterDllNotification = (void *)GetProcAddress(ntdll, "LdrRegisterDllNotification");
4850 pFlsAlloc = (void *)GetProcAddress(kernel32, "FlsAlloc");
4851 pFlsSetValue = (void *)GetProcAddress(kernel32, "FlsSetValue");
4852 pFlsGetValue = (void *)GetProcAddress(kernel32, "FlsGetValue");
4853 pFlsFree = (void *)GetProcAddress(kernel32, "FlsFree");
4854 pIsWow64Process = (void *)GetProcAddress(kernel32, "IsWow64Process");
4855 pWow64DisableWow64FsRedirection = (void *)GetProcAddress(kernel32, "Wow64DisableWow64FsRedirection");
4856 pWow64RevertWow64FsRedirection = (void *)GetProcAddress(kernel32, "Wow64RevertWow64FsRedirection");
4857 pResolveDelayLoadedAPI = (void *)GetProcAddress(kernel32, "ResolveDelayLoadedAPI");
4858 pLoadPackagedLibrary = (void *)GetProcAddress(kernel32, "LoadPackagedLibrary");
4859
4860 if (pIsWow64Process) pIsWow64Process( GetCurrentProcess(), &is_wow64 );
4861 GetSystemInfo( &si );
4862 page_size = si.dwPageSize;
4863 dos_header.e_magic = IMAGE_DOS_SIGNATURE;
4864 dos_header.e_lfanew = sizeof(dos_header);
4865
4866 mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_loader");
4867 ok(mapping != 0, "CreateFileMapping failed\n");
4868 child_failures = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 4096);
4869 if (*child_failures == -1)
4870 {
4871 *child_failures = 0;
4872 }
4873 else
4874 *child_failures = -1;
4875
4876 argc = winetest_get_mainargs(&argv);
4877 if (argc > 4)
4878 {
4879 test_dll_phase = atoi(argv[4]);
4880 child_process(argv[2], atol(argv[3]));
4881 return;
4882 }
4883
4884 len = GetSystemDirectoryA(system_dir, ARRAY_SIZE(system_dir));
4885 ok(len && len < ARRAY_SIZE(system_dir), "Couldn't get system directory: %lu\n", GetLastError());
4886 if (is_wow64)
4887 {
4888 len = GetSystemWow64DirectoryA(syswow_dir, ARRAY_SIZE(syswow_dir));
4889 ok(len && len < ARRAY_SIZE(syswow_dir), "Couldn't get wow directory: %lu\n", GetLastError());
4890 }
4891
4892 test_filenames();
4893 test_ResolveDelayLoadedAPI();
4894 test_ImportDescriptors();
4895 test_section_access();
4896 test_import_resolution();
4897 test_export_forwarder_dep_chain();
4898 test_ExitProcess();
4899 test_InMemoryOrderModuleList();
4900 test_LoadPackagedLibrary();
4901 test_wow64_redirection();
4902 test_dll_file( "ntdll.dll" );
4903 test_dll_file( "kernel32.dll" );
4904 test_dll_file( "advapi32.dll" );
4905 test_dll_file( "user32.dll" );
4906 test_Wow64Transition();
4907 /* loader test must be last, it can corrupt the internal loader state on Windows */
4908 test_Loader();
4909}