diff options
Diffstat (limited to 'dlfcn.c')
-rw-r--r-- | dlfcn.c | 127 |
1 files changed, 80 insertions, 47 deletions
@@ -72,34 +72,36 @@ static local_object *local_search( HMODULE hModule ) | |||
72 | return NULL; | 72 | return NULL; |
73 | } | 73 | } |
74 | 74 | ||
75 | static void local_add( HMODULE hModule ) | 75 | static BOOL local_add( HMODULE hModule ) |
76 | { | 76 | { |
77 | local_object *pobject; | 77 | local_object *pobject; |
78 | local_object *nobject; | 78 | local_object *nobject; |
79 | 79 | ||
80 | if( hModule == NULL ) | 80 | if( hModule == NULL ) |
81 | return; | 81 | return TRUE; |
82 | 82 | ||
83 | pobject = local_search( hModule ); | 83 | pobject = local_search( hModule ); |
84 | 84 | ||
85 | /* Do not add object again if it's already on the list */ | 85 | /* Do not add object again if it's already on the list */ |
86 | if( pobject ) | 86 | if( pobject ) |
87 | return; | 87 | return TRUE; |
88 | 88 | ||
89 | for( pobject = &first_object; pobject->next; pobject = pobject->next ); | 89 | for( pobject = &first_object; pobject->next; pobject = pobject->next ); |
90 | 90 | ||
91 | nobject = (local_object*) malloc( sizeof( local_object ) ); | 91 | nobject = (local_object*) malloc( sizeof( local_object ) ); |
92 | 92 | ||
93 | /* Should this be enough to fail local_add, and therefore also fail | ||
94 | * dlopen? | ||
95 | */ | ||
96 | if( !nobject ) | 93 | if( !nobject ) |
97 | return; | 94 | { |
95 | SetLastError( ERROR_NOT_ENOUGH_MEMORY ); | ||
96 | return FALSE; | ||
97 | } | ||
98 | 98 | ||
99 | pobject->next = nobject; | 99 | pobject->next = nobject; |
100 | nobject->next = NULL; | 100 | nobject->next = NULL; |
101 | nobject->previous = pobject; | 101 | nobject->previous = pobject; |
102 | nobject->hModule = hModule; | 102 | nobject->hModule = hModule; |
103 | |||
104 | return TRUE; | ||
103 | } | 105 | } |
104 | 106 | ||
105 | static void local_rem( HMODULE hModule ) | 107 | static void local_rem( HMODULE hModule ) |
@@ -240,51 +242,73 @@ void *dlopen( const char *file, int mode ) | |||
240 | HANDLE hCurrentProc; | 242 | HANDLE hCurrentProc; |
241 | DWORD dwProcModsBefore, dwProcModsAfter; | 243 | DWORD dwProcModsBefore, dwProcModsAfter; |
242 | char lpFileName[MAX_PATH]; | 244 | char lpFileName[MAX_PATH]; |
243 | size_t i; | 245 | size_t i, len; |
244 | 246 | ||
245 | /* MSDN says backslashes *must* be used instead of forward slashes. */ | 247 | len = strlen( file ); |
246 | for( i = 0 ; i < sizeof(lpFileName) - 1 ; i ++ ) | 248 | |
249 | if( len >= sizeof( lpFileName ) ) | ||
247 | { | 250 | { |
248 | if( !file[i] ) | 251 | SetLastError( ERROR_FILENAME_EXCED_RANGE ); |
249 | break; | 252 | save_err_str( file ); |
250 | else if( file[i] == '/' ) | 253 | hModule = NULL; |
251 | lpFileName[i] = '\\'; | ||
252 | else | ||
253 | lpFileName[i] = file[i]; | ||
254 | } | 254 | } |
255 | lpFileName[i] = '\0'; | 255 | else |
256 | { | ||
257 | /* MSDN says backslashes *must* be used instead of forward slashes. */ | ||
258 | for( i = 0; i < len; i++ ) | ||
259 | { | ||
260 | if( file[i] == '/' ) | ||
261 | lpFileName[i] = '\\'; | ||
262 | else | ||
263 | lpFileName[i] = file[i]; | ||
264 | } | ||
265 | lpFileName[len] = '\0'; | ||
256 | 266 | ||
257 | hCurrentProc = GetCurrentProcess( ); | 267 | hCurrentProc = GetCurrentProcess( ); |
258 | 268 | ||
259 | if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsBefore ) == 0 ) | 269 | if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsBefore ) == 0 ) |
260 | dwProcModsBefore = 0; | 270 | dwProcModsBefore = 0; |
261 | 271 | ||
262 | /* POSIX says the search path is implementation-defined. | 272 | /* POSIX says the search path is implementation-defined. |
263 | * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely | 273 | * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely |
264 | * to UNIX's search paths (start with system folders instead of current | 274 | * to UNIX's search paths (start with system folders instead of current |
265 | * folder). | 275 | * folder). |
266 | */ | 276 | */ |
267 | hModule = LoadLibraryExA(lpFileName, NULL, | 277 | hModule = LoadLibraryExA( lpFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH ); |
268 | LOAD_WITH_ALTERED_SEARCH_PATH ); | 278 | |
269 | 279 | if( !hModule ) | |
270 | if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 ) | 280 | { |
271 | dwProcModsAfter = 0; | 281 | save_err_str( lpFileName ); |
272 | 282 | } | |
273 | /* If the object was loaded with RTLD_LOCAL, add it to list of local | 283 | else |
274 | * objects, so that its symbols cannot be retrieved even if the handle for | 284 | { |
275 | * the original program file is passed. POSIX says that if the same | 285 | if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 ) |
276 | * file is specified in multiple invocations, and any of them are | 286 | dwProcModsAfter = 0; |
277 | * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the | 287 | |
278 | * symbols will remain global. If number of loaded modules was not | 288 | /* If the object was loaded with RTLD_LOCAL, add it to list of local |
279 | * changed after calling LoadLibraryEx(), it means that library was | 289 | * objects, so that its symbols cannot be retrieved even if the handle for |
280 | * already loaded. | 290 | * the original program file is passed. POSIX says that if the same |
281 | */ | 291 | * file is specified in multiple invocations, and any of them are |
282 | if( !hModule ) | 292 | * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the |
283 | save_err_str( lpFileName ); | 293 | * symbols will remain global. If number of loaded modules was not |
284 | else if( (mode & RTLD_LOCAL) && dwProcModsBefore != dwProcModsAfter ) | 294 | * changed after calling LoadLibraryEx(), it means that library was |
285 | local_add( hModule ); | 295 | * already loaded. |
286 | else if( !(mode & RTLD_LOCAL) && dwProcModsBefore == dwProcModsAfter ) | 296 | */ |
287 | local_rem( hModule ); | 297 | if( (mode & RTLD_LOCAL) && dwProcModsBefore != dwProcModsAfter ) |
298 | { | ||
299 | if( !local_add( hModule ) ) | ||
300 | { | ||
301 | save_err_str( lpFileName ); | ||
302 | FreeLibrary( hModule ); | ||
303 | hModule = NULL; | ||
304 | } | ||
305 | } | ||
306 | else if( !(mode & RTLD_LOCAL) && dwProcModsBefore == dwProcModsAfter ) | ||
307 | { | ||
308 | local_rem( hModule ); | ||
309 | } | ||
310 | } | ||
311 | } | ||
288 | } | 312 | } |
289 | 313 | ||
290 | /* Return to previous state of the error-mode bit flags. */ | 314 | /* Return to previous state of the error-mode bit flags. */ |
@@ -353,10 +377,17 @@ void *dlsym( void *handle, const char *name ) | |||
353 | size_t sLen; | 377 | size_t sLen; |
354 | sLen = VirtualQueryEx( hCurrentProc, _ReturnAddress(), &info, sizeof( info ) ); | 378 | sLen = VirtualQueryEx( hCurrentProc, _ReturnAddress(), &info, sizeof( info ) ); |
355 | if( sLen != sizeof( info ) ) | 379 | if( sLen != sizeof( info ) ) |
380 | { | ||
381 | if( sLen != 0 ) | ||
382 | SetLastError( ERROR_INVALID_PARAMETER ); | ||
356 | goto end; | 383 | goto end; |
384 | } | ||
357 | hCaller = (HMODULE) info.AllocationBase; | 385 | hCaller = (HMODULE) info.AllocationBase; |
358 | if(!hCaller) | 386 | if( !hCaller ) |
387 | { | ||
388 | SetLastError( ERROR_INVALID_PARAMETER ); | ||
359 | goto end; | 389 | goto end; |
390 | } | ||
360 | } | 391 | } |
361 | 392 | ||
362 | if( handle != RTLD_NEXT ) | 393 | if( handle != RTLD_NEXT ) |
@@ -414,6 +445,8 @@ void *dlsym( void *handle, const char *name ) | |||
414 | end: | 445 | end: |
415 | if( symbol == NULL ) | 446 | if( symbol == NULL ) |
416 | { | 447 | { |
448 | if( GetLastError() == 0 ) | ||
449 | SetLastError( ERROR_PROC_NOT_FOUND ); | ||
417 | save_err_str( name ); | 450 | save_err_str( name ); |
418 | } | 451 | } |
419 | 452 | ||