[PATCH 3/5] ntdll: Store module dependencies in DDAG structure.

Paul Gofman pgofman at codeweavers.com
Tue Nov 2 05:26:42 CDT 2021


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 dlls/kernel32/tests/module.c |  12 +--
 dlls/ntdll/loader.c          | 201 +++++++++++++++++++++++++----------
 include/winternl.h           |   4 +-
 3 files changed, 152 insertions(+), 65 deletions(-)

diff --git a/dlls/kernel32/tests/module.c b/dlls/kernel32/tests/module.c
index 7c4b690fb39..466ff3e8d38 100644
--- a/dlls/kernel32/tests/module.c
+++ b/dlls/kernel32/tests/module.c
@@ -1376,14 +1376,14 @@ static void test_ddag_node(void)
     ok( !node->IncomingDependencies.Tail, "Expected empty incoming dependencies list.\n" );
 
     /* node->Dependencies.Tail is NULL on Windows 10 1507-1607 32 bit test, maybe due to broken structure layout. */
-    todo_wine ok( !!node->Dependencies.Tail || broken( sizeof(void *) == 4 && !node->Dependencies.Tail ),
+    ok( !!node->Dependencies.Tail || broken( sizeof(void *) == 4 && !node->Dependencies.Tail ),
             "Expected nonempty dependencies list.\n" );
     if (!node->Dependencies.Tail)
     {
-        skip( "Empty dependencies list.\n" );
+        win_skip( "Empty dependencies list.\n" );
         return;
     }
-    ok( node->LoadCount == -1, "Got unexpected LoadCount %d.\n", node->LoadCount );
+    todo_wine ok( node->LoadCount == -1, "Got unexpected LoadCount %d.\n", node->LoadCount );
 
     prev_node = NULL;
     se = node->Dependencies.Tail;
@@ -1409,7 +1409,7 @@ static void test_ddag_node(void)
         }
 
         mod2 = CONTAINING_RECORD(dep_node->Modules.Flink, LDR_DATA_TABLE_ENTRY, NodeModuleLink);
-        ok( !lstrcmpW( mod2->BaseDllName.Buffer, expected_exe_dependencies[i].dllname ),
+        todo_wine ok( !lstrcmpW( mod2->BaseDllName.Buffer, expected_exe_dependencies[i].dllname ),
                 "Got unexpected module %s.\n", debugstr_w(mod2->BaseDllName.Buffer));
 
         se2 = dep_node->IncomingDependencies.Tail;
@@ -1422,13 +1422,13 @@ static void test_ddag_node(void)
         while (dep2 != dep && se2 != dep_node->IncomingDependencies.Tail);
         ok( dep2 == dep, "Dependency not found in incoming deps list.\n" );
 
-        ok( dep_node->LoadCount > 0 || broken(!dep_node->LoadCount) /* Win8 */,
+        todo_wine ok( dep_node->LoadCount > 0 || broken(!dep_node->LoadCount) /* Win8 */,
                 "Got unexpected LoadCount %d.\n", dep_node->LoadCount );
 
         winetest_pop_context();
         prev_node = dep_node;
     }
-    ok( se == node->Dependencies.Tail, "Expected end of the list.\n" );
+    todo_wine ok( se == node->Dependencies.Tail, "Expected end of the list.\n" );
 }
 
 START_TEST(module)
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 23f5a982798..3b5d1de0f3e 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -133,9 +133,6 @@ typedef struct _wine_modref
 {
     LDR_DATA_TABLE_ENTRY  ldr;
     struct file_id        id;
-    int                   alloc_deps;
-    int                   nDeps;
-    struct _wine_modref **deps;
     ULONG                 CheckSum;
 } WINE_MODREF;
 
@@ -588,26 +585,112 @@ static WINE_MODREF *find_fileid_module( const struct file_id *id )
     return NULL;
 }
 
+/**********************************************************************
+ *	    insert_single_list_tail
+ */
+static void insert_single_list_after( LDRP_CSLIST *list, SINGLE_LIST_ENTRY *prev, SINGLE_LIST_ENTRY *entry )
+{
+    if (!list->Tail)
+    {
+        assert( !prev );
+        entry->Next = entry;
+        list->Tail = entry;
+        return;
+    }
+    if (!prev)
+    {
+        /* Insert at head. */
+        entry->Next = list->Tail->Next;
+        list->Tail->Next = entry;
+        return;
+    }
+    entry->Next = prev->Next;
+    prev->Next = entry;
+    if (prev == list->Tail) list->Tail = entry;
+}
 
-/*************************************************************************
- *		grow_module_deps
+/**********************************************************************
+ *	    remove_single_list_entry
  */
-static WINE_MODREF **grow_module_deps( WINE_MODREF *wm, int count )
+static void remove_single_list_entry( LDRP_CSLIST *list, SINGLE_LIST_ENTRY *entry )
 {
-    WINE_MODREF **deps;
+    SINGLE_LIST_ENTRY *prev;
 
-    if (wm->alloc_deps)
-        deps = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, wm->deps,
-                                  (wm->alloc_deps + count) * sizeof(*deps) );
-    else
-        deps = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(*deps) );
+    assert( list->Tail );
 
-    if (deps)
+    if (entry->Next == entry)
     {
-        wm->deps = deps;
-        wm->alloc_deps += count;
+        assert( list->Tail == entry );
+        list->Tail = NULL;
+        return;
     }
-    return deps;
+
+    prev = list->Tail->Next;
+    while (prev->Next != entry && prev != list->Tail)
+        prev = prev->Next;
+    assert( prev->Next == entry );
+    prev->Next = entry->Next;
+    if (list->Tail == entry) list->Tail = prev;
+    entry->Next = NULL;
+}
+
+/**********************************************************************
+ *	    add_module_dependency_after
+ */
+static BOOL add_module_dependency_after( LDR_DDAG_NODE *from, LDR_DDAG_NODE *to,
+                                         SINGLE_LIST_ENTRY *dep_after )
+{
+    LDR_DEPENDENCY *dep;
+
+    if (!(dep = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*dep) ))) return FALSE;
+
+    dep->dependency_from = from;
+    insert_single_list_after( &from->Dependencies, dep_after, &dep->dependency_to_entry );
+    dep->dependency_to = to;
+    insert_single_list_after( &to->IncomingDependencies, NULL, &dep->dependency_from_entry );
+
+    return TRUE;
+}
+
+/**********************************************************************
+ *	    add_module_dependency
+ */
+static BOOL add_module_dependency( LDR_DDAG_NODE *from, LDR_DDAG_NODE *to )
+{
+    return add_module_dependency_after( from, to, from->Dependencies.Tail );
+}
+
+/**********************************************************************
+ *	    remove_module_dependency
+ */
+static void remove_module_dependency( LDR_DEPENDENCY *dep )
+{
+    remove_single_list_entry( &dep->dependency_to->IncomingDependencies, &dep->dependency_from_entry );
+    remove_single_list_entry( &dep->dependency_from->Dependencies, &dep->dependency_to_entry );
+    RtlFreeHeap( GetProcessHeap(), 0, dep );
+}
+
+/**********************************************************************
+ *	    walk_node_dependencies
+ */
+static NTSTATUS walk_node_dependencies( LDR_DDAG_NODE *node, void *context,
+                                        NTSTATUS (*callback)( LDR_DDAG_NODE *, void * ))
+{
+    SINGLE_LIST_ENTRY *entry;
+    LDR_DEPENDENCY *dep;
+    NTSTATUS status;
+
+    if (!(entry = node->Dependencies.Tail)) return STATUS_SUCCESS;
+
+    do
+    {
+        entry = entry->Next;
+        dep = CONTAINING_RECORD( entry, LDR_DEPENDENCY, dependency_to_entry );
+        assert( dep->dependency_from == node );
+        if ((status = callback( dep->dependency_to, context ))) break;
+    } while (entry != node->Dependencies.Tail);
+
+    return status;
 }
 
 /*************************************************************************
@@ -645,8 +728,7 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS
         {
             if (!imports_fixup_done && current_modref)
             {
-                WINE_MODREF **deps = grow_module_deps( current_modref, 1 );
-                if (deps) deps[current_modref->nDeps++] = wm;
+                add_module_dependency( current_modref->ldr.DdagNode, wm->ldr.DdagNode );
             }
             else if (process_attach( wm->ldr.DdagNode, NULL ) != STATUS_SUCCESS)
             {
@@ -1125,12 +1207,12 @@ static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void *
     if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS;  /* already done */
     wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
 
-    if (!grow_module_deps( wm, 1 )) return STATUS_NO_MEMORY;
-    wm->nDeps = 1;
-
     prev = current_modref;
     current_modref = wm;
-    if (!(status = load_dll( load_path, L"mscoree.dll", NULL, 0, &imp ))) wm->deps[0] = imp;
+    assert( !wm->ldr.DdagNode->Dependencies.Tail );
+    if (!(status = load_dll( load_path, L"mscoree.dll", NULL, 0, &imp ))
+          && !add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, NULL ))
+        status = STATUS_NO_MEMORY;
     current_modref = prev;
     if (status)
     {
@@ -1156,9 +1238,10 @@ static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void *
  */
 static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
 {
-    int i, dep, nb_imports;
     const IMAGE_IMPORT_DESCRIPTOR *imports;
+    SINGLE_LIST_ENTRY *dep_after;
     WINE_MODREF *prev, *imp;
+    int i, nb_imports;
     DWORD size;
     NTSTATUS status;
     ULONG_PTR cookie;
@@ -1176,7 +1259,6 @@ static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
     while (imports[nb_imports].Name && imports[nb_imports].FirstThunk) nb_imports++;
 
     if (!nb_imports) return STATUS_SUCCESS;  /* no imports */
-    if (!grow_module_deps( wm, nb_imports )) return STATUS_NO_MEMORY;
 
     if (!create_module_activation_context( &wm->ldr ))
         RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
@@ -1189,14 +1271,13 @@ static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
     status = STATUS_SUCCESS;
     for (i = 0; i < nb_imports; i++)
     {
-        dep = wm->nDeps++;
-
+        dep_after = wm->ldr.DdagNode->Dependencies.Tail;
         if (!import_dll( wm->ldr.DllBase, &imports[i], load_path, &imp ))
         {
             imp = NULL;
             status = STATUS_DLL_NOT_FOUND;
         }
-        wm->deps[dep] = imp;
+        else add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, dep_after );
     }
     current_modref = prev;
     if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
@@ -1443,7 +1524,6 @@ static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved )
     LDR_DATA_TABLE_ENTRY *mod;
     ULONG_PTR cookie;
     WINE_MODREF *wm;
-    int i;
 
     if (process_detaching) return status;
 
@@ -1463,11 +1543,7 @@ static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved )
     if (wm->ldr.ActivationContext) RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
 
     /* Recursively attach all DLLs this one depends on */
-    for ( i = 0; i < wm->nDeps; i++ )
-    {
-        if (!wm->deps[i]) continue;
-        if ((status = process_attach( wm->deps[i]->ldr.DdagNode, lpReserved )) != STATUS_SUCCESS) break;
-    }
+    walk_node_dependencies( node, lpReserved, process_attach );
 
     if (!wm->ldr.InInitializationOrderLinks.Flink)
         InsertTailList(&NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList,
@@ -3527,11 +3603,28 @@ void WINAPI LdrShutdownThread(void)
  */
 static void free_modref( WINE_MODREF *wm )
 {
+    SINGLE_LIST_ENTRY *entry;
+    LDR_DEPENDENCY *dep;
+
     RemoveEntryList(&wm->ldr.InLoadOrderLinks);
     RemoveEntryList(&wm->ldr.InMemoryOrderLinks);
     if (wm->ldr.InInitializationOrderLinks.Flink)
         RemoveEntryList(&wm->ldr.InInitializationOrderLinks);
 
+    while ((entry = wm->ldr.DdagNode->Dependencies.Tail))
+    {
+        dep = CONTAINING_RECORD( entry, LDR_DEPENDENCY, dependency_to_entry );
+        assert( dep->dependency_from == wm->ldr.DdagNode );
+        remove_module_dependency( dep );
+    }
+
+    while ((entry = wm->ldr.DdagNode->IncomingDependencies.Tail))
+    {
+        dep = CONTAINING_RECORD( entry, LDR_DEPENDENCY, dependency_from_entry );
+        assert( dep->dependency_to == wm->ldr.DdagNode );
+        remove_module_dependency( dep );
+    }
+
     RemoveEntryList(&wm->ldr.NodeModuleLink);
     if (IsListEmpty(&wm->ldr.DdagNode->Modules))
         RtlFreeHeap( GetProcessHeap(), 0, wm->ldr.DdagNode );
@@ -3547,7 +3640,6 @@ static void free_modref( WINE_MODREF *wm )
     NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.DllBase );
     if (cached_modref == wm) cached_modref = NULL;
     RtlFreeUnicodeString( &wm->ldr.FullDllName );
-    RtlFreeHeap( GetProcessHeap(), 0, wm->deps );
     RtlFreeHeap( GetProcessHeap(), 0, wm );
 }
 
@@ -3590,15 +3682,19 @@ static void MODULE_FlushModrefs(void)
  *
  * The loader_section must be locked while calling this function.
  */
-static void MODULE_DecRefCount( WINE_MODREF *wm )
+static NTSTATUS MODULE_DecRefCount( LDR_DDAG_NODE *node, void *context )
 {
-    int i;
+    LDR_DATA_TABLE_ENTRY *mod;
+    WINE_MODREF *wm;
+
+    mod = CONTAINING_RECORD( node->Modules.Flink, LDR_DATA_TABLE_ENTRY, NodeModuleLink );
+    wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
 
     if ( wm->ldr.Flags & LDR_UNLOAD_IN_PROGRESS )
-        return;
+        return STATUS_SUCCESS;
 
     if ( wm->ldr.LoadCount <= 0 )
-        return;
+        return STATUS_SUCCESS;
 
     --wm->ldr.LoadCount;
     TRACE("(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
@@ -3606,15 +3702,11 @@ static void MODULE_DecRefCount( WINE_MODREF *wm )
     if ( wm->ldr.LoadCount == 0 )
     {
         wm->ldr.Flags |= LDR_UNLOAD_IN_PROGRESS;
-
-        for ( i = 0; i < wm->nDeps; i++ )
-            if ( wm->deps[i] )
-                MODULE_DecRefCount( wm->deps[i] );
-
+        walk_node_dependencies( node, context, MODULE_DecRefCount );
         wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
-
         module_push_unload_trace( wm );
     }
+    return STATUS_SUCCESS;
 }
 
 /******************************************************************
@@ -3639,7 +3731,7 @@ NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
         TRACE("(%s) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
 
         /* Recursively decrement reference counts */
-        MODULE_DecRefCount( wm );
+        MODULE_DecRefCount( wm->ldr.DdagNode, NULL );
 
         /* Call process detach notifications */
         if ( free_lib_count <= 1 )
@@ -3854,7 +3946,6 @@ static void release_address_space(void)
 void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR unknown3, ULONG_PTR unknown4 )
 {
     static int attach_done;
-    int i;
     NTSTATUS status;
     ULONG_PTR cookie;
     WINE_MODREF *wm;
@@ -3958,18 +4049,14 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR
         if (wm->ldr.ActivationContext)
             RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
 
-        for (i = 0; i < wm->nDeps; i++)
+        if ((status = walk_node_dependencies( wm->ldr.DdagNode, context, process_attach )))
         {
-            if (!wm->deps[i]) continue;
-            if ((status = process_attach( wm->deps[i]->ldr.DdagNode, context )) != STATUS_SUCCESS)
-            {
-                if (last_failed_modref)
-                    ERR( "%s failed to initialize, aborting\n",
-                         debugstr_w(last_failed_modref->ldr.BaseDllName.Buffer) + 1 );
-                ERR( "Initializing dlls for %s failed, status %x\n",
-                     debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
-                NtTerminateProcess( GetCurrentProcess(), status );
-            }
+            if (last_failed_modref)
+                ERR( "%s failed to initialize, aborting\n",
+                     debugstr_w(last_failed_modref->ldr.BaseDllName.Buffer) + 1 );
+            ERR( "Initializing dlls for %s failed, status %x\n",
+                 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
+            NtTerminateProcess( GetCurrentProcess(), status );
         }
         release_address_space();
         if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_PROCESS_ATTACH );
diff --git a/include/winternl.h b/include/winternl.h
index 7a34629edb0..eea97f1238b 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -3274,9 +3274,9 @@ typedef struct _LDRP_CSLIST
 
 typedef struct _LDR_DEPENDENCY
 {
-    LDRP_CSLIST dependency_to_entry;
+    SINGLE_LIST_ENTRY dependency_to_entry;
     struct _LDR_DDAG_NODE *dependency_to;
-    LDRP_CSLIST dependency_from_entry;
+    SINGLE_LIST_ENTRY dependency_from_entry;
     struct _LDR_DDAG_NODE *dependency_from;
 } LDR_DEPENDENCY, *PLDR_DEPENDENCY;
 
-- 
2.31.1




More information about the wine-devel mailing list