Alexandre Julliard : ntdll: Add refcounting for .so builtin dlls.

Alexandre Julliard julliard at winehq.org
Mon Mar 22 17:15:52 CDT 2021


Module: wine
Branch: master
Commit: 20c4ae45cecb2b08544880da5aeb7b9435d1ec65
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=20c4ae45cecb2b08544880da5aeb7b9435d1ec65

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Mon Mar 22 16:11:51 2021 +0100

ntdll: Add refcounting for .so builtin dlls.

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/unix/loader.c       |  4 ++-
 dlls/ntdll/unix/unix_private.h |  1 +
 dlls/ntdll/unix/virtual.c      | 58 +++++++++++++++++++++++++++++-------------
 3 files changed, 45 insertions(+), 18 deletions(-)

diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index 1c95b84e965..f7bdb055871 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -1456,7 +1456,9 @@ static void CDECL init_builtin_dll( void *module )
 #endif
 
     if (!(handle = get_builtin_so_handle( module ))) return;
-    if (dlinfo( handle, RTLD_DI_LINKMAP, &map )) return;
+    if (dlinfo( handle, RTLD_DI_LINKMAP, &map )) map = NULL;
+    release_builtin_module( module );
+    if (!map) return;
 
     for (dyn = map->l_ld; dyn->d_tag; dyn++)
     {
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index 5877a00bac8..1307364d5d3 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -202,6 +202,7 @@ extern void virtual_set_force_exec( BOOL enable ) DECLSPEC_HIDDEN;
 extern void virtual_set_large_address_space(void) DECLSPEC_HIDDEN;
 extern void virtual_fill_image_information( const pe_image_info_t *pe_info,
                                             SECTION_IMAGE_INFORMATION *info ) DECLSPEC_HIDDEN;
+extern NTSTATUS release_builtin_module( void *module ) DECLSPEC_HIDDEN;
 extern void *get_builtin_so_handle( void *module ) DECLSPEC_HIDDEN;
 extern NTSTATUS get_builtin_unix_info( void *module, const char **name, void **handle, void **entry ) DECLSPEC_HIDDEN;
 extern NTSTATUS set_builtin_unix_info( void *module, const char *name, void *handle, void *entry ) DECLSPEC_HIDDEN;
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 4edc7d0261e..d00178d6261 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -85,14 +85,15 @@ static struct list reserved_areas = LIST_INIT(reserved_areas);
 
 struct builtin_module
 {
-    struct list entry;
-    dev_t       dev;
-    ino_t       ino;
-    void       *handle;
-    void       *module;
-    char       *unix_name;
-    void       *unix_handle;
-    void       *unix_entry;
+    struct list  entry;
+    unsigned int refcount;
+    dev_t        dev;
+    ino_t        ino;
+    void        *handle;
+    void        *module;
+    char        *unix_name;
+    void        *unix_handle;
+    void        *unix_entry;
 };
 
 static struct list builtin_modules = LIST_INIT( builtin_modules );
@@ -569,8 +570,9 @@ static void add_builtin_module( void *module, void *handle, const struct stat *s
     struct builtin_module *builtin;
 
     if (!(builtin = malloc( sizeof(*builtin) ))) return;
-    builtin->handle = handle;
-    builtin->module = module;
+    builtin->handle      = handle;
+    builtin->module      = module;
+    builtin->refcount    = 1;
     builtin->unix_name   = NULL;
     builtin->unix_handle = NULL;
     builtin->unix_entry  = NULL;
@@ -589,19 +591,23 @@ static void add_builtin_module( void *module, void *handle, const struct stat *s
 
 
 /***********************************************************************
- *           remove_builtin_module
+ *           release_builtin_module
  */
-static NTSTATUS remove_builtin_module( void *module )
+NTSTATUS release_builtin_module( void *module )
 {
     struct builtin_module *builtin;
 
     LIST_FOR_EACH_ENTRY( builtin, &builtin_modules, struct builtin_module, entry )
     {
         if (builtin->module != module) continue;
-        list_remove( &builtin->entry );
-        if (builtin->handle) dlclose( builtin->handle );
-        if (builtin->unix_handle) dlclose( builtin->unix_handle );
-        free( builtin );
+        if (!--builtin->refcount)
+        {
+            list_remove( &builtin->entry );
+            if (builtin->handle) dlclose( builtin->handle );
+            if (builtin->unix_handle) dlclose( builtin->unix_handle );
+            free( builtin->unix_name );
+            free( builtin );
+        }
         return STATUS_SUCCESS;
     }
     return STATUS_INVALID_PARAMETER;
@@ -635,6 +641,7 @@ void *get_builtin_so_handle( void *module )
     {
         if (builtin->module != module) continue;
         ret = builtin->handle;
+        if (ret) builtin->refcount++;
         break;
     }
     server_leave_uninterrupted_section( &virtual_mutex, &sigset );
@@ -4374,6 +4381,23 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
     server_enter_uninterrupted_section( &virtual_mutex, &sigset );
     if ((view = find_view( addr, 0 )) && !is_view_valloc( view ))
     {
+        if (view->protect & VPROT_SYSTEM)
+        {
+            struct builtin_module *builtin;
+
+            LIST_FOR_EACH_ENTRY( builtin, &builtin_modules, struct builtin_module, entry )
+            {
+                if (builtin->module != view->base) continue;
+                if (builtin->refcount > 1)
+                {
+                    TRACE( "not freeing in-use builtin %p\n", view->base );
+                    builtin->refcount--;
+                    server_leave_uninterrupted_section( &virtual_mutex, &sigset );
+                    return STATUS_SUCCESS;
+                }
+            }
+        }
+
         SERVER_START_REQ( unmap_view )
         {
             req->base = wine_server_client_ptr( view->base );
@@ -4382,7 +4406,7 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
         SERVER_END_REQ;
         if (!status)
         {
-            if (view->protect & SEC_IMAGE) remove_builtin_module( view->base );
+            if (view->protect & SEC_IMAGE) release_builtin_module( view->base );
             delete_view( view );
         }
         else FIXME( "failed to unmap %p %x\n", view->base, status );




More information about the wine-cvs mailing list