[PATCH 18/22] ntdll: Use shared loader locking in LdrGetProcedureAddress() when possible.

Paul Gofman pgofman at codeweavers.com
Fri Oct 1 13:21:03 CDT 2021


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 dlls/ntdll/loader.c | 62 +++++++++++++++++++++++++++++++++------------
 1 file changed, 46 insertions(+), 16 deletions(-)

diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 436491921c6..77d7a292569 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -217,9 +217,9 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WC
                           DWORD flags, WINE_MODREF** pwm );
 static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved );
 static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
-                                    DWORD exp_size, DWORD ordinal, LPCWSTR load_path );
+                                    DWORD exp_size, DWORD ordinal, LPCWSTR load_path, NTSTATUS *status );
 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
-                                  DWORD exp_size, const char *name, int hint, LPCWSTR load_path );
+                                  DWORD exp_size, const char *name, int hint, LPCWSTR load_path, NTSTATUS *status );
 
 /* convert PE image VirtualAddress to Real Address */
 static inline void *get_rva( HMODULE module, DWORD va )
@@ -937,7 +937,7 @@ static WINE_MODREF **grow_module_deps( WINE_MODREF *wm, int count )
  * Find the final function pointer for a forwarded function.
  * The loader must be locked while calling this function.
  */
-static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path )
+static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path, NTSTATUS *status )
 {
     const IMAGE_EXPORT_DIRECTORY *exports;
     DWORD exp_size;
@@ -960,6 +960,14 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS
 
     if (!(wm = find_basename_module( mod_name )))
     {
+        if (!locked_exclusive)
+        {
+            TRACE( "Need to load %s for '%s' while not in exclusive lock.\n", debugstr_w(mod_name), forward );
+            assert( status );
+            if (mod_name != buffer) RtlFreeHeap( GetProcessHeap(), 0, mod_name );
+            if (status) *status = STATUS_NOT_FOUND;
+            return NULL;
+        }
         TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward );
         if (load_dll( load_path, mod_name, L".dll", 0, &wm ) == STATUS_SUCCESS &&
             !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
@@ -991,9 +999,9 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS
 
         if (*name == '#') { /* ordinal */
             proc = find_ordinal_export( wm->ldr.DllBase, exports, exp_size,
-                                        atoi(name+1) - exports->Base, load_path );
+                                        atoi(name+1) - exports->Base, load_path, status );
         } else
-            proc = find_named_export( wm->ldr.DllBase, exports, exp_size, name, -1, load_path );
+            proc = find_named_export( wm->ldr.DllBase, exports, exp_size, name, -1, load_path, status );
     }
 
     if (!proc)
@@ -1016,11 +1024,13 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS
  * The loader must be locked while calling this function.
  */
 static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
-                                    DWORD exp_size, DWORD ordinal, LPCWSTR load_path )
+                                    DWORD exp_size, DWORD ordinal, LPCWSTR load_path, NTSTATUS *status )
 {
     FARPROC proc;
     const DWORD *functions = get_rva( module, exports->AddressOfFunctions );
 
+    if (status) *status = STATUS_PROCEDURE_NOT_FOUND;
+
     if (ordinal >= exports->NumberOfFunctions)
     {
         TRACE("	ordinal %d out of range!\n", ordinal + exports->Base );
@@ -1033,7 +1043,7 @@ static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY
     /* if the address falls into the export dir, it's a forward */
     if (((const char *)proc >= (const char *)exports) && 
         ((const char *)proc < (const char *)exports + exp_size))
-        return find_forwarded_export( module, (const char *)proc, load_path );
+        return find_forwarded_export( module, (const char *)proc, load_path, status );
 
     if (TRACE_ON(snoop))
     {
@@ -1079,7 +1089,7 @@ static int find_name_in_exports( HMODULE module, const IMAGE_EXPORT_DIRECTORY *e
  * The loader must be locked while calling this function.
  */
 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
-                                  DWORD exp_size, const char *name, int hint, LPCWSTR load_path )
+                                  DWORD exp_size, const char *name, int hint, LPCWSTR load_path, NTSTATUS *status )
 {
     const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
     const DWORD *names = get_rva( module, exports->AddressOfNames );
@@ -1090,12 +1100,12 @@ static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *
     {
         char *ename = get_rva( module, names[hint] );
         if (!strcmp( ename, name ))
-            return find_ordinal_export( module, exports, exp_size, ordinals[hint], load_path );
+            return find_ordinal_export( module, exports, exp_size, ordinals[hint], load_path, status );
     }
 
     /* then do a binary search */
     if ((ordinal = find_name_in_exports( module, exports, name )) == -1) return NULL;
-    return find_ordinal_export( module, exports, exp_size, ordinal, load_path );
+    return find_ordinal_export( module, exports, exp_size, ordinal, load_path, status );
 
 }
 
@@ -1229,7 +1239,7 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP
             int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
 
             thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,
-                                                                      ordinal - exports->Base, load_path );
+                                                                      ordinal - exports->Base, load_path, NULL );
             if (!thunk_list->u1.Function)
             {
                 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
@@ -1245,7 +1255,7 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP
             pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
             thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,
                                                                     (const char*)pe_name->Name,
-                                                                    pe_name->Hint, load_path );
+                                                                    pe_name->Hint, load_path, NULL );
             if (!thunk_list->u1.Function)
             {
                 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
@@ -2078,24 +2088,37 @@ NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG_PTR magic )
 NTSTATUS get_procedure_address( HMODULE module, const ANSI_STRING *name,
                                 ULONG ord, void **address )
 {
+    NTSTATUS status = STATUS_PROCEDURE_NOT_FOUND;
     IMAGE_EXPORT_DIRECTORY *exports;
+    WINE_MODREF *wm;
     DWORD exp_size;
 
+retry:
     /* check if the module itself is invalid to return the proper error */
-    if (!get_modref( module )) return STATUS_DLL_NOT_FOUND;
+    if (!(wm = get_modref( module ))) return STATUS_DLL_NOT_FOUND;
+
+    lock_module_info();
+    if (!is_thread_exclusive() && (!wm->ldr.LoadCount || (wm->ldr.Flags & LDR_LOAD_IN_PROGRESS)))
+    {
+        unlock_module_info();
+        if (!wm->ldr.LoadCount) return STATUS_INVALID_PARAMETER;
+        wait_for_exclusive_lock_release();
+        goto retry;
+    }
+    unlock_module_info();
 
     if ((exports = RtlImageDirectoryEntryToData( module, TRUE,
                                                       IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
     {
-        void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, NULL )
-                          : find_ordinal_export( module, exports, exp_size, ord - exports->Base, NULL );
+        void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, NULL, &status )
+                          : find_ordinal_export( module, exports, exp_size, ord - exports->Base, NULL, &status );
         if (proc)
         {
             *address = proc;
             return STATUS_SUCCESS;
         }
     }
-    return STATUS_PROCEDURE_NOT_FOUND;
+    return status;
 }
 
 /******************************************************************
@@ -2106,9 +2129,16 @@ NTSTATUS WINAPI LdrGetProcedureAddress( HMODULE module, const ANSI_STRING *name,
 {
     NTSTATUS ret;
 
+    lock_loader_shared();
+    ret = get_procedure_address( module, name, ord, address );
+    unlock_loader();
+
+    if (ret != STATUS_NOT_FOUND) return ret;
+
     lock_loader_exclusive();
     ret = get_procedure_address( module, name, ord, address );
     unlock_loader();
+
     return ret;
 }
 
-- 
2.31.1




More information about the wine-devel mailing list