[PATCH 10/10] ntdll: Cleanup MUI structures when modules are unloaded.
Mark Harmstone
mark at harmstone.com
Sat Mar 27 14:47:37 CDT 2021
Signed-off-by: Mark Harmstone <mark at harmstone.com>
---
dlls/ntdll/loader.c | 72 ++++++++++++++++++++++++++++++++++++++---
dlls/ntdll/mui.c | 51 +++++++++++++++++++++++++++++
dlls/ntdll/ntdll_misc.h | 1 +
3 files changed, 120 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 7dada146044..c1746955558 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -3286,12 +3286,42 @@ static void free_modref( WINE_MODREF *wm )
* for the library type.
*
* The loader_section must be locked while calling this function.
+ *
+ * If anything is unloaded, the modules array is allocated and populated,
+ * so that cleanup_mui can be called for these outside of the lock.
*/
-static void MODULE_FlushModrefs(void)
+static void MODULE_FlushModrefs( void ***modules, unsigned int *num_modules )
{
PLIST_ENTRY mark, entry, prev;
LDR_DATA_TABLE_ENTRY *mod;
WINE_MODREF*wm;
+ unsigned int max_num_modules = 0;
+ void **m;
+
+ mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
+ for (entry = mark->Blink; entry != mark; entry = prev)
+ {
+ mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
+ wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
+ prev = entry->Blink;
+ if (!mod->LoadCount) max_num_modules++;
+ }
+
+ /* check load order list too for modules that haven't been initialized yet */
+ mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
+ for (entry = mark->Blink; entry != mark; entry = prev)
+ {
+ mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
+ wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
+ prev = entry->Blink;
+ if (!mod->LoadCount) max_num_modules++;
+ }
+
+ if (max_num_modules == 0)
+ return;
+
+ *modules = m = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(void*) * max_num_modules);
+ *num_modules = 0;
mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
for (entry = mark->Blink; entry != mark; entry = prev)
@@ -3299,7 +3329,17 @@ static void MODULE_FlushModrefs(void)
mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
prev = entry->Blink;
- if (!mod->LoadCount) free_modref( wm );
+ if (!mod->LoadCount)
+ {
+ if (m)
+ {
+ *m = wm->ldr.DllBase;
+ m++;
+ (*num_modules)++;
+ }
+
+ free_modref( wm );
+ }
}
/* check load order list too for modules that haven't been initialized yet */
@@ -3309,7 +3349,17 @@ static void MODULE_FlushModrefs(void)
mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
prev = entry->Blink;
- if (!mod->LoadCount) free_modref( wm );
+ if (!mod->LoadCount)
+ {
+ if (m)
+ {
+ *m = wm->ldr.DllBase;
+ m++;
+ (*num_modules)++;
+ }
+
+ free_modref( wm );
+ }
}
}
@@ -3354,6 +3404,8 @@ NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
{
WINE_MODREF *wm;
NTSTATUS retv = STATUS_SUCCESS;
+ void **modules;
+ unsigned int num_freed = 0;
if (process_detaching) return retv;
@@ -3373,7 +3425,7 @@ NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
if ( free_lib_count <= 1 )
{
process_detach();
- MODULE_FlushModrefs();
+ MODULE_FlushModrefs( &modules, &num_freed );
}
TRACE("END\n");
@@ -3385,6 +3437,18 @@ NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
RtlLeaveCriticalSection( &loader_section );
+ if (num_freed > 0)
+ {
+ unsigned int i;
+
+ for (i = 0; i < num_freed; i++)
+ {
+ cleanup_mui(modules[i]);
+ }
+
+ RtlFreeHeap( GetProcessHeap(), 0, modules);
+ }
+
return retv;
}
diff --git a/dlls/ntdll/mui.c b/dlls/ntdll/mui.c
index a9758c71f82..4921d710a2e 100644
--- a/dlls/ntdll/mui.c
+++ b/dlls/ntdll/mui.c
@@ -1244,6 +1244,7 @@ NTSTATUS NTAPI LdrRemoveLoadAsDataTable( PVOID init_module, PVOID *base_module,
ULONG flags )
{
data_module *dm;
+ BOOLEAN found = FALSE;
TRACE("(%p, %p, %p, %x)\n", init_module, base_module, size, flags);
@@ -1254,6 +1255,7 @@ NTSTATUS NTAPI LdrRemoveLoadAsDataTable( PVOID init_module, PVOID *base_module,
if (dm->module == init_module)
{
list_remove( &dm->entry );
+ found = TRUE;
RtlFreeHeap( GetProcessHeap(), 0, dm );
break;
}
@@ -1261,6 +1263,9 @@ NTSTATUS NTAPI LdrRemoveLoadAsDataTable( PVOID init_module, PVOID *base_module,
RtlLeaveCriticalSection( &data_modules_section );
+ if (found)
+ cleanup_mui( init_module );
+
return STATUS_SUCCESS;
}
@@ -1332,3 +1337,49 @@ void try_mui_redirect_module( HMODULE *mod, const IMAGE_RESOURCE_DATA_ENTRY *ent
RtlLeaveCriticalSection( &mm->list_section );
}
+
+/***********************************************************************
+ * cleanup_mui
+ *
+ * Free MUI structures when module is unloaded.
+ */
+void cleanup_mui( HMODULE mod )
+{
+ mui_module *mm = NULL, *mm2;
+
+ TRACE("(%p)\n", mod);
+
+ RtlEnterCriticalSection( &mui_section );
+
+ LIST_FOR_EACH_ENTRY( mm2, &mui_modules, mui_module, entry )
+ {
+ if (mm2->module == mod)
+ {
+ mm = mm2;
+ list_remove( &mm2->entry );
+ break;
+ }
+ }
+
+ RtlLeaveCriticalSection( &mui_section );
+
+ if (!mm)
+ return;
+
+ while (!list_empty( &mm->langs ))
+ {
+ mui_lang_module *mlm = LIST_ENTRY(mm->langs.next, mui_lang_module, entry);
+
+ TRACE("unmapping MUI file loaded at %p\n", mlm->addr);
+
+ list_remove( &mlm->entry );
+
+ NtUnmapViewOfSection( NtCurrentProcess(), mlm->addr );
+
+ RtlFreeHeap( GetProcessHeap(), 0, mlm);
+ }
+
+ RtlDeleteCriticalSection( &mm->list_section );
+
+ RtlFreeHeap( GetProcessHeap(), 0, mm );
+}
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index 563d599d426..552ff2013db 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -118,5 +118,6 @@ extern NTSTATUS find_resource_entry( HMODULE hmod, const LDR_RESOURCE_INFO *info
extern BOOLEAN try_mui_find_entry( HMODULE mod, const LDR_RESOURCE_INFO *info, ULONG level,
const void **ret, NTSTATUS *status) DECLSPEC_HIDDEN;
extern void try_mui_redirect_module( HMODULE *mod, const IMAGE_RESOURCE_DATA_ENTRY *entry ) DECLSPEC_HIDDEN;
+extern void cleanup_mui( HMODULE mod ) DECLSPEC_HIDDEN;
#endif
--
2.26.3
More information about the wine-devel
mailing list