From 3b735be29deae48aea3b30d84fda040501600ce9 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Sat, 2 Dec 2023 16:30:22 +0100 Subject: Fix dlclose() for dlopen(NULL, ...) dlopen(NULL, ...) does not call LoadLibrary(), so do not call FreeLibrary() in dlclose() for this case. --- src/dlfcn.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/dlfcn.c b/src/dlfcn.c index cb9f9bb..be6e01f 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -466,6 +466,10 @@ int dlclose( void *handle ) error_occurred = FALSE; + /* dlopen(NULL, ...) does not call LoadLibrary(), so do not call FreeLibrary(). */ + if( hModule == GetModuleHandle( NULL ) ) + return 0; + ret = FreeLibrary( hModule ); /* If the object was loaded with RTLD_LOCAL, remove it from list of local -- cgit v1.2.3-55-g6feb From 56ba0f7b07930ec827328a139e8cf5c25d64d428 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Wed, 24 May 2023 21:10:25 +0200 Subject: Style fixes --- src/dlfcn.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/dlfcn.c b/src/dlfcn.c index be6e01f..749c35f 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -710,11 +710,11 @@ static BOOL is_valid_address( const void *addr ) } #if defined(_M_ARM64) || defined(__aarch64__) -static INT64 sign_extend(UINT64 value, UINT bits) +static INT64 sign_extend( UINT64 value, UINT bits ) { const UINT left = 64 - bits; const INT64 m1 = -1; - const INT64 wide = (INT64) (value << left); + const INT64 wide = (INT64) ( value << left ); const INT64 sign = ( wide < 0 ) ? ( m1 << left ) : 0; return value | sign; @@ -746,16 +746,16 @@ static INT64 sign_extend(UINT64 value, UINT bits) static BOOL is_import_thunk( const void *addr ) { #if defined(_M_ARM64) || defined(__aarch64__) - ULONG opCode1 = * (ULONG *) ( (BYTE *) addr ); - ULONG opCode2 = * (ULONG *) ( (BYTE *) addr + 4 ); - ULONG opCode3 = * (ULONG *) ( (BYTE *) addr + 8 ); + ULONG opCode1 = *(ULONG *) ( (BYTE *) addr ); + ULONG opCode2 = *(ULONG *) ( (BYTE *) addr + 4 ); + ULONG opCode3 = *(ULONG *) ( (BYTE *) addr + 8 ); - return (opCode1 & 0x9f00001f) == 0x90000010 /* adrp x16, [page_offset] */ - && (opCode2 & 0xffe003ff) == 0xf9400210 /* ldr x16, [x16, offset] */ + return ( opCode1 & 0x9f00001f ) == 0x90000010 /* adrp x16, [page_offset] */ + && ( opCode2 & 0xffe003ff ) == 0xf9400210 /* ldr x16, [x16, offset] */ && opCode3 == 0xd61f0200 /* br x16 */ ? TRUE : FALSE; #else - return *(short *) addr == 0x25ff ? TRUE : FALSE; + return *(USHORT *) addr == 0x25ff ? TRUE : FALSE; #endif } @@ -772,16 +772,16 @@ static void *get_address_from_import_address_table( void *iat, DWORD iat_size, c * 0x7ff772ae78c4 <+25764>: ldr x16, [x16, #0xdc0] * 0x7ff772ae78c8 <+25768>: br x16 */ - ULONG opCode1 = * (ULONG *) ( (BYTE *) addr ); - ULONG opCode2 = * (ULONG *) ( (BYTE *) addr + 4 ); + ULONG opCode1 = *(ULONG *) ( (BYTE *) addr ); + ULONG opCode2 = *(ULONG *) ( (BYTE *) addr + 4 ); /* Extract the offset from adrp instruction */ - UINT64 pageLow2 = (opCode1 >> 29) & 3; - UINT64 pageHigh19 = (opCode1 >> 5) & ~(~0ull << 19); - INT64 page = sign_extend((pageHigh19 << 2) | pageLow2, 21) << 12; + UINT64 pageLow2 = ( opCode1 >> 29 ) & 3; + UINT64 pageHigh19 = ( opCode1 >> 5 ) & ~( ~0ull << 19 ); + INT64 page = sign_extend( ( pageHigh19 << 2 ) | pageLow2, 21 ) << 12; /* Extract the offset from ldr instruction */ - UINT64 offset = ((opCode2 >> 10) & ~(~0ull << 12)) << 3; + UINT64 offset = ( ( opCode2 >> 10 ) & ~( ~0ull << 12 ) ) << 3; /* Calculate the final address */ BYTE *ptr = (BYTE *) ( (ULONG64) thkp & ~0xfffull ) + page + offset; @@ -789,7 +789,7 @@ static void *get_address_from_import_address_table( void *iat, DWORD iat_size, c /* Get offset from thunk table (after instruction 0xff 0x25) * 4018c8 <_VirtualQuery>: ff 25 4a 8a 00 00 */ - ULONG offset = *(ULONG *)( thkp + 2 ); + ULONG offset = *(ULONG *) ( thkp + 2 ); #if defined(_M_AMD64) || defined(__x86_64__) /* On 64 bit the offset is relative * 4018c8: ff 25 4a 8a 00 00 jmpq *0x8a4a(%rip) # 40a318 <__imp_VirtualQuery> @@ -797,7 +797,7 @@ static void *get_address_from_import_address_table( void *iat, DWORD iat_size, c * 100002f20: ff 25 3a e1 ff ff jmpq *-0x1ec6(%rip) # 0x100001060 * So cast to signed LONG type */ - BYTE *ptr = (BYTE *)( thkp + 6 + (LONG) offset ); + BYTE *ptr = (BYTE *) ( thkp + 6 + (LONG) offset ); #else /* On 32 bit the offset is absolute * 4019b4: ff 25 90 71 40 00 jmp *0x40719 -- cgit v1.2.3-55-g6feb From c815879efea297cad9d9fbf76baf972d49dd97fa Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Fri, 29 Dec 2023 23:19:48 +0100 Subject: Add proper guards for platform code Do not expect that non-ARM code is automatically X86 code as it does not have to be. Returns failure (not thunk) in other case. Make sure that windows test code is not called on non-windows platforms. Test code tests/test-dladdr.c is written to be validated on any platforms, including non-windows. --- src/dlfcn.c | 8 ++++++-- tests/test-dladdr.c | 9 +++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/dlfcn.c b/src/dlfcn.c index 749c35f..522eed0 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -754,8 +754,10 @@ static BOOL is_import_thunk( const void *addr ) && ( opCode2 & 0xffe003ff ) == 0xf9400210 /* ldr x16, [x16, offset] */ && opCode3 == 0xd61f0200 /* br x16 */ ? TRUE : FALSE; -#else +#elif defined(_M_AMD64) || defined(_M_IX86) || defined(__x86_64__) || defined(__i386__) return *(USHORT *) addr == 0x25ff ? TRUE : FALSE; +#else + return FALSE; #endif } @@ -785,7 +787,7 @@ static void *get_address_from_import_address_table( void *iat, DWORD iat_size, c /* Calculate the final address */ BYTE *ptr = (BYTE *) ( (ULONG64) thkp & ~0xfffull ) + page + offset; -#else +#elif defined(_M_AMD64) || defined(_M_IX86) || defined(__x86_64__) || defined(__i386__) /* Get offset from thunk table (after instruction 0xff 0x25) * 4018c8 <_VirtualQuery>: ff 25 4a 8a 00 00 */ @@ -804,6 +806,8 @@ static void *get_address_from_import_address_table( void *iat, DWORD iat_size, c */ BYTE *ptr = (BYTE *) offset; #endif +#else + return NULL; #endif if( !is_valid_address( ptr ) || ptr < (BYTE *) iat || ptr > (BYTE *) iat + iat_size ) diff --git a/tests/test-dladdr.c b/tests/test-dladdr.c index 5568f23..aa815b0 100644 --- a/tests/test-dladdr.c +++ b/tests/test-dladdr.c @@ -140,6 +140,7 @@ __declspec(dllexport) #endif int main(int argc, char **argv) { +#ifdef _WIN32 #if defined(_M_ARM64) || defined(__aarch64__) /* points to non reachable address */ unsigned char zero_thunk_address[12] = { 0x10, 0x00, 0x00, 0x90, 0x10, 0x02, 0x40, 0xF9, 0x00, 0x02, 0x1F, 0xD6 }; @@ -147,13 +148,16 @@ int main(int argc, char **argv) unsigned char invalid_thunk_address[12] = { 0x10, 0x00, 0x00, 0xb0, 0x10, 0x06, 0x47, 0xF9, 0x00, 0x02, 0x1F, 0xD6 }; /* no import thunk */ unsigned char no_import_thunk[12] = { 0x11, 0x00, 0x00, 0xb0, 0x31, 0x06, 0x47, 0xF9, 0x20, 0x02, 0x1F, 0xD6 }; -#else +#elif defined(_M_AMD64) || defined(_M_IX86) || defined(__x86_64__) || defined(__i386__) /* points to non reachable address */ unsigned char zero_thunk_address[6] = { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; /* points to executable base */ unsigned char invalid_thunk_address[6] = { 0xFF, 0x25, 0x00, 0x00, 0x40, 0x00 }; /* no import thunk */ unsigned char no_import_thunk[6] = { 0xFF, 0x26, 0x00, 0x00, 0x40, 0x00 }; +#else +#error "thunk test cases are not defined for this architecture" +#endif #endif int result = 0; UNUSED(argv); @@ -169,11 +173,12 @@ int main(int argc, char **argv) result |= check_dladdr( "function from executable", (void*)main, "main", Pass ); result |= check_dladdr( "static function from executable", (void*)print_dl_info, "print_dl_info", Fail ); result |= check_dladdr( "address with positive offset", ((char*)atoi)+1, "atoi", PassWithDifferentAddress ); + +#ifdef _WIN32 result |= check_dladdr( "zero address from import thunk", zero_thunk_address, "", NoInfo ); result |= check_dladdr( "invalid address from import thunk", invalid_thunk_address, "", NoInfo ); result |= check_dladdr( "no import thunk", no_import_thunk, "", NoInfo ); -#ifdef _WIN32 result |= check_dladdr( "last entry in iat", (void*)VirtualQuery, "VirtualQuery", PassWithDifferentAddress ); result |= check_dladdr ( "address through import thunk", (void*)GetModuleHandleA, "GetModuleHandleA", PassWithDifferentAddress ); -- cgit v1.2.3-55-g6feb From b5004cdcc136421217e3afc9832fbce3445ddddb Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Fri, 29 Dec 2023 23:20:56 +0100 Subject: Store kernel32.dll handle into kernel32 variable --- src/dlfcn.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/dlfcn.c b/src/dlfcn.c index 522eed0..4b5719f 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -314,6 +314,7 @@ static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD) = NULL; static BOOL failed = FALSE; UINT uMode; + HMODULE kernel32; HMODULE psapi; if( failed ) @@ -322,9 +323,9 @@ static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, if( EnumProcessModulesPtr == NULL ) { /* 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)) (LPVOID) GetProcAddress( psapi, "K32EnumProcessModules" ); + kernel32 = GetModuleHandleA( "Kernel32.dll" ); + if( kernel32 != NULL ) + EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (LPVOID) GetProcAddress( kernel32, "K32EnumProcessModules" ); /* Windows Vista and older version have EnumProcessModules in Psapi.dll which needs to be loaded */ if( EnumProcessModulesPtr == NULL ) @@ -332,13 +333,13 @@ static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, /* Do not let Windows display the critical-error-handler message box */ uMode = MySetErrorMode( SEM_FAILCRITICALERRORS ); psapi = LoadLibraryA( "Psapi.dll" ); + MySetErrorMode( uMode ); if( psapi != NULL ) { EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (LPVOID) GetProcAddress( psapi, "EnumProcessModules" ); if( EnumProcessModulesPtr == NULL ) FreeLibrary( psapi ); } - MySetErrorMode( uMode ); } if( EnumProcessModulesPtr == NULL ) -- cgit v1.2.3-55-g6feb From ce6d045bc3d6f26109f70f8eca0e2b564cc18989 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Mon, 1 Jan 2024 15:36:03 +0100 Subject: Consistently always use GetModuleHandleA() to reduce number of imports --- src/dlfcn.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/dlfcn.c b/src/dlfcn.c index 4b5719f..2bee0fa 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -369,13 +369,13 @@ void *dlopen( const char *file, int mode ) * 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. - * The return value from GetModuleHandle( ) allows us to retrieve + * The return value from GetModuleHandleA( ) allows us to retrieve * symbols only from the original program file. EnumProcessModules() is * used to access symbols from other libraries. For objects loaded * with the RTLD_LOCAL flag, we create our own list later on. They are * excluded from EnumProcessModules() iteration. */ - hModule = GetModuleHandle( NULL ); + hModule = GetModuleHandleA( NULL ); if( !hModule ) save_err_str( "(null)", GetLastError( ) ); @@ -468,7 +468,7 @@ int dlclose( void *handle ) error_occurred = FALSE; /* dlopen(NULL, ...) does not call LoadLibrary(), so do not call FreeLibrary(). */ - if( hModule == GetModuleHandle( NULL ) ) + if( hModule == GetModuleHandleA( NULL ) ) return 0; ret = FreeLibrary( hModule ); @@ -500,7 +500,7 @@ void *dlsym( void *handle, const char *name ) symbol = NULL; hCaller = NULL; - hModule = GetModuleHandle( NULL ); + hModule = GetModuleHandleA( NULL ); dwMessageId = 0; if( handle == RTLD_DEFAULT ) @@ -553,7 +553,7 @@ void *dlsym( void *handle, const char *name ) hCurrentProc = GetCurrentProcess( ); - /* GetModuleHandle( NULL ) only returns the current program file. So + /* GetModuleHandleA( 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 9a2d78ac8768d5623107dc49c091e186354b6efb Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Mon, 26 Feb 2024 22:03:26 +0100 Subject: Fix is_valid_address() function Returned structure is valid only if the function return value is same as the size of the structure. So check for the correct size, not just for the non-zero size. "AllocationProtect" member contains the initial protection, valid at the time when VirtualAlloc() was called. "Protect" member contains the current protection of the requested address, valid at the time when VirtualQuery() was called. So is_valid_address() function has to check "Protect" member, not the "AllocationProtect". If "State" member is MEM_FREE or MEM_RESERVE then "Protect" member is undefined. So check "State" member before "Protect" member. --- src/dlfcn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dlfcn.c b/src/dlfcn.c index 2bee0fa..b3e97d3 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -704,7 +704,7 @@ static BOOL is_valid_address( const void *addr ) /* check valid pointer */ result = VirtualQuery( addr, &info, sizeof( info ) ); - if( result == 0 || info.AllocationBase == NULL || info.AllocationProtect == 0 || info.AllocationProtect == PAGE_NOACCESS ) + if( result != sizeof( info ) || info.AllocationBase == NULL || info.State == MEM_FREE || info.State == MEM_RESERVE || info.Protect == 0 || info.Protect == PAGE_NOACCESS ) return FALSE; return TRUE; -- cgit v1.2.3-55-g6feb From 4fd808d661d88a2ab4ae1dc768f2c8ff0841c8a1 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Fri, 29 Mar 2024 16:00:18 +0100 Subject: Fix gcc compile errors in C++ mode Add missing casts which are required in C++. --- src/dlfcn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dlfcn.c b/src/dlfcn.c index b3e97d3..5219fba 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -291,7 +291,7 @@ static HMODULE MyGetModuleHandleFromAddress( const void *addr ) 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, addr, &hModule ) ) + if( !GetModuleHandleExAPtr( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) addr, &hModule ) ) return NULL; } else @@ -559,7 +559,7 @@ void *dlsym( void *handle, const char *name ) */ if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwSize ) != 0 ) { - modules = malloc( dwSize ); + modules = (HMODULE *) malloc( dwSize ); if( modules ) { if( MyEnumProcessModules( hCurrentProc, modules, dwSize, &cbNeeded ) != 0 && dwSize == cbNeeded ) -- cgit v1.2.3-55-g6feb From 94faff301f529c72a52aa564f8e6829120133d12 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Fri, 29 Mar 2024 16:37:24 +0100 Subject: Fix C++ compile error C2065: '_alloca' : undeclared identifier When compiling in C++ mode, it is required to have C declaration for _alloca. Declaration can be included also via malloc.h header file. --- src/dlfcn.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/dlfcn.c b/src/dlfcn.c index 5219fba..d3a6a22 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -70,7 +70,11 @@ typedef ULONG ULONG_PTR; * EBP register optimization. Read value of EBP + 4 via inline assembly. And * because inline assembly does not have a return value, put it into naked * function which does not have prologue and epilogue and preserve registers. + * When compiling in C++ mode, it is required to have C declaration for _alloca. */ +#ifdef __cplusplus +extern "C" void *__cdecl _alloca(size_t); +#endif __declspec( naked ) static void *_ReturnAddress( void ) { __asm mov eax, [ebp+4] __asm ret } #define _ReturnAddress( ) ( _alloca(1), _ReturnAddress( ) ) #endif -- cgit v1.2.3-55-g6feb From e3568d86334b67111d4a0458ad46abbb82f53f22 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Fri, 29 Mar 2024 18:00:32 +0100 Subject: Fix C++ compile error C2065: '_ReturnAddress' : undeclared identifier It follows compile warning C4164: '_ReturnAddress' : intrinsic function not declared Declaration can be included also via intrin.h header file. --- src/dlfcn.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/dlfcn.c b/src/dlfcn.c index d3a6a22..749710d 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -61,7 +61,12 @@ typedef ULONG ULONG_PTR; #ifdef _MSC_VER #if _MSC_VER >= 1000 -/* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */ +/* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress + * When compiling in C++ mode, it is required to have C declaration for _ReturnAddress. + */ +#ifdef __cplusplus +extern "C" void *_ReturnAddress(void); +#endif #pragma intrinsic( _ReturnAddress ) #else /* On older version read return address from the value on stack pointer + 4 of -- cgit v1.2.3-55-g6feb From 7ce4d24605590e4222eea678403bbf479a432d30 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Fri, 29 Mar 2024 18:02:07 +0100 Subject: Fix test compile error C2065: 'errno' : undeclared identifier For errno usage it is required to include C header file errno.h and do not depend that some other header file will include it. --- tests/test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test.c b/tests/test.c index 1d0d437..4fa7089 100644 --- a/tests/test.c +++ b/tests/test.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "dlfcn.h" /* If these dlclose's fails, we don't care as the handles are going to be -- cgit v1.2.3-55-g6feb From 34238cbb5aabda6f1d9a605cc6ef06a1d831bd25 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Fri, 29 Mar 2024 17:05:06 +0100 Subject: Fix compile warning C4244: '=' : conversion from 'int' to 'char', possible loss of data --- src/dlfcn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dlfcn.c b/src/dlfcn.c index 749710d..9b8a252 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -242,7 +242,7 @@ static void save_err_ptr_str( const void *ptr, DWORD dwMessageId ) for( i = 0; i < 2 * sizeof( ptr ); i++ ) { num = (char) ( ( ( (ULONG_PTR) ptr ) >> ( 8 * sizeof( ptr ) - 4 * ( i + 1 ) ) ) & 0xF ); - ptr_buf[2 + i] = num + ( ( num < 0xA ) ? '0' : ( 'A' - 0xA ) ); + ptr_buf[2 + i] = (char) ( num + ( ( num < 0xA ) ? '0' : ( 'A' - 0xA ) ) ); } ptr_buf[2 + 2 * sizeof( ptr )] = 0; -- cgit v1.2.3-55-g6feb From 5a4d701248f88fb1a6f66932c58d73e74dfadbd9 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Fri, 29 Mar 2024 15:54:23 +0100 Subject: Fix compile warning: comparison of integer expressions of different signedness: ‘int’ and ‘DWORD’ {aka ‘long unsigned int’} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/dlfcn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dlfcn.c b/src/dlfcn.c index 9b8a252..0f9fa38 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -654,7 +654,7 @@ static BOOL get_image_section( HMODULE module, int index, void **ptr, DWORD *siz if( optionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC ) return FALSE; - if( index < 0 || index >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES || index >= optionalHeader->NumberOfRvaAndSizes ) + if( index < 0 || index >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES || (DWORD)index >= optionalHeader->NumberOfRvaAndSizes ) return FALSE; if( optionalHeader->DataDirectory[index].Size == 0 || optionalHeader->DataDirectory[index].VirtualAddress == 0 ) -- cgit v1.2.3-55-g6feb From e0520e25643b51e69aa78e5944cdf2853323b06a Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Mon, 16 Sep 2024 23:59:06 +0200 Subject: Do not cast between function pointer and data pointer when not required This is undefined in C and also C++. Both gcc and msvc allows to cast between two incompatible function pointers without triggering warnings transitionally via void(*)(void) function pointer. Replace transitional LPVOID cast by void(*)(void) cast. --- src/dlfcn.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dlfcn.c b/src/dlfcn.c index 0f9fa38..2711e60 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -261,7 +261,7 @@ static UINT MySetErrorMode( UINT uMode ) { kernel32 = GetModuleHandleA( "Kernel32.dll" ); if( kernel32 != NULL ) - SetThreadErrorModePtr = (BOOL (WINAPI *)(DWORD, DWORD *)) (LPVOID) GetProcAddress( kernel32, "SetThreadErrorMode" ); + SetThreadErrorModePtr = (BOOL (WINAPI *)(DWORD, DWORD *)) (void(*)(void)) GetProcAddress( kernel32, "SetThreadErrorMode" ); if( SetThreadErrorModePtr == NULL ) failed = TRUE; } @@ -292,7 +292,7 @@ static HMODULE MyGetModuleHandleFromAddress( const void *addr ) { kernel32 = GetModuleHandleA( "Kernel32.dll" ); if( kernel32 != NULL ) - GetModuleHandleExAPtr = (BOOL (WINAPI *)(DWORD, LPCSTR, HMODULE *)) (LPVOID) GetProcAddress( kernel32, "GetModuleHandleExA" ); + GetModuleHandleExAPtr = (BOOL (WINAPI *)(DWORD, LPCSTR, HMODULE *)) (void(*)(void)) GetProcAddress( kernel32, "GetModuleHandleExA" ); if( GetModuleHandleExAPtr == NULL ) failed = TRUE; } @@ -334,7 +334,7 @@ static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, /* Windows 7 and newer versions have K32EnumProcessModules in Kernel32.dll which is always pre-loaded */ kernel32 = GetModuleHandleA( "Kernel32.dll" ); if( kernel32 != NULL ) - EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (LPVOID) GetProcAddress( kernel32, "K32EnumProcessModules" ); + EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (void(*)(void)) GetProcAddress( kernel32, "K32EnumProcessModules" ); /* Windows Vista and older version have EnumProcessModules in Psapi.dll which needs to be loaded */ if( EnumProcessModulesPtr == NULL ) @@ -345,7 +345,7 @@ static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, MySetErrorMode( uMode ); if( psapi != NULL ) { - EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (LPVOID) GetProcAddress( psapi, "EnumProcessModules" ); + EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (void(*)(void)) GetProcAddress( psapi, "EnumProcessModules" ); if( EnumProcessModulesPtr == NULL ) FreeLibrary( psapi ); } -- cgit v1.2.3-55-g6feb From 8c28ff3b85f87ae9cb645fed9ec2d146b3059e7a Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Fri, 22 Mar 2024 01:35:52 +0100 Subject: Fix includes * Remove unused include stdio.h * Add used include string.h * Add reason comments for includes --- src/dlfcn.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dlfcn.c b/src/dlfcn.c index 2711e60..d52d736 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -26,12 +26,12 @@ #ifdef _DEBUG #define _CRTDBG_MAP_ALLOC -#include +#include /* malloc() and free() */ #include #endif #include -#include -#include +#include /* malloc() and free() */ +#include /* strlen() and memcpy() */ /* Older versions do not have this type */ #if _WIN32_WINNT < 0x0500 -- cgit v1.2.3-55-g6feb From f87cc876be9b450d3491a174b8c673d918ec5daf Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Fri, 22 Mar 2024 01:53:18 +0100 Subject: Replace CRT's malloc() and free() by WinAPI's LocalAlloc() and LocalFree() in release mode In debug mode is still used malloc() and free() for as part of memory leak testing done by _CRTDBG_MAP_ALLOC and _CrtDumpMemoryLeaks() in test.c. This change allows to wrap CRT's malloc() via dlsym's RTLD_NEXT. See #112 --- src/dlfcn.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/dlfcn.c b/src/dlfcn.c index d52d736..be66cac 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -30,7 +30,6 @@ #include #endif #include -#include /* malloc() and free() */ #include /* strlen() and memcpy() */ /* Older versions do not have this type */ @@ -105,6 +104,24 @@ __declspec( naked ) static void *_ReturnAddress( void ) { __asm mov eax, [ebp+4] #define DLFCN_NOINLINE #endif +static void *MyAlloc( size_t size ) +{ +#ifdef _DEBUG + return malloc( size ); +#else + return LocalAlloc( LPTR, size ); +#endif +} + +static void MyFree( void *ptr ) +{ +#ifdef _DEBUG + free( ptr ); +#else + LocalFree( ptr ); +#endif +} + /* Note: * MSDN says these functions are not thread-safe. We make no efforts to have * any kind of thread safety. @@ -149,7 +166,7 @@ static BOOL local_add( HMODULE hModule ) for( pobject = &first_object; pobject->next; pobject = pobject->next ); - nobject = (local_object *) malloc( sizeof( local_object ) ); + nobject = (local_object *) MyAlloc( sizeof( local_object ) ); if( !nobject ) return FALSE; @@ -179,7 +196,7 @@ static void local_rem( HMODULE hModule ) if( pobject->previous ) pobject->previous->next = pobject->next; - free( pobject ); + MyFree( pobject ); } /* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one @@ -568,7 +585,7 @@ void *dlsym( void *handle, const char *name ) */ if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwSize ) != 0 ) { - modules = (HMODULE *) malloc( dwSize ); + modules = (HMODULE *) MyAlloc( dwSize ); if( modules ) { if( MyEnumProcessModules( hCurrentProc, modules, dwSize, &cbNeeded ) != 0 && dwSize == cbNeeded ) @@ -587,13 +604,13 @@ void *dlsym( void *handle, const char *name ) symbol = GetProcAddress( modules[i], name ); if( symbol != NULL ) { - free( modules ); + MyFree( modules ); goto end; } } } - free( modules ); + MyFree( modules ); } else { -- cgit v1.2.3-55-g6feb From 3e9bfa7d9dd0e8f4a846d45261df1dcb838b60d8 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Fri, 29 Mar 2024 15:52:29 +0100 Subject: Replace CRT's strlen() and memcpy() by open coded variants After this change there is no usage of of CRT library function. This allows to build CRT-neutral variant of libdl.dll library, which can be used in any application. --- src/dlfcn.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/dlfcn.c b/src/dlfcn.c index be66cac..1830b20 100644 --- a/src/dlfcn.c +++ b/src/dlfcn.c @@ -30,7 +30,6 @@ #include #endif #include -#include /* strlen() and memcpy() */ /* Older versions do not have this type */ #if _WIN32_WINNT < 0x0500 @@ -210,19 +209,15 @@ static BOOL error_occurred; static void save_err_str( const char *str, DWORD dwMessageId ) { DWORD ret; - size_t pos, len; - - len = strlen( str ); - if( len > sizeof( error_buffer ) - 5 ) - len = sizeof( error_buffer ) - 5; + size_t pos, i; /* Format error message to: * "": */ pos = 0; error_buffer[pos++] = '"'; - memcpy( error_buffer + pos, str, len ); - pos += len; + for( i = 0; i < sizeof( error_buffer ) - 5 && str[i] != '\0'; i++ ) + error_buffer[pos++] = str[i]; error_buffer[pos++] = '"'; error_buffer[pos++] = ':'; error_buffer[pos++] = ' '; @@ -413,7 +408,11 @@ void *dlopen( const char *file, int mode ) char lpFileName[MAX_PATH]; size_t i, len; - len = strlen( file ); + for( len = 0; ; len++ ) + { + if( file[len] == '\0' ) + break; + } if( len >= sizeof( lpFileName ) ) { -- cgit v1.2.3-55-g6feb From 7989e4dc4fa1dc31b4c353c72b092209a773c78f Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Fri, 29 Mar 2024 19:59:43 +0100 Subject: Do not install test file --- tests/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cd321f2..1fe7387 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -31,6 +31,4 @@ if(WIN32 AND NOT BUILD_SHARED_LIBS) endif() endif() -install(TARGETS test-dladdr EXPORT dlfcn-win32-targets RUNTIME DESTINATION bin) - add_test(NAME test-dladdr COMMAND test-dladdr WORKING_DIRECTORY $) -- cgit v1.2.3-55-g6feb