Commit 1efa50e4 authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

- implementation of LdrUnloadDll out of loader/module.c

- in impacted functions, ensure that we only use ntdll functions - making use of new LdrUnloadDll
parent 580da246
...@@ -25,8 +25,15 @@ ...@@ -25,8 +25,15 @@
#include "wine/exception.h" #include "wine/exception.h"
#include "excpt.h" #include "excpt.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/server.h"
#include "ntdll_misc.h"
WINE_DEFAULT_DEBUG_CHANNEL(ntdll); WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
WINE_DECLARE_DEBUG_CHANNEL(module);
WINE_DECLARE_DEBUG_CHANNEL(module);
WINE_DECLARE_DEBUG_CHANNEL(loaddll);
static int free_lib_count; /* recursion depth of FreeLibrary calls */
/* filter for page-fault exceptions */ /* filter for page-fault exceptions */
static WINE_EXCEPTION_FILTER(page_fault) static WINE_EXCEPTION_FILTER(page_fault)
...@@ -154,7 +161,6 @@ FARPROC MODULE_GetProcAddress( ...@@ -154,7 +161,6 @@ FARPROC MODULE_GetProcAddress(
if ((wm = MODULE32_LookupHMODULE( hModule ))) if ((wm = MODULE32_LookupHMODULE( hModule )))
{ {
retproc = wm->find_export( wm, function, hint, snoop ); retproc = wm->find_export( wm, function, hint, snoop );
if (!retproc) SetLastError(ERROR_PROC_NOT_FOUND);
} }
RtlLeaveCriticalSection( &loader_section ); RtlLeaveCriticalSection( &loader_section );
return retproc; return retproc;
...@@ -172,7 +178,7 @@ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE base, PANSI_STRING name, ULONG or ...@@ -172,7 +178,7 @@ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE base, PANSI_STRING name, ULONG or
*address = MODULE_GetProcAddress( base, name ? name->Buffer : (LPSTR)ord, -1, TRUE ); *address = MODULE_GetProcAddress( base, name ? name->Buffer : (LPSTR)ord, -1, TRUE );
return (*address) ? STATUS_SUCCESS : STATUS_DLL_NOT_FOUND; return (*address) ? STATUS_SUCCESS : STATUS_PROCEDURE_NOT_FOUND;
} }
...@@ -217,6 +223,131 @@ NTSTATUS WINAPI LdrShutdownThread(void) ...@@ -217,6 +223,131 @@ NTSTATUS WINAPI LdrShutdownThread(void)
} }
/*********************************************************************** /***********************************************************************
* MODULE_FlushModrefs
*
* NOTE: Assumes that the process critical section is held!
*
* Remove all unused modrefs and call the internal unloading routines
* for the library type.
*/
static void MODULE_FlushModrefs(void)
{
WINE_MODREF *wm, *next;
for (wm = MODULE_modref_list; wm; wm = next)
{
next = wm->next;
if (wm->refCount)
continue;
/* Unlink this modref from the chain */
if (wm->next)
wm->next->prev = wm->prev;
if (wm->prev)
wm->prev->next = wm->next;
if (wm == MODULE_modref_list)
MODULE_modref_list = wm->next;
TRACE(" unloading %s\n", wm->filename);
if (!TRACE_ON(module))
TRACE_(loaddll)("Unloaded module '%s' : %s\n", wm->filename,
wm->dlhandle ? "builtin" : "native" );
SERVER_START_REQ( unload_dll )
{
req->base = (void *)wm->module;
wine_server_call( req );
}
SERVER_END_REQ;
if (wm->dlhandle) wine_dll_unload( wm->dlhandle );
else UnmapViewOfFile( (LPVOID)wm->module );
FreeLibrary16( wm->hDummyMod );
RtlFreeHeap( ntdll_get_process_heap(), 0, wm->deps );
RtlFreeHeap( ntdll_get_process_heap(), 0, wm );
}
}
/***********************************************************************
* MODULE_DecRefCount
*
* NOTE: Assumes that the process critical section is held!
*/
static void MODULE_DecRefCount( WINE_MODREF *wm )
{
int i;
if ( wm->flags & WINE_MODREF_MARKER )
return;
if ( wm->refCount <= 0 )
return;
--wm->refCount;
TRACE("(%s) refCount: %d\n", wm->modname, wm->refCount );
if ( wm->refCount == 0 )
{
wm->flags |= WINE_MODREF_MARKER;
for ( i = 0; i < wm->nDeps; i++ )
if ( wm->deps[i] )
MODULE_DecRefCount( wm->deps[i] );
wm->flags &= ~WINE_MODREF_MARKER;
}
}
/******************************************************************
* LdrUnloadDll (NTDLL.@)
*
*
*/
NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
{
NTSTATUS retv = STATUS_SUCCESS;
TRACE("(%p)\n", hModule);
RtlEnterCriticalSection( &loader_section );
/* if we're stopping the whole process (and forcing the removal of all
* DLLs) the library will be freed anyway
*/
if (!process_detaching)
{
WINE_MODREF *wm;
free_lib_count++;
if ((wm = MODULE32_LookupHMODULE( hModule )) != NULL)
{
TRACE("(%s) - START\n", wm->modname);
/* Recursively decrement reference counts */
MODULE_DecRefCount( wm );
/* Call process detach notifications */
if ( free_lib_count <= 1 )
{
MODULE_DllProcessDetach( FALSE, NULL );
MODULE_FlushModrefs();
}
TRACE("END\n");
}
else
retv = STATUS_DLL_NOT_FOUND;
free_lib_count--;
}
RtlLeaveCriticalSection( &loader_section );
return retv;
}
/***********************************************************************
* RtlImageNtHeader (NTDLL.@) * RtlImageNtHeader (NTDLL.@)
*/ */
PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule) PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
@ stub LdrQueryProcessModuleInformation @ stub LdrQueryProcessModuleInformation
@ stdcall LdrShutdownProcess() LdrShutdownProcess @ stdcall LdrShutdownProcess() LdrShutdownProcess
@ stdcall LdrShutdownThread() LdrShutdownThread @ stdcall LdrShutdownThread() LdrShutdownThread
@ stub LdrUnloadDll @ stdcall LdrUnloadDll(ptr) LdrUnloadDll
@ stub LdrVerifyImageMatchesChecksum @ stub LdrVerifyImageMatchesChecksum
@ stub NPXEMULATORTABLE @ stub NPXEMULATORTABLE
@ extern NlsAnsiCodePage NlsAnsiCodePage @ extern NlsAnsiCodePage NlsAnsiCodePage
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "winnt.h" #include "winnt.h"
#include "winternl.h" #include "winternl.h"
#include "thread.h"
/* debug helper */ /* debug helper */
extern LPCSTR debugstr_us( const UNICODE_STRING *str ); extern LPCSTR debugstr_us( const UNICODE_STRING *str );
...@@ -29,4 +30,10 @@ extern void dump_ObjectAttributes (const OBJECT_ATTRIBUTES *ObjectAttributes); ...@@ -29,4 +30,10 @@ extern void dump_ObjectAttributes (const OBJECT_ATTRIBUTES *ObjectAttributes);
/* module handling */ /* module handling */
extern FARPROC MODULE_GetProcAddress( HMODULE hModule, LPCSTR function, int hint, BOOL snoop ); extern FARPROC MODULE_GetProcAddress( HMODULE hModule, LPCSTR function, int hint, BOOL snoop );
static inline HANDLE ntdll_get_process_heap(void)
{
HANDLE *pdb = (HANDLE *)NtCurrentTeb()->process;
return pdb[0x18 / sizeof(HANDLE)]; /* get dword at offset 0x18 in pdb */
}
#endif #endif
...@@ -194,12 +194,10 @@ enum binary_type ...@@ -194,12 +194,10 @@ enum binary_type
/* module.c */ /* module.c */
extern WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename ); extern WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename );
extern FARPROC MODULE_GetProcAddress( HMODULE hModule, LPCSTR function, int hint, BOOL snoop );
extern BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved ); extern BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved );
extern void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved ); extern void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved );
extern void MODULE_DllThreadAttach( LPVOID lpReserved ); extern void MODULE_DllThreadAttach( LPVOID lpReserved );
extern WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HANDLE hfile, DWORD flags ); extern WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HANDLE hfile, DWORD flags );
extern BOOL MODULE_FreeLibrary( WINE_MODREF *wm );
extern WINE_MODREF *MODULE_FindModule( LPCSTR path ); extern WINE_MODREF *MODULE_FindModule( LPCSTR path );
extern HMODULE16 MODULE_CreateDummyModule( LPCSTR filename, HMODULE module32 ); extern HMODULE16 MODULE_CreateDummyModule( LPCSTR filename, HMODULE module32 );
extern enum binary_type MODULE_GetBinaryType( HANDLE hfile ); extern enum binary_type MODULE_GetBinaryType( HANDLE hfile );
......
...@@ -48,7 +48,6 @@ WINE_DECLARE_DEBUG_CHANNEL(loaddll); ...@@ -48,7 +48,6 @@ WINE_DECLARE_DEBUG_CHANNEL(loaddll);
WINE_MODREF *MODULE_modref_list = NULL; WINE_MODREF *MODULE_modref_list = NULL;
WINE_MODREF *exe_modref; WINE_MODREF *exe_modref;
static int free_lib_count; /* recursion depth of FreeLibrary calls */
int process_detaching = 0; /* set on process detach to avoid deadlocks with thread detach */ int process_detaching = 0; /* set on process detach to avoid deadlocks with thread detach */
CRITICAL_SECTION loader_section = CRITICAL_SECTION_INIT( "loader_section" ); CRITICAL_SECTION loader_section = CRITICAL_SECTION_INIT( "loader_section" );
...@@ -1083,7 +1082,7 @@ HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags) ...@@ -1083,7 +1082,7 @@ HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags)
if ( !MODULE_DllProcessAttach( wm, NULL ) ) if ( !MODULE_DllProcessAttach( wm, NULL ) )
{ {
WARN_(module)("Attach failed for module '%s'.\n", libname); WARN_(module)("Attach failed for module '%s'.\n", libname);
MODULE_FreeLibrary(wm); LdrUnloadDll(wm->module);
SetLastError(ERROR_DLL_INIT_FAILED); SetLastError(ERROR_DLL_INIT_FAILED);
wm = NULL; wm = NULL;
} }
...@@ -1334,66 +1333,13 @@ HMODULE WINAPI LoadLibraryExW(LPCWSTR libnameW,HANDLE hfile,DWORD flags) ...@@ -1334,66 +1333,13 @@ HMODULE WINAPI LoadLibraryExW(LPCWSTR libnameW,HANDLE hfile,DWORD flags)
} }
/*********************************************************************** /***********************************************************************
* MODULE_FlushModrefs
*
* NOTE: Assumes that the process critical section is held!
*
* Remove all unused modrefs and call the internal unloading routines
* for the library type.
*/
static void MODULE_FlushModrefs(void)
{
WINE_MODREF *wm, *next;
for(wm = MODULE_modref_list; wm; wm = next)
{
next = wm->next;
if(wm->refCount)
continue;
/* Unlink this modref from the chain */
if(wm->next)
wm->next->prev = wm->prev;
if(wm->prev)
wm->prev->next = wm->next;
if(wm == MODULE_modref_list)
MODULE_modref_list = wm->next;
TRACE(" unloading %s\n", wm->filename);
if (!TRACE_ON(module))
TRACE_(loaddll)("Unloaded module '%s' : %s\n", wm->filename,
wm->dlhandle ? "builtin" : "native" );
SERVER_START_REQ( unload_dll )
{
req->base = (void *)wm->module;
wine_server_call( req );
}
SERVER_END_REQ;
if (wm->dlhandle) wine_dll_unload( wm->dlhandle );
else UnmapViewOfFile( (LPVOID)wm->module );
FreeLibrary16(wm->hDummyMod);
HeapFree( GetProcessHeap(), 0, wm->deps );
HeapFree( GetProcessHeap(), 0, wm );
}
}
/***********************************************************************
* FreeLibrary (KERNEL32.@) * FreeLibrary (KERNEL32.@)
* FreeLibrary32 (KERNEL.486) * FreeLibrary32 (KERNEL.486)
*/ */
BOOL WINAPI FreeLibrary(HINSTANCE hLibModule) BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
{ {
BOOL retv = FALSE; BOOL retv = FALSE;
WINE_MODREF *wm; NTSTATUS nts;
if (!hLibModule)
{
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
if ((ULONG_PTR)hLibModule & 1) if ((ULONG_PTR)hLibModule & 1)
{ {
...@@ -1402,81 +1348,21 @@ BOOL WINAPI FreeLibrary(HINSTANCE hLibModule) ...@@ -1402,81 +1348,21 @@ BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
UnmapViewOfFile( ptr ); UnmapViewOfFile( ptr );
return TRUE; return TRUE;
} }
RtlEnterCriticalSection( &loader_section ); if (!hLibModule)
/* if we're stopping the whole process (and forcing the removal of all
* DLLs) the library will be freed anyway
*/
if (process_detaching) retv = TRUE;
else
{ {
free_lib_count++; SetLastError( ERROR_INVALID_HANDLE );
if ((wm = MODULE32_LookupHMODULE( hLibModule ))) retv = MODULE_FreeLibrary( wm ); RtlLeaveCriticalSection( &loader_section );
free_lib_count--; return FALSE;
} }
RtlLeaveCriticalSection( &loader_section ); if ((nts = LdrUnloadDll( hLibModule )) == STATUS_SUCCESS) retv = TRUE;
else SetLastError( RtlNtStatusToDosError( nts ) );
return retv; return retv;
} }
/*********************************************************************** /***********************************************************************
* MODULE_DecRefCount
*
* NOTE: Assumes that the process critical section is held!
*/
static void MODULE_DecRefCount( WINE_MODREF *wm )
{
int i;
if ( wm->flags & WINE_MODREF_MARKER )
return;
if ( wm->refCount <= 0 )
return;
--wm->refCount;
TRACE("(%s) refCount: %d\n", wm->modname, wm->refCount );
if ( wm->refCount == 0 )
{
wm->flags |= WINE_MODREF_MARKER;
for ( i = 0; i < wm->nDeps; i++ )
if ( wm->deps[i] )
MODULE_DecRefCount( wm->deps[i] );
wm->flags &= ~WINE_MODREF_MARKER;
}
}
/***********************************************************************
* MODULE_FreeLibrary
*
* NOTE: Assumes that the process critical section is held!
*/
BOOL MODULE_FreeLibrary( WINE_MODREF *wm )
{
TRACE("(%s) - START\n", wm->modname );
/* Recursively decrement reference counts */
MODULE_DecRefCount( wm );
/* Call process detach notifications */
if ( free_lib_count <= 1 )
{
MODULE_DllProcessDetach( FALSE, NULL );
MODULE_FlushModrefs();
}
TRACE("END\n");
return TRUE;
}
/***********************************************************************
* FreeLibraryAndExitThread (KERNEL32.@) * FreeLibraryAndExitThread (KERNEL32.@)
*/ */
VOID WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode) VOID WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment