diff options
author | Silvio Traversaro <silvio@traversaro.it> | 2019-06-11 00:19:48 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-11 00:19:48 +0200 |
commit | 11ff86bfab0e3baf6d17d2f2743aa735b3656ef7 (patch) | |
tree | 3984a9c029036cc902a08b91056d4a8a7cd62a01 | |
parent | 1488731c810ed76589170909da9ef07f060cef46 (diff) | |
parent | e646c9ab005d6a4480fa3728ebe9c34182bfedc6 (diff) | |
download | dlfcn-win32-11ff86bfab0e3baf6d17d2f2743aa735b3656ef7.tar.gz dlfcn-win32-11ff86bfab0e3baf6d17d2f2743aa735b3656ef7.tar.bz2 dlfcn-win32-11ff86bfab0e3baf6d17d2f2743aa735b3656ef7.zip |
Merge pull request #54 from pali/master
Correctly process and indicate errors
-rw-r--r-- | dlfcn.c | 127 | ||||
-rw-r--r-- | test.c | 168 |
2 files changed, 228 insertions, 67 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 | ||
@@ -83,6 +83,11 @@ int main() | |||
83 | int (*nonexistentfunction)( void ); | 83 | int (*nonexistentfunction)( void ); |
84 | int ret; | 84 | int ret; |
85 | HMODULE library3; | 85 | HMODULE library3; |
86 | char toolongfile[32767]; | ||
87 | DWORD code; | ||
88 | char nonlibraryfile[MAX_PATH]; | ||
89 | HANDLE tempfile; | ||
90 | DWORD dummy; | ||
86 | 91 | ||
87 | #ifdef _DEBUG | 92 | #ifdef _DEBUG |
88 | _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); | 93 | _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); |
@@ -93,6 +98,112 @@ int main() | |||
93 | _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT); | 98 | _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT); |
94 | #endif | 99 | #endif |
95 | 100 | ||
101 | ret = GetTempPathA( sizeof( nonlibraryfile ) - sizeof( "temp.dll" ), nonlibraryfile ); | ||
102 | if( ret == 0 || ret > sizeof( nonlibraryfile ) - sizeof( "temp.dll" ) ) | ||
103 | { | ||
104 | printf( "ERROR\tGetTempPath failed\n" ); | ||
105 | RETURN_ERROR; | ||
106 | } | ||
107 | |||
108 | memcpy( nonlibraryfile + ret, "temp.dll", sizeof( "temp.dll" ) ); | ||
109 | |||
110 | tempfile = CreateFileA( (LPCSTR) nonlibraryfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL ); | ||
111 | if( tempfile == INVALID_HANDLE_VALUE ) | ||
112 | { | ||
113 | printf( "ERROR\tCannot create temporary file %s: %lu\n", nonlibraryfile, (unsigned long)GetLastError( ) ); | ||
114 | RETURN_ERROR; | ||
115 | } | ||
116 | |||
117 | WriteFile( tempfile, "test content", 12, &dummy, NULL ); | ||
118 | |||
119 | CloseHandle( tempfile ); | ||
120 | |||
121 | library3 = LoadLibraryA( nonlibraryfile ); | ||
122 | code = GetLastError( ); | ||
123 | if( library3 ) | ||
124 | { | ||
125 | printf( "ERROR\tNon-library file %s was opened via WINAPI\n", nonlibraryfile ); | ||
126 | CloseHandle( library3 ); | ||
127 | DeleteFileA( nonlibraryfile ); | ||
128 | RETURN_ERROR; | ||
129 | } | ||
130 | else if( code != ERROR_BAD_EXE_FORMAT ) | ||
131 | { | ||
132 | printf( "ERROR\tNon-library file %s was processed via WINAPI: %lu\n", nonlibraryfile, (unsigned long)code ); | ||
133 | DeleteFileA( nonlibraryfile ); | ||
134 | RETURN_ERROR; | ||
135 | } | ||
136 | else | ||
137 | printf( "SUCCESS\tCould not open non-library file %s via WINAPI: %lu\n", nonlibraryfile, (unsigned long)code ); | ||
138 | |||
139 | library = dlopen( nonlibraryfile, RTLD_GLOBAL ); | ||
140 | if( library ) | ||
141 | { | ||
142 | printf( "ERROR\tNon-library file %s was opened via dlopen\n", nonlibraryfile ); | ||
143 | dlclose( library ); | ||
144 | DeleteFileA( nonlibraryfile ); | ||
145 | RETURN_ERROR; | ||
146 | } | ||
147 | error = dlerror( ); | ||
148 | if( !error ) | ||
149 | { | ||
150 | printf( "ERROR\tNo error from dlopen for non-library file\n" ); | ||
151 | DeleteFileA( nonlibraryfile ); | ||
152 | RETURN_ERROR; | ||
153 | } | ||
154 | else | ||
155 | printf( "SUCCESS\tCould not open non-library file %s: %s\n", nonlibraryfile, error ); | ||
156 | |||
157 | DeleteFileA( nonlibraryfile ); | ||
158 | |||
159 | library = dlopen( "nonexistentfile.dll", RTLD_GLOBAL ); | ||
160 | if( library ) | ||
161 | { | ||
162 | printf( "ERROR\tNon-existent file nonexistentfile.dll was opened via dlopen\n" ); | ||
163 | RETURN_ERROR; | ||
164 | } | ||
165 | error = dlerror( ); | ||
166 | if( !error ) | ||
167 | { | ||
168 | printf( "ERROR\tNo error from dlopen for non-existent file\n" ); | ||
169 | RETURN_ERROR; | ||
170 | } | ||
171 | else | ||
172 | printf( "SUCCESS\tCould not open non-existent file nonexistentfile.dll: %s\n", error ); | ||
173 | |||
174 | memset( toolongfile, 'X', sizeof( toolongfile ) - 5 ); | ||
175 | memcpy( toolongfile + sizeof( toolongfile ) - 5, ".dll", 5 ); | ||
176 | |||
177 | library = dlopen( toolongfile, RTLD_GLOBAL ); | ||
178 | if( library ) | ||
179 | { | ||
180 | printf( "ERROR\tFile with too long file name was opened via dlopen\n" ); | ||
181 | RETURN_ERROR; | ||
182 | } | ||
183 | error = dlerror( ); | ||
184 | if( !error ) | ||
185 | { | ||
186 | printf( "ERROR\tNo error from dlopen for file with too long file name\n" ); | ||
187 | RETURN_ERROR; | ||
188 | } | ||
189 | else | ||
190 | printf( "SUCCESS\tCould not open file with too long file name: %s\n", error ); | ||
191 | |||
192 | library3 = LoadLibraryA( toolongfile ); | ||
193 | code = GetLastError( ); | ||
194 | if( library3 ) | ||
195 | { | ||
196 | printf( "ERROR\tFile with too long file name was opened via WINAPI\n" ); | ||
197 | RETURN_ERROR; | ||
198 | } | ||
199 | else if( code != ERROR_FILENAME_EXCED_RANGE ) | ||
200 | { | ||
201 | printf( "ERROR\tFile with too long file name was processed via WINAPI: %lu\n", (unsigned long)code ); | ||
202 | RETURN_ERROR; | ||
203 | } | ||
204 | else | ||
205 | printf( "SUCCESS\tCould not open file with too long file name via WINAPI: %lu\n", (unsigned long)code ); | ||
206 | |||
96 | library2 = dlopen( "testdll2.dll", RTLD_GLOBAL ); | 207 | library2 = dlopen( "testdll2.dll", RTLD_GLOBAL ); |
97 | if( !library2 ) | 208 | if( !library2 ) |
98 | { | 209 | { |
@@ -201,11 +312,14 @@ int main() | |||
201 | CLOSE_GLOBAL; | 312 | CLOSE_GLOBAL; |
202 | RETURN_ERROR; | 313 | RETURN_ERROR; |
203 | } | 314 | } |
204 | else { | 315 | error = dlerror( ); |
205 | error = dlerror( ); | 316 | if( !error ) |
206 | printf( "SUCCESS\tCould not get nonexistent symbol from library handle: %s\n", | 317 | { |
207 | error ? error : "" ); | 318 | printf( "ERROR\tNo error from dlsym for nonexistent symbol\n" ); |
319 | RETURN_ERROR; | ||
208 | } | 320 | } |
321 | else | ||
322 | printf( "SUCCESS\tCould not get nonexistent symbol from library handle: %s\n", error ); | ||
209 | 323 | ||
210 | function = dlsym( global, "function" ); | 324 | function = dlsym( global, "function" ); |
211 | if( !function ) | 325 | if( !function ) |
@@ -231,11 +345,14 @@ int main() | |||
231 | CLOSE_GLOBAL; | 345 | CLOSE_GLOBAL; |
232 | RETURN_ERROR; | 346 | RETURN_ERROR; |
233 | } | 347 | } |
234 | else { | 348 | error = dlerror( ); |
235 | error = dlerror( ); | 349 | if( !error ) |
236 | printf( "SUCCESS\tCould not get nonexistent symbol from global handle: %s\n", | 350 | { |
237 | error ? error : "" ); | 351 | printf( "ERROR\tNo error from dlsym for nonexistent symbol\n" ); |
352 | RETURN_ERROR; | ||
238 | } | 353 | } |
354 | else | ||
355 | printf( "SUCCESS\tCould not get nonexistent symbol from global handle: %s\n", error ); | ||
239 | 356 | ||
240 | ret = dlclose( library ); | 357 | ret = dlclose( library ); |
241 | if( ret ) | 358 | if( ret ) |
@@ -293,11 +410,14 @@ int main() | |||
293 | CLOSE_GLOBAL; | 410 | CLOSE_GLOBAL; |
294 | RETURN_ERROR; | 411 | RETURN_ERROR; |
295 | } | 412 | } |
296 | else { | 413 | error = dlerror( ); |
297 | error = dlerror( ); | 414 | if( !error ) |
298 | printf( "SUCCESS\tCould not get nonexistent symbol from library handle: %s\n", | 415 | { |
299 | error ? error : "" ); | 416 | printf( "ERROR\tNo error from dlsym for nonexistent symbol\n" ); |
417 | RETURN_ERROR; | ||
300 | } | 418 | } |
419 | else | ||
420 | printf( "SUCCESS\tCould not get nonexistent symbol from library handle: %s\n", error ); | ||
301 | 421 | ||
302 | function = dlsym( global, "function" ); | 422 | function = dlsym( global, "function" ); |
303 | if( function ) | 423 | if( function ) |
@@ -321,11 +441,14 @@ int main() | |||
321 | CLOSE_GLOBAL; | 441 | CLOSE_GLOBAL; |
322 | RETURN_ERROR; | 442 | RETURN_ERROR; |
323 | } | 443 | } |
324 | else { | 444 | error = dlerror( ); |
325 | error = dlerror( ); | 445 | if( !error ) |
326 | printf( "SUCCESS\tDid not get nonexistent local symbol from global handle: %s\n", | 446 | { |
327 | error ? error : "" ); | 447 | printf( "ERROR\tNo error from dlsym for nonexistent symbol\n" ); |
448 | RETURN_ERROR; | ||
328 | } | 449 | } |
450 | else | ||
451 | printf( "SUCCESS\tDid not get nonexistent local symbol from global handle: %s\n", error ); | ||
329 | 452 | ||
330 | library = dlopen( "testdll.dll", RTLD_GLOBAL ); | 453 | library = dlopen( "testdll.dll", RTLD_GLOBAL ); |
331 | if( !library ) | 454 | if( !library ) |
@@ -363,10 +486,15 @@ int main() | |||
363 | CLOSE_GLOBAL; | 486 | CLOSE_GLOBAL; |
364 | RETURN_ERROR; | 487 | RETURN_ERROR; |
365 | } | 488 | } |
366 | else { | 489 | error = dlerror( ); |
367 | error = dlerror( ); | 490 | if( !error ) |
368 | printf( "SUCCESS\tCould not get nonexistent symbol from global handle: %s\n", | 491 | { |
369 | error ? error : "" ); | 492 | printf( "ERROR\tNo error from dlsym for nonexistent symbol\n" ); |
493 | RETURN_ERROR; | ||
494 | } | ||
495 | else | ||
496 | { | ||
497 | printf( "SUCCESS\tCould not get nonexistent symbol from global handle: %s\n", error ); | ||
370 | 498 | ||
371 | /* Test that the second call to dlerror() returns null as in the specs | 499 | /* Test that the second call to dlerror() returns null as in the specs |
372 | See https://github.com/dlfcn-win32/dlfcn-win32/issues/34 */ | 500 | See https://github.com/dlfcn-win32/dlfcn-win32/issues/34 */ |