aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--Makefile7
-rw-r--r--cmake-test/CMakeLists.txt2
-rw-r--r--dlfcn.c180
-rw-r--r--test.c27
-rw-r--r--testdll3.c38
6 files changed, 144 insertions, 112 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 48945b2..a13cf99 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -63,6 +63,8 @@ if (BUILD_TESTS)
63 enable_testing() 63 enable_testing()
64 add_library(testdll SHARED testdll.c) 64 add_library(testdll SHARED testdll.c)
65 set_target_properties(testdll PROPERTIES PREFIX "") 65 set_target_properties(testdll PROPERTIES PREFIX "")
66 add_library(testdll3 SHARED testdll3.c)
67 set_target_properties(testdll3 PROPERTIES PREFIX "")
66 add_executable(t_dlfcn test.c) 68 add_executable(t_dlfcn test.c)
67 target_link_libraries(t_dlfcn dl) 69 target_link_libraries(t_dlfcn dl)
68 add_test (NAME t_dlfcn COMMAND t_dlfcn) 70 add_test (NAME t_dlfcn COMMAND t_dlfcn)
diff --git a/Makefile b/Makefile
index c02dce0..a0f5cb9 100644
--- a/Makefile
+++ b/Makefile
@@ -66,7 +66,10 @@ test.exe: test.o $(TARGETS)
66testdll.dll: testdll.c 66testdll.dll: testdll.c
67 $(CC) -shared -o $@ $^ 67 $(CC) -shared -o $@ $^
68 68
69test: $(TARGETS) test.exe testdll.dll 69testdll3.dll: testdll3.c
70 $(CC) -shared -o $@ $^
71
72test: $(TARGETS) test.exe testdll.dll testdll3.dll
70 $(WINE) test.exe 73 $(WINE) test.exe
71 74
72clean:: 75clean::
@@ -74,7 +77,7 @@ clean::
74 dlfcn.o \ 77 dlfcn.o \
75 libdl.dll libdl.a libdl.def libdl.dll.a libdl.lib libdl.exp \ 78 libdl.dll libdl.a libdl.def libdl.dll.a libdl.lib libdl.exp \
76 tmptest.c tmptest.dll \ 79 tmptest.c tmptest.dll \
77 test.exe testdll.dll 80 test.exe testdll.dll testdll3.dll
78 81
79distclean: clean 82distclean: clean
80 rm -f config.mak 83 rm -f config.mak
diff --git a/cmake-test/CMakeLists.txt b/cmake-test/CMakeLists.txt
index 532f2b8..b853920 100644
--- a/cmake-test/CMakeLists.txt
+++ b/cmake-test/CMakeLists.txt
@@ -8,6 +8,8 @@ find_package(dlfcn-win32 REQUIRED)
8 8
9add_library(testdll SHARED ../testdll.c) 9add_library(testdll SHARED ../testdll.c)
10set_target_properties(testdll PROPERTIES PREFIX "") 10set_target_properties(testdll PROPERTIES PREFIX "")
11add_library(testdll3 SHARED ../testdll3.c)
12set_target_properties(testdll3 PROPERTIES PREFIX "")
11add_executable(t_dlfcn ../test.c) 13add_executable(t_dlfcn ../test.c)
12target_link_libraries(t_dlfcn dlfcn-win32::dl) 14target_link_libraries(t_dlfcn dlfcn-win32::dl)
13enable_testing() 15enable_testing()
diff --git a/dlfcn.c b/dlfcn.c
index b356558..1e706f0 100644
--- a/dlfcn.c
+++ b/dlfcn.c
@@ -2,6 +2,7 @@
2 * dlfcn-win32 2 * dlfcn-win32
3 * Copyright (c) 2007 Ramiro Polla 3 * Copyright (c) 2007 Ramiro Polla
4 * Copyright (c) 2015 Tiancheng "Timothy" Gu 4 * Copyright (c) 2015 Tiancheng "Timothy" Gu
5 * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com>
5 * 6 *
6 * dlfcn-win32 is free software; you can redistribute it and/or 7 * dlfcn-win32 is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public 8 * modify it under the terms of the GNU Lesser General Public
@@ -52,57 +53,48 @@
52 * any kind of thread safety. 53 * any kind of thread safety.
53 */ 54 */
54 55
55typedef struct global_object { 56typedef struct local_object {
56 HMODULE hModule; 57 HMODULE hModule;
57 struct global_object *previous; 58 struct local_object *previous;
58 struct global_object *next; 59 struct local_object *next;
59} global_object; 60} local_object;
60 61
61static global_object first_object; 62static local_object first_object;
62static global_object first_automatic_object;
63static int auto_ref_count = 0;
64 63
65/* These functions implement a double linked list for the global objects. */ 64/* These functions implement a double linked list for the local objects. */
66static global_object *global_search( global_object *start, HMODULE hModule ) 65static local_object *local_search( HMODULE hModule )
67{ 66{
68 global_object *pobject; 67 local_object *pobject;
69 68
70 if( hModule == NULL ) 69 if( hModule == NULL )
71 return NULL; 70 return NULL;
72 71
73 for( pobject = start; pobject; pobject = pobject->next ) 72 for( pobject = &first_object; pobject; pobject = pobject->next )
74 if( pobject->hModule == hModule ) 73 if( pobject->hModule == hModule )
75 return pobject; 74 return pobject;
76 75
77 return NULL; 76 return NULL;
78} 77}
79 78
80static void global_add( global_object *start, HMODULE hModule ) 79static void local_add( HMODULE hModule )
81{ 80{
82 global_object *pobject; 81 local_object *pobject;
83 global_object *nobject; 82 local_object *nobject;
84 83
85 if( hModule == NULL ) 84 if( hModule == NULL )
86 return; 85 return;
87 86
88 pobject = global_search( start, hModule ); 87 pobject = local_search( hModule );
89 88
90 /* Do not add object again if it's already on the list */ 89 /* Do not add object again if it's already on the list */
91 if( pobject ) 90 if( pobject )
92 return; 91 return;
93 92
94 if( start == &first_automatic_object ) 93 for( pobject = &first_object; pobject->next; pobject = pobject->next );
95 {
96 pobject = global_search( &first_object, hModule );
97 if( pobject )
98 return;
99 }
100
101 for( pobject = start; pobject->next; pobject = pobject->next );
102 94
103 nobject = (global_object*) malloc( sizeof( global_object ) ); 95 nobject = (local_object*) malloc( sizeof( local_object ) );
104 96
105 /* Should this be enough to fail global_add, and therefore also fail 97 /* Should this be enough to fail local_add, and therefore also fail
106 * dlopen? 98 * dlopen?
107 */ 99 */
108 if( !nobject ) 100 if( !nobject )
@@ -114,14 +106,14 @@ static void global_add( global_object *start, HMODULE hModule )
114 nobject->hModule = hModule; 106 nobject->hModule = hModule;
115} 107}
116 108
117static void global_rem( global_object *start, HMODULE hModule ) 109static void local_rem( HMODULE hModule )
118{ 110{
119 global_object *pobject; 111 local_object *pobject;
120 112
121 if( hModule == NULL ) 113 if( hModule == NULL )
122 return; 114 return;
123 115
124 pobject = global_search( start, hModule ); 116 pobject = local_search( hModule );
125 117
126 if( !pobject ) 118 if( !pobject )
127 return; 119 return;
@@ -224,10 +216,6 @@ void *dlopen( const char *file, int mode )
224 216
225 if( file == 0 ) 217 if( file == 0 )
226 { 218 {
227 HMODULE hAddtnlMods[1024]; // Already loaded modules
228 HANDLE hCurrentProc = GetCurrentProcess( );
229 DWORD cbNeeded;
230
231 /* POSIX says that if the value of file is 0, a handle on a global 219 /* POSIX says that if the value of file is 0, a handle on a global
232 * symbol object must be provided. That object must be able to access 220 * symbol object must be provided. That object must be able to access
233 * all symbols from the original program file, and any objects loaded 221 * all symbols from the original program file, and any objects loaded
@@ -242,27 +230,13 @@ void *dlopen( const char *file, int mode )
242 230
243 if( !hModule ) 231 if( !hModule )
244 save_err_ptr_str( file ); 232 save_err_ptr_str( file );
245
246
247 /* GetModuleHandle( NULL ) only returns the current program file. So
248 * if we want to get ALL loaded module including those in linked DLLs,
249 * we have to use EnumProcessModules( ).
250 */
251 if( EnumProcessModules( hCurrentProc, hAddtnlMods,
252 sizeof( hAddtnlMods ), &cbNeeded ) != 0 )
253 {
254 DWORD i;
255 for( i = 0; i < cbNeeded / sizeof( HMODULE ); i++ )
256 {
257 global_add( &first_automatic_object, hAddtnlMods[i] );
258 }
259 }
260 auto_ref_count++;
261 } 233 }
262 else 234 else
263 { 235 {
236 HANDLE hCurrentProc;
237 DWORD dwProcModsBefore, dwProcModsAfter;
264 CHAR lpFileName[MAX_PATH]; 238 CHAR lpFileName[MAX_PATH];
265 int i; 239 size_t i;
266 240
267 /* MSDN says backslashes *must* be used instead of forward slashes. */ 241 /* MSDN says backslashes *must* be used instead of forward slashes. */
268 for( i = 0 ; i < sizeof(lpFileName) - 1 ; i ++ ) 242 for( i = 0 ; i < sizeof(lpFileName) - 1 ; i ++ )
@@ -276,6 +250,11 @@ void *dlopen( const char *file, int mode )
276 } 250 }
277 lpFileName[i] = '\0'; 251 lpFileName[i] = '\0';
278 252
253 hCurrentProc = GetCurrentProcess( );
254
255 if( EnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsBefore ) == 0 )
256 dwProcModsBefore = 0;
257
279 /* POSIX says the search path is implementation-defined. 258 /* POSIX says the search path is implementation-defined.
280 * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely 259 * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely
281 * to UNIX's search paths (start with system folders instead of current 260 * to UNIX's search paths (start with system folders instead of current
@@ -284,17 +263,24 @@ void *dlopen( const char *file, int mode )
284 hModule = LoadLibraryEx(lpFileName, NULL, 263 hModule = LoadLibraryEx(lpFileName, NULL,
285 LOAD_WITH_ALTERED_SEARCH_PATH ); 264 LOAD_WITH_ALTERED_SEARCH_PATH );
286 265
287 /* If the object was loaded with RTLD_GLOBAL, add it to list of global 266 if( EnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 )
288 * objects, so that its symbols may be retrieved even if the handle for 267 dwProcModsAfter = 0;
268
269 /* If the object was loaded with RTLD_LOCAL, add it to list of local
270 * objects, so that its symbols cannot be retrieved even if the handle for
289 * the original program file is passed. POSIX says that if the same 271 * the original program file is passed. POSIX says that if the same
290 * file is specified in multiple invocations, and any of them are 272 * file is specified in multiple invocations, and any of them are
291 * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the 273 * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the
292 * symbols will remain global. 274 * symbols will remain global. If number of loaded modules was not
275 * changed after calling LoadLibraryEx(), it means that library was
276 * already loaded.
293 */ 277 */
294 if( !hModule ) 278 if( !hModule )
295 save_err_str( lpFileName ); 279 save_err_str( lpFileName );
296 else if( (mode & RTLD_GLOBAL) ) 280 else if( (mode & RTLD_LOCAL) && dwProcModsBefore != dwProcModsAfter )
297 global_add( &first_object, hModule ); 281 local_add( hModule );
282 else if( !(mode & RTLD_LOCAL) && dwProcModsBefore == dwProcModsAfter )
283 local_rem( hModule );
298 } 284 }
299 285
300 /* Return to previous state of the error-mode bit flags. */ 286 /* Return to previous state of the error-mode bit flags. */
@@ -303,21 +289,6 @@ void *dlopen( const char *file, int mode )
303 return (void *) hModule; 289 return (void *) hModule;
304} 290}
305 291
306static void free_auto( )
307{
308 global_object *pobject = first_automatic_object.next;
309 if( pobject )
310 {
311 global_object *next;
312 for ( ; pobject; pobject = next )
313 {
314 next = pobject->next;
315 free( pobject );
316 }
317 first_automatic_object.next = NULL;
318 }
319}
320
321int dlclose( void *handle ) 292int dlclose( void *handle )
322{ 293{
323 HMODULE hModule = (HMODULE) handle; 294 HMODULE hModule = (HMODULE) handle;
@@ -327,22 +298,11 @@ int dlclose( void *handle )
327 298
328 ret = FreeLibrary( hModule ); 299 ret = FreeLibrary( hModule );
329 300
330 /* If the object was loaded with RTLD_GLOBAL, remove it from list of global 301 /* If the object was loaded with RTLD_LOCAL, remove it from list of local
331 * objects. 302 * objects.
332 */ 303 */
333 if( ret ) 304 if( ret )
334 { 305 local_rem( hModule );
335 HMODULE cur = GetModuleHandle( NULL );
336 global_rem( &first_object, hModule );
337 if( hModule == cur )
338 {
339 auto_ref_count--;
340 if( auto_ref_count < 0 )
341 auto_ref_count = 0;
342 if( !auto_ref_count )
343 free_auto( );
344 }
345 }
346 else 306 else
347 save_err_ptr_str( handle ); 307 save_err_ptr_str( handle );
348 308
@@ -356,6 +316,7 @@ void *dlsym( void *handle, const char *name )
356{ 316{
357 FARPROC symbol; 317 FARPROC symbol;
358 HMODULE hModule; 318 HMODULE hModule;
319 HANDLE hCurrentProc;
359 320
360#ifdef UNICODE 321#ifdef UNICODE
361 wchar_t namew[MAX_PATH]; 322 wchar_t namew[MAX_PATH];
@@ -363,6 +324,7 @@ void *dlsym( void *handle, const char *name )
363#endif 324#endif
364 325
365 current_error = NULL; 326 current_error = NULL;
327 hCurrentProc = GetCurrentProcess( );
366 328
367 symbol = GetProcAddress( (HMODULE) handle, name ); 329 symbol = GetProcAddress( (HMODULE) handle, name );
368 330
@@ -377,25 +339,33 @@ void *dlsym( void *handle, const char *name )
377 339
378 if( hModule == handle ) 340 if( hModule == handle )
379 { 341 {
380 global_object *pobject; 342 HMODULE *modules;
381 343 DWORD cbNeeded;
382 for( pobject = &first_object; pobject; pobject = pobject->next ) 344 DWORD dwSize;
383 { 345 size_t i;
384 if( pobject->hModule )
385 {
386 symbol = GetProcAddress( pobject->hModule, name );
387 if( symbol != NULL )
388 goto end;
389 }
390 }
391 346
392 for( pobject = &first_automatic_object; pobject; pobject = pobject->next ) 347 /* GetModuleHandle( NULL ) only returns the current program file. So
348 * if we want to get ALL loaded module including those in linked DLLs,
349 * we have to use EnumProcessModules( ).
350 */
351 if( EnumProcessModules( hCurrentProc, NULL, 0, &dwSize ) != 0 )
393 { 352 {
394 if( pobject->hModule ) 353 modules = malloc( dwSize );
354 if( modules )
395 { 355 {
396 symbol = GetProcAddress( pobject->hModule, name ); 356 if( EnumProcessModules( hCurrentProc, modules, dwSize, &cbNeeded ) != 0 && dwSize == cbNeeded )
397 if( symbol != NULL ) 357 {
398 goto end; 358 for( i = 0; i < dwSize / sizeof( HMODULE ); i++ )
359 {
360 if( local_search( modules[i] ) )
361 continue;
362 symbol = GetProcAddress( modules[i], name );
363 if( symbol != NULL )
364 goto end;
365 }
366
367 }
368 free( modules );
399 } 369 }
400 } 370 }
401 } 371 }
@@ -472,18 +442,8 @@ char *dlerror( void )
472BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) 442BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
473{ 443{
474 (void) hinstDLL; 444 (void) hinstDLL;
475 /* 445 (void) fdwReason;
476 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx 446 (void) lpvReserved;
477 *
478 * When handling DLL_PROCESS_DETACH, a DLL should free resources such as heap
479 * memory only if the DLL is being unloaded dynamically (the lpReserved
480 * parameter is NULL).
481 */
482 if( fdwReason == DLL_PROCESS_DETACH && !lpvReserved )
483 {
484 auto_ref_count = 0;
485 free_auto( );
486 }
487 return TRUE; 447 return TRUE;
488} 448}
489#endif 449#endif
diff --git a/test.c b/test.c
index ba440da..10c655e 100644
--- a/test.c
+++ b/test.c
@@ -2,6 +2,7 @@
2 * dlfcn-win32 2 * dlfcn-win32
3 * Copyright (c) 2007-2009 Ramiro Polla 3 * Copyright (c) 2007-2009 Ramiro Polla
4 * Copyright (c) 2014 Tiancheng "Timothy" Gu 4 * Copyright (c) 2014 Tiancheng "Timothy" Gu
5 * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com>
5 * 6 *
6 * dlfcn-win32 is free software; you can redistribute it and/or 7 * dlfcn-win32 is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public 8 * modify it under the terms of the GNU Lesser General Public
@@ -25,6 +26,7 @@
25#endif 26#endif
26#include <stdio.h> 27#include <stdio.h>
27#include <string.h> 28#include <string.h>
29#include <windows.h>
28#include "dlfcn.h" 30#include "dlfcn.h"
29 31
30/* If these dlclose's fails, we don't care as the handles are going to be 32/* If these dlclose's fails, we don't care as the handles are going to be
@@ -77,6 +79,7 @@ int main()
77 size_t (*fwrite_local) ( const void *, size_t, size_t, FILE * ); 79 size_t (*fwrite_local) ( const void *, size_t, size_t, FILE * );
78 int (*nonexistentfunction)( void ); 80 int (*nonexistentfunction)( void );
79 int ret; 81 int ret;
82 HMODULE library3;
80 83
81#ifdef _DEBUG 84#ifdef _DEBUG
82 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); 85 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
@@ -335,6 +338,15 @@ int main()
335 printf("SUCCESS\tGot symbol from global handle: %p\n", function); 338 printf("SUCCESS\tGot symbol from global handle: %p\n", function);
336 339
337 340
341 library3 = LoadLibraryA("testdll3.dll");
342 if (!library3)
343 {
344 printf( "ERROR\tCould not open library3 via WINAPI\n" );
345 RETURN_ERROR;
346 }
347 else
348 printf( "SUCCESS\tOpened library3 via WINAPI: %p\n", library3 );
349
338 ret = dlclose( library ); 350 ret = dlclose( library );
339 if( ret ) 351 if( ret )
340 { 352 {
@@ -346,6 +358,21 @@ int main()
346 else 358 else
347 printf( "SUCCESS\tClosed library.\n" ); 359 printf( "SUCCESS\tClosed library.\n" );
348 360
361 function = dlsym(global, "function3");
362 if (!function)
363 {
364 error = dlerror();
365 printf("ERROR\tCould not get symbol from global handle: %s\n",
366 error ? error : "");
367 CLOSE_LIB;
368 CLOSE_GLOBAL;
369 RETURN_ERROR;
370 }
371 else
372 printf("SUCCESS\tGot symbol from global handle: %p\n", function);
373
374 RUNFUNC;
375
349 ret = dlclose( global ); 376 ret = dlclose( global );
350 if( ret ) 377 if( ret )
351 { 378 {
diff --git a/testdll3.c b/testdll3.c
new file mode 100644
index 0000000..3906e48
--- /dev/null
+++ b/testdll3.c
@@ -0,0 +1,38 @@
1/*
2 * dlfcn-win32
3 * Copyright (c) 2007 Ramiro Polla
4 * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com>
5 *
6 * dlfcn-win32 is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * dlfcn-win32 is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with dlfcn-win32; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#ifdef _DEBUG
22#define _CRTDBG_MAP_ALLOC
23#include <stdlib.h>
24#include <crtdbg.h>
25#endif
26#include <stdio.h>
27
28#if defined(_WIN32)
29#define EXPORT __declspec(dllexport)
30#else
31#define EXPORT
32#endif
33
34EXPORT int function3( void )
35{
36 printf( "Hello, world!\n" );
37 return 0;
38}