From 417b739dbe09a63c5ac40f9632a9e7a349134ac7 Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Fri, 9 Dec 2011 10:33:09 +0000 Subject: [PATCH] [ACTCTX] - Improve and rewrite a few active context support functions in RTL, making them more close to their real functionality and throwing away wineisms. - Uncomment a line in RtlAllocateActivationContextStack() which was causing it to always allocate a new activation context stack even if there was one. Thanks to my previous commit in kernel32 counterpart, this hack is not needed anymore and memory won't be wasted. - Since we have mostly Wine's code in our activation context implementation, it makes sense to use it properly until it's rewritten, so first of all: - Properly initialize current process's activation context support by calling actctx_init() from LdrpInitializeProcess instead of calling it all the time when a new context is created. - Bring in create_module_activation_context and find_actctx_dll (newer version from Wine which supports manifests/assmeblies in local directories) and use it. Every place where it's used is marked as a HACK so it will be easy to detach it later. - Remove actctx-related hack LdrpInitializeThread, now it works properly. - Fix a typo in LdrpMapDll found by rafalh. Now the error-detection condition will be correctly evaluated. See issue #6611 for more details. svn path=/trunk/; revision=54623 --- reactos/dll/ntdll/ldr/ldrinit.c | 18 ++-- reactos/dll/ntdll/ldr/ldrutils.c | 153 +++++++++++++++++++++++++++++-- reactos/lib/rtl/actctx.c | 60 +++++++++--- 3 files changed, 198 insertions(+), 33 deletions(-) diff --git a/reactos/dll/ntdll/ldr/ldrinit.c b/reactos/dll/ntdll/ldr/ldrinit.c index def676250a2..bd7084d8a65 100644 --- a/reactos/dll/ntdll/ldr/ldrinit.c +++ b/reactos/dll/ntdll/ldr/ldrinit.c @@ -87,6 +87,7 @@ ULONG RtlpDisableHeapLookaside; // TODO: Move to heap.c ULONG RtlpShutdownProcessFlags; // TODO: Use it NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase); +void actctx_init(void); #ifdef _WIN64 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll @@ -504,19 +505,11 @@ LdrpInitializeThread(IN PCONTEXT Context) NtCurrentTeb()->RealClientId.UniqueThread); /* Allocate an Activation Context Stack */ - /* FIXME: This is a hack for Wine's actctx stuff */ DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer); - if (!(NtCurrentTeb()->ActivationContextStackPointer)) + Status = RtlAllocateActivationContextStack((PVOID*)&NtCurrentTeb()->ActivationContextStackPointer); + if (!NT_SUCCESS(Status)) { - Status = RtlAllocateActivationContextStack((PVOID*)&NtCurrentTeb()->ActivationContextStackPointer); - if (NT_SUCCESS(Status)) - { - DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer); - DPRINT("ActiveFrame %p\n", ((PACTIVATION_CONTEXT_STACK)NtCurrentTeb()->ActivationContextStackPointer)->ActiveFrame); - NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = NULL; - } - else - DPRINT1("Warning: Unable to allocate ActivationContextStack\n"); + DPRINT1("Warning: Unable to allocate ActivationContextStack\n"); } /* Make sure we are not shutting down */ @@ -1946,6 +1939,9 @@ LdrpInitializeProcess(IN PCONTEXT Context, InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList, &LdrpNtDllDataTableEntry->InInitializationOrderModuleList); + /* Initialize Wine's active context implementation for the current process */ + actctx_init(); + /* Set the current directory */ Status = RtlSetCurrentDirectory_U(&CurrentDirectory); if (!NT_SUCCESS(Status)) diff --git a/reactos/dll/ntdll/ldr/ldrutils.c b/reactos/dll/ntdll/ldr/ldrutils.c index 5532b45228f..d67f5ba2820 100644 --- a/reactos/dll/ntdll/ldr/ldrutils.c +++ b/reactos/dll/ntdll/ldr/ldrutils.c @@ -20,6 +20,122 @@ BOOLEAN g_ShimsEnabled; /* FUNCTIONS *****************************************************************/ +/* NOTE: Remove those two once our actctx support becomes better */ +NTSTATUS create_module_activation_context( LDR_DATA_TABLE_ENTRY *module ) +{ + NTSTATUS status; + LDR_RESOURCE_INFO info; + IMAGE_RESOURCE_DATA_ENTRY *entry; + + info.Type = (ULONG)RT_MANIFEST; + info.Name = (ULONG)ISOLATIONAWARE_MANIFEST_RESOURCE_ID; + info.Language = 0; + if (!(status = LdrFindResource_U( module->DllBase, &info, 3, &entry ))) + { + ACTCTXW ctx; + ctx.cbSize = sizeof(ctx); + ctx.lpSource = NULL; + ctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID; + ctx.hModule = module->DllBase; + ctx.lpResourceName = (LPCWSTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID; + status = RtlCreateActivationContext( &module->EntryPointActivationContext, &ctx ); + } + return status; +} + +NTSTATUS find_actctx_dll( LPCWSTR libname, WCHAR *fullname ) +{ + static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\',0}; + static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0}; + + ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info; + ACTCTX_SECTION_KEYED_DATA data; + UNICODE_STRING nameW; + NTSTATUS status; + SIZE_T needed, size = 1024; + WCHAR *p; + + RtlInitUnicodeString( &nameW, libname ); + data.cbSize = sizeof(data); + status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL, + ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, + &nameW, &data ); + if (status != STATUS_SUCCESS) return status; + + for (;;) + { + if (!(info = RtlAllocateHeap( RtlGetProcessHeap(), 0, size ))) + { + status = STATUS_NO_MEMORY; + goto done; + } + status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex, + AssemblyDetailedInformationInActivationContext, + info, size, &needed ); + if (status == STATUS_SUCCESS) break; + if (status != STATUS_BUFFER_TOO_SMALL) goto done; + RtlFreeHeap( RtlGetProcessHeap(), 0, info ); + size = needed; + } + + DPRINT("manifestpath === %S\n", info->lpAssemblyManifestPath); + DPRINT("DirectoryName === %S\n", info->lpAssemblyDirectoryName); + if (!info->lpAssemblyManifestPath || !info->lpAssemblyDirectoryName) + { + status = STATUS_SXS_KEY_NOT_FOUND; + goto done; + } + + if ((p = wcsrchr( info->lpAssemblyManifestPath, '\\' ))) + { + DWORD dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR); + + p++; + if (_wcsnicmp( p, info->lpAssemblyDirectoryName, dirlen ) || wcsicmp( p + dirlen, dotManifestW )) + { + /* manifest name does not match directory name, so it's not a global + * windows/winsxs manifest; use the manifest directory name instead */ + dirlen = p - info->lpAssemblyManifestPath; + needed = (dirlen + 1) * sizeof(WCHAR) + nameW.Length; + + p = fullname; + /*if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed ))) + { + status = STATUS_NO_MEMORY; + goto done; + }*/ + memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) ); + p += dirlen; + wcscpy( p, libname ); + goto done; + } + } + + needed = (wcslen(SharedUserData->NtSystemRoot) * sizeof(WCHAR) + + sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + nameW.Length + 2*sizeof(WCHAR)); + + //if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed ))) + //{ + //status = STATUS_NO_MEMORY; + //goto done; + //} + wcscpy( p, SharedUserData->NtSystemRoot ); + p += wcslen(p); + memcpy( p, winsxsW, sizeof(winsxsW) ); + p += sizeof(winsxsW) / sizeof(WCHAR); + memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength ); + p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR); + *p++ = '\\'; + wcscpy( p, libname ); + +done: + RtlFreeHeap( RtlGetProcessHeap(), 0, info ); + RtlReleaseActivationContext( data.hActCtx ); + DPRINT("%S\n", fullname); + return status; +} + + NTSTATUS NTAPI LdrpAllocateUnicodeString(IN OUT PUNICODE_STRING StringOut, @@ -559,6 +675,7 @@ LdrpResolveDllName(PWSTR DllPath, PWCHAR NameBuffer, p1, p2 = 0; ULONG Length; ULONG BufSize = 500; + NTSTATUS Status; /* Allocate space for full DLL name */ FullDllName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufSize + sizeof(UNICODE_NULL)); @@ -573,14 +690,25 @@ LdrpResolveDllName(PWSTR DllPath, if (!Length || Length > BufSize) { - if (ShowSnaps) + /* HACK: Try to find active context dll */ + Status = find_actctx_dll(DllName, FullDllName->Buffer); + if(Status == STATUS_SUCCESS) { - DPRINT1("LDR: LdrResolveDllName - Unable to find "); - DPRINT1("%ws from %ws\n", DllName, DllPath ? DllPath : LdrpDefaultPath.Buffer); + Length = wcslen(FullDllName->Buffer) * sizeof(WCHAR); + DPRINT1("found %S for %S\n", FullDllName->Buffer, DllName); } + else + { + /* NOTE: This code should remain after removing the hack */ + if (ShowSnaps) + { + DPRINT1("LDR: LdrResolveDllName - Unable to find "); + DPRINT1("%ws from %ws\n", DllName, DllPath ? DllPath : LdrpDefaultPath.Buffer); + } - RtlFreeUnicodeString(FullDllName); - return FALSE; + RtlFreeUnicodeString(FullDllName); + return FALSE; + } } /* Construct full DLL name */ @@ -1269,7 +1397,7 @@ SkipCheck: } /* Check if this was a non-relocatable DLL or a known dll */ - if (!RelocatableDll && KnownDll) + if (!RelocatableDll || KnownDll) { /* Setup for hard error */ HardErrorParameters[0] = (ULONG_PTR)&IllegalDll; @@ -1847,7 +1975,7 @@ LdrpCheckForLoadedDll(IN PWSTR DllPath, PVOID ViewBase = NULL; SIZE_T ViewSize = 0; PIMAGE_NT_HEADERS NtHeader, NtHeader2; - DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %d %d %p)\n", DllPath, DllName, Flag, RedirectedDll, LdrEntry); + DPRINT("LdrpCheckForLoadedDll('%S' '%wZ' %d %d %p)\n", DllPath ? ((ULONG_PTR)DllPath == 1 ? L"" : DllPath) : L"", DllName, Flag, RedirectedDll, LdrEntry); /* Check if a dll name was provided */ if (!(DllName->Buffer) || !(DllName->Buffer[0])) return FALSE; @@ -1910,6 +2038,16 @@ lookinhash: /* Check if that was successful */ if (!(Length) || (Length > (sizeof(NameBuf) - sizeof(UNICODE_NULL)))) { + /* HACK: Try to find active context dll */ + Status = find_actctx_dll(DllName->Buffer, FullDllName.Buffer); + if(Status == STATUS_SUCCESS) + { + Length = wcslen(FullDllName.Buffer) * sizeof(WCHAR); + DPRINT1("found %S for %S\n", FullDllName.Buffer, DllName->Buffer); + } + else + { + if (ShowSnaps) { DPRINT1("LDR: LdrpCheckForLoadedDll - Unable To Locate %ws: 0x%08x\n", @@ -1918,6 +2056,7 @@ lookinhash: /* Return failure */ return FALSE; + } } /* Full dll name is found */ diff --git a/reactos/lib/rtl/actctx.c b/reactos/lib/rtl/actctx.c index b6f1aeb84b8..297f035e2eb 100644 --- a/reactos/lib/rtl/actctx.c +++ b/reactos/lib/rtl/actctx.c @@ -1659,6 +1659,9 @@ static NTSTATUS get_manifest_in_module( struct actctx_loader* acl, struct assemb IMAGE_RESOURCE_DATA_ENTRY* entry = NULL; void *ptr; + //DPRINT( "looking for res %s in module %p %s\n", resname, + // hModule, filename ); + #if 0 if (TRACE_ON(actctx)) { @@ -2427,20 +2430,42 @@ RtlDeactivateActivationContext( ULONG flags, ULONG_PTR cookie ) return STATUS_SUCCESS; } +VOID +NTAPI +RtlFreeActivationContextStack(PACTIVATION_CONTEXT_STACK Stack) +{ + PRTL_ACTIVATION_CONTEXT_STACK_FRAME ActiveFrame, PrevFrame; + + /* Nothing to do if there is no stack */ + if (!Stack) return; + + /* Get the current active frame */ + ActiveFrame = Stack->ActiveFrame; + + /* Go through them in backwards order and release */ + while (ActiveFrame) + { + PrevFrame = ActiveFrame->Previous; + RtlReleaseActivationContext(ActiveFrame->ActivationContext); + RtlFreeHeap(RtlGetProcessHeap(), 0, ActiveFrame); + ActiveFrame = PrevFrame; + } + + /* Zero out the active frame */ + Stack->ActiveFrame = NULL; + + /* TODO: Empty the Frame List Cache */ + ASSERT(IsListEmpty(&Stack->FrameListCache)); + + /* Free activation stack memory */ + RtlFreeHeap(RtlGetProcessHeap(), 0, Stack); +} + VOID NTAPI RtlFreeThreadActivationContextStack(void) { - RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame; - - frame = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame; - while (frame) - { - RTL_ACTIVATION_CONTEXT_STACK_FRAME *prev = frame->Previous; - RtlReleaseActivationContext( frame->ActivationContext ); - RtlFreeHeap( RtlGetProcessHeap(), 0, frame ); - frame = prev; - } - NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = NULL; + RtlFreeActivationContextStack(NtCurrentTeb()->ActivationContextStackPointer); + NtCurrentTeb()->ActivationContextStackPointer = NULL; } @@ -2757,17 +2782,22 @@ RtlAllocateActivationContextStack(IN PVOID *Context) { PACTIVATION_CONTEXT_STACK ContextStack; - /* FIXME: Check if it's already allocated */ - //if (*Context) return STATUS_SUCCESS; + /* Check if it's already allocated */ + if (*Context) return STATUS_SUCCESS; + /* Allocate space for the context stack */ ContextStack = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof (ACTIVATION_CONTEXT_STACK) ); if (!ContextStack) { return STATUS_NO_MEMORY; } - ContextStack->ActiveFrame = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME)); - if (!ContextStack->ActiveFrame) return STATUS_NO_MEMORY; + /* Initialize the context stack */ + ContextStack->Flags = 0; + ContextStack->ActiveFrame = NULL; + InitializeListHead(&ContextStack->FrameListCache); + ContextStack->NextCookieSequenceNumber = 1; + ContextStack->StackId = 1; //TODO: Timer-based *Context = ContextStack;