From f7e7a5d7345cb416c5514b983f2d8ad387b6f915 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Wed, 3 Feb 2021 20:57:40 +0100 Subject: Fix some style issues --- src/dlfcn.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/dlfcn.c b/src/dlfcn.c index abbd58d..9620692 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -38,11 +38,11 @@ #ifdef _MSC_VER /* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */ -#pragma intrinsic(_ReturnAddress) +#pragma intrinsic( _ReturnAddress ) #else /* https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html */ #ifndef _ReturnAddress -#define _ReturnAddress() (__builtin_extract_return_addr(__builtin_return_address(0))) +#define _ReturnAddress( ) ( __builtin_extract_return_addr( __builtin_return_address( 0 ) ) ) #endif #endif @@ -90,12 +90,12 @@ static BOOL local_add( HMODULE hModule ) pobject = local_search( hModule ); /* Do not add object again if it's already on the list */ - if( pobject ) + if( pobject != NULL ) return TRUE; for( pobject = &first_object; pobject->next; pobject = pobject->next ); - nobject = (local_object*) malloc( sizeof( local_object ) ); + nobject = (local_object *) malloc( sizeof( local_object ) ); if( !nobject ) { @@ -120,7 +120,7 @@ static void local_rem( HMODULE hModule ) pobject = local_search( hModule ); - if( !pobject ) + if( pobject == NULL ) return; if( pobject->next ) @@ -159,7 +159,7 @@ static void save_err_str( const char *str ) */ pos = 0; error_buffer[pos++] = '"'; - memcpy( error_buffer+pos, str, len ); + memcpy( error_buffer + pos, str, len ); pos += len; error_buffer[pos++] = '"'; error_buffer[pos++] = ':'; @@ -167,7 +167,7 @@ static void save_err_str( const char *str ) ret = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwMessageId, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), - error_buffer+pos, (DWORD) (sizeof(error_buffer)-pos), NULL ); + error_buffer + pos, (DWORD) ( sizeof( error_buffer ) - pos ), NULL ); pos += ret; /* When FormatMessageA() fails it returns zero and does not touch buffer @@ -197,7 +197,7 @@ static void save_err_ptr_str( const void *ptr ) for( i = 0; i < 2 * sizeof( ptr ); i++ ) { num = ( ( (ULONG_PTR) ptr ) >> ( 8 * sizeof( ptr ) - 4 * ( i + 1 ) ) ) & 0xF; - ptr_buf[2+i] = num + ( ( num < 0xA ) ? '0' : ( 'A' - 0xA ) ); + ptr_buf[2 + i] = num + ( ( num < 0xA ) ? '0' : ( 'A' - 0xA ) ); } ptr_buf[2 + 2 * sizeof( ptr )] = 0; @@ -234,9 +234,9 @@ void *dlopen( const char *file, int mode ) /* Do not let Windows display the critical-error-handler message box */ uMode = SetErrorMode( SEM_FAILCRITICALERRORS ); - if( file == 0 ) + if( file == NULL ) { - /* POSIX says that if the value of file is 0, a handle on a global + /* POSIX says that if the value of file is NULL, a handle on a global * symbol object must be provided. That object must be able to access * all symbols from the original program file, and any objects loaded * with the RTLD_GLOBAL flag. -- cgit v1.2.3-55-g6feb From b89f89323c13a9804d9d521ea9800983f955560a Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Wed, 3 Feb 2021 20:58:15 +0100 Subject: Move hCurrentProc variable to scope where is used --- src/dlfcn.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/dlfcn.c b/src/dlfcn.c index 9620692..8cd2fc9 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -362,14 +362,12 @@ void *dlsym( void *handle, const char *name ) FARPROC symbol; HMODULE hCaller; HMODULE hModule; - HANDLE hCurrentProc; error_occurred = FALSE; symbol = NULL; hCaller = NULL; hModule = GetModuleHandle( NULL ); - hCurrentProc = GetCurrentProcess( ); if( handle == RTLD_DEFAULT ) { @@ -407,11 +405,14 @@ void *dlsym( void *handle, const char *name ) if( hModule == handle || handle == RTLD_NEXT ) { + HANDLE hCurrentProc; HMODULE *modules; DWORD cbNeeded; DWORD dwSize; size_t i; + hCurrentProc = GetCurrentProcess( ); + /* GetModuleHandle( NULL ) only returns the current program file. So * if we want to get ALL loaded module including those in linked DLLs, * we have to use EnumProcessModules( ). -- cgit v1.2.3-55-g6feb From c172ee216cd5d46c1999018e1a3e905eebe3c10c Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Wed, 3 Feb 2021 20:58:39 +0100 Subject: Avoid calling SetLastError() and GetLastError() internally There is no need for propagating internal errors via SetLastError() and GetLastError() calls. Just use additional argument for save_err_str() function. Also dlfcn API is POSIX and does not use GetLastError(). --- src/dlfcn.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/dlfcn.c b/src/dlfcn.c index 8cd2fc9..33fa325 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -98,10 +98,7 @@ static BOOL local_add( HMODULE hModule ) nobject = (local_object *) malloc( sizeof( local_object ) ); if( !nobject ) - { - SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return FALSE; - } pobject->next = nobject; nobject->next = NULL; @@ -139,17 +136,11 @@ static void local_rem( HMODULE hModule ) static char error_buffer[65535]; static BOOL error_occurred; -static void save_err_str( const char *str ) +static void save_err_str( const char *str, DWORD dwMessageId ) { - DWORD dwMessageId; DWORD ret; size_t pos, len; - dwMessageId = GetLastError( ); - - if( dwMessageId == 0 ) - return; - len = strlen( str ); if( len > sizeof( error_buffer ) - 5 ) len = sizeof( error_buffer ) - 5; @@ -185,7 +176,7 @@ static void save_err_str( const char *str ) error_occurred = TRUE; } -static void save_err_ptr_str( const void *ptr ) +static void save_err_ptr_str( const void *ptr, DWORD dwMessageId ) { char ptr_buf[2 + 2 * sizeof( ptr ) + 1]; char num; @@ -202,7 +193,7 @@ static void save_err_ptr_str( const void *ptr ) ptr_buf[2 + 2 * sizeof( ptr )] = 0; - save_err_str( ptr_buf ); + save_err_str( ptr_buf, dwMessageId ); } /* Load Psapi.dll at runtime, this avoids linking caveat */ @@ -249,7 +240,7 @@ void *dlopen( const char *file, int mode ) hModule = GetModuleHandle( NULL ); if( !hModule ) - save_err_str( "(null)" ); + save_err_str( "(null)", GetLastError( ) ); } else { @@ -262,8 +253,7 @@ void *dlopen( const char *file, int mode ) if( len >= sizeof( lpFileName ) ) { - SetLastError( ERROR_FILENAME_EXCED_RANGE ); - save_err_str( file ); + save_err_str( file, ERROR_FILENAME_EXCED_RANGE ); hModule = NULL; } else @@ -292,7 +282,7 @@ void *dlopen( const char *file, int mode ) if( !hModule ) { - save_err_str( lpFileName ); + save_err_str( lpFileName, GetLastError( ) ); } else { @@ -312,7 +302,7 @@ void *dlopen( const char *file, int mode ) { if( !local_add( hModule ) ) { - save_err_str( lpFileName ); + save_err_str( lpFileName, ERROR_NOT_ENOUGH_MEMORY ); FreeLibrary( hModule ); hModule = NULL; } @@ -347,7 +337,7 @@ int dlclose( void *handle ) if( ret ) local_rem( hModule ); else - save_err_ptr_str( handle ); + save_err_ptr_str( handle, GetLastError( ) ); /* dlclose's return value in inverted in relation to FreeLibrary's. */ ret = !ret; @@ -362,12 +352,14 @@ void *dlsym( void *handle, const char *name ) FARPROC symbol; HMODULE hCaller; HMODULE hModule; + DWORD dwMessageId; error_occurred = FALSE; symbol = NULL; hCaller = NULL; hModule = GetModuleHandle( NULL ); + dwMessageId = 0; if( handle == RTLD_DEFAULT ) { @@ -388,7 +380,10 @@ void *dlsym( void *handle, const char *name ) * use standard GetModuleHandleExA() function. */ if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) _ReturnAddress( ), &hCaller ) ) + { + dwMessageId = ERROR_INVALID_PARAMETER; goto end; + } } if( handle != RTLD_NEXT ) @@ -448,7 +443,7 @@ void *dlsym( void *handle, const char *name ) } else { - SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + dwMessageId = ERROR_NOT_ENOUGH_MEMORY; goto end; } } @@ -457,9 +452,9 @@ void *dlsym( void *handle, const char *name ) end: if( symbol == NULL ) { - if( GetLastError() == 0 ) - SetLastError( ERROR_PROC_NOT_FOUND ); - save_err_str( name ); + if( !dwMessageId ) + dwMessageId = ERROR_PROC_NOT_FOUND; + save_err_str( name, dwMessageId ); } return *(void **) (&symbol); -- cgit v1.2.3-55-g6feb From 0e9d85a9d03bcedade35cced63ec6b969ab3451e Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Wed, 3 Feb 2021 20:59:18 +0100 Subject: Fix helper function MyEnumProcessModules() Call SetErrorMode(SEM_FAILCRITICALERRORS) prior opening Psapi.dll library to avoid GUI error messages. Close Psapi.dll library via FreeLibrary() if symbol was not retrieved to prevent possible memory leaks. Try to get K32EnumProcessModules symbol from Kernel32.dll library as it is preferred way how to call EnumProcessModules() on Windows 7 and newer versions. If retrieving EnumProcessModules symbol failed with both methods then do not try it again on next MyEnumProcessModules() function call. --- src/dlfcn.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/dlfcn.c b/src/dlfcn.c index 33fa325..4e4e10e 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -199,16 +199,41 @@ static void save_err_ptr_str( const void *ptr, DWORD dwMessageId ) /* Load Psapi.dll at runtime, this avoids linking caveat */ static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ) { - static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD); + static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD) = NULL; + static BOOL failed = FALSE; + UINT uMode; HMODULE psapi; - if( !EnumProcessModulesPtr ) + if( failed ) + return FALSE; + + if( EnumProcessModulesPtr == NULL ) { - psapi = LoadLibraryA( "Psapi.dll" ); - if( psapi ) - EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( psapi, "EnumProcessModules" ); - if( !EnumProcessModulesPtr ) - return 0; + /* Windows 7 and newer versions have K32EnumProcessModules in Kernel32.dll which is always pre-loaded */ + psapi = GetModuleHandleA( "Kernel32.dll" ); + if( psapi != NULL ) + EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( psapi, "K32EnumProcessModules" ); + + /* Windows Vista and older version have EnumProcessModules in Psapi.dll which needs to be loaded */ + if( EnumProcessModulesPtr == NULL ) + { + /* Do not let Windows display the critical-error-handler message box */ + uMode = SetErrorMode( SEM_FAILCRITICALERRORS ); + psapi = LoadLibraryA( "Psapi.dll" ); + if( psapi != NULL ) + { + EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( psapi, "EnumProcessModules" ); + if( EnumProcessModulesPtr == NULL ) + FreeLibrary( psapi ); + } + SetErrorMode( uMode ); + } + + if( EnumProcessModulesPtr == NULL ) + { + failed = TRUE; + return FALSE; + } } return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded ); -- cgit v1.2.3-55-g6feb From 06fea3fe8b3efe8c79f97fa724f703bc0e25aeef Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Wed, 3 Feb 2021 20:59:58 +0100 Subject: Add helper function MyGetModuleHandleFromAddress() This function implements calling GetModuleHandleExA() with correct flags to retrieve hModule from passed address. To allow compilation also with older compilers and environments (like WDK) with any _WIN32_WINNT value, retrieve pointer to this function via GetProcAddress(). And as a fallback implementation use old code via VirtualQuery() which was there prior commit 8ec5ffef2eca. --- src/dlfcn.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/dlfcn.c b/src/dlfcn.c index 4e4e10e..80bd119 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -24,9 +24,6 @@ * THE SOFTWARE. */ -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif #ifdef _DEBUG #define _CRTDBG_MAP_ALLOC #include @@ -36,6 +33,14 @@ #include #include +/* Older SDK versions do not have these macros */ +#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS +#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x4 +#endif +#ifndef GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT +#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 0x2 +#endif + #ifdef _MSC_VER /* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */ #pragma intrinsic( _ReturnAddress ) @@ -196,6 +201,44 @@ static void save_err_ptr_str( const void *ptr, DWORD dwMessageId ) save_err_str( ptr_buf, dwMessageId ); } +static HMODULE MyGetModuleHandleFromAddress( void *addr ) +{ + static BOOL (WINAPI *GetModuleHandleExAPtr)(DWORD, LPCSTR, HMODULE *) = NULL; + static BOOL failed = FALSE; + HMODULE kernel32; + HMODULE hModule; + MEMORY_BASIC_INFORMATION info; + SIZE_T sLen; + + if( !failed && GetModuleHandleExAPtr == NULL ) + { + kernel32 = GetModuleHandleA( "Kernel32.dll" ); + if( kernel32 != NULL ) + GetModuleHandleExAPtr = (BOOL (WINAPI *)(DWORD, LPCSTR, HMODULE *)) GetProcAddress( kernel32, "GetModuleHandleExA" ); + if( GetModuleHandleExAPtr == NULL ) + failed = TRUE; + } + + if( !failed ) + { + /* If GetModuleHandleExA is available use it with GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS */ + if( !GetModuleHandleExAPtr( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) addr, &hModule ) ) + return NULL; + } + else + { + /* To get HMODULE from address use undocumented hack from https://stackoverflow.com/a/2396380 + * The HMODULE of a DLL is the same value as the module's base address. + */ + sLen = VirtualQuery( addr, &info, sizeof( info ) ); + if( sLen != sizeof( info ) ) + return NULL; + hModule = (HMODULE) info.AllocationBase; + } + + return hModule; +} + /* Load Psapi.dll at runtime, this avoids linking caveat */ static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ) { @@ -402,9 +445,12 @@ void *dlsym( void *handle, const char *name ) * The next object is the one found upon the application of a load * order symbol resolution algorithm. To get caller function of dlsym() * use _ReturnAddress() intrinsic. To get HMODULE of caller function - * use standard GetModuleHandleExA() function. + * use MyGetModuleHandleFromAddress() which calls either standard + * GetModuleHandleExA() function or hack via VirtualQuery(). */ - if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) _ReturnAddress( ), &hCaller ) ) + hCaller = MyGetModuleHandleFromAddress( _ReturnAddress( ) ); + + if( hCaller == NULL ) { dwMessageId = ERROR_INVALID_PARAMETER; goto end; @@ -638,7 +684,9 @@ static BOOL fill_info( void *addr, Dl_info *info ) void *funcAddress = NULL; /* Get module of the specified address */ - if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &hModule ) || hModule == NULL ) + hModule = MyGetModuleHandleFromAddress( addr ); + + if( hModule == NULL ) return FALSE; dwSize = GetModuleFileNameA( hModule, module_filename, sizeof( module_filename ) ); @@ -676,7 +724,9 @@ int dladdr( void *addr, Dl_info *info ) HMODULE hModule; /* Get module of the import thunk address */ - if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &hModule ) || hModule == NULL ) + hModule = MyGetModuleHandleFromAddress( addr ); + + if( hModule == NULL ) return 0; if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IAT, &iat, &iatSize ) ) -- cgit v1.2.3-55-g6feb From d1a0d28f903f9d3eff03f06e299cde5a7998216e Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Wed, 3 Feb 2021 21:00:28 +0100 Subject: Fix MSVC 14.00 compile warning: warning C4244: '=' : conversion from 'ULONG_PTR' to 'char', possible loss of data --- src/dlfcn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/dlfcn.c b/src/dlfcn.c index 80bd119..394ee19 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -192,7 +192,7 @@ static void save_err_ptr_str( const void *ptr, DWORD dwMessageId ) for( i = 0; i < 2 * sizeof( ptr ); i++ ) { - num = ( ( (ULONG_PTR) ptr ) >> ( 8 * sizeof( ptr ) - 4 * ( i + 1 ) ) ) & 0xF; + num = (char) ( ( ( (ULONG_PTR) ptr ) >> ( 8 * sizeof( ptr ) - 4 * ( i + 1 ) ) ) & 0xF ); ptr_buf[2 + i] = num + ( ( num < 0xA ) ? '0' : ( 'A' - 0xA ) ); } -- cgit v1.2.3-55-g6feb From 7da1054564609f3382869714432f54b63812d083 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Wed, 3 Feb 2021 21:00:56 +0100 Subject: Define ULONG_PTR for older SDK If compiling with _WIN32_WINNT target prior 0x0500 then SDK does not define ULONG_PTR type. Such systems are only 32bit so define it explicitly to 32bit type ULONG. --- src/dlfcn.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/dlfcn.c b/src/dlfcn.c index 394ee19..c4f410d 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -33,6 +33,11 @@ #include #include +/* Older versions do not have this type */ +#if _WIN32_WINNT < 0x0500 +typedef ULONG ULONG_PTR; +#endif + /* Older SDK versions do not have these macros */ #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x4 -- cgit v1.2.3-55-g6feb From 9e40646cf3a7d0817b2298f915399a128fcb4d27 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Wed, 3 Feb 2021 21:01:24 +0100 Subject: Fix noinline for older compiler versions (e.g. Visual Studio 6.0) Visual Studio 6.0 does not support __declspec(noinline) and throw error. Add checks for compilers which support noinline to prevent compile errors. --- src/dlfcn.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/dlfcn.c b/src/dlfcn.c index c4f410d..86f24df 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -61,6 +61,16 @@ typedef ULONG ULONG_PTR; #endif #include "dlfcn.h" +#if defined( _MSC_VER ) && _MSC_VER >= 1300 +/* https://docs.microsoft.com/en-us/cpp/cpp/noinline */ +#define DLFCN_NOINLINE __declspec( noinline ) +#elif defined( __GNUC__ ) && ( ( __GNUC__ > 3 ) || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 1 ) ) +/* https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html */ +#define DLFCN_NOINLINE __attribute__(( noinline )) +#else +#define DLFCN_NOINLINE +#endif + /* Note: * MSDN says these functions are not thread-safe. We make no efforts to have * any kind of thread safety. @@ -418,7 +428,7 @@ int dlclose( void *handle ) return (int) ret; } -__declspec(noinline) /* Needed for _ReturnAddress() */ +DLFCN_NOINLINE /* Needed for _ReturnAddress() */ DLFCN_EXPORT void *dlsym( void *handle, const char *name ) { -- cgit v1.2.3-55-g6feb