Module: wine Branch: master Commit: 20c4ae45cecb2b08544880da5aeb7b9435d1ec65 URL: https://source.winehq.org/git/wine.git/?a=commit;h=20c4ae45cecb2b08544880da5...
Author: Alexandre Julliard julliard@winehq.org Date: Mon Mar 22 16:11:51 2021 +0100
ntdll: Add refcounting for .so builtin dlls.
Signed-off-by: Alexandre Julliard julliard@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 );