diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/CMakeLists.txt | 12 | ||||
-rw-r--r-- | tests/test.c | 687 | ||||
-rw-r--r-- | tests/testdll.c | 47 | ||||
-rw-r--r-- | tests/testdll2.c | 59 | ||||
-rw-r--r-- | tests/testdll3.c | 42 |
5 files changed, 847 insertions, 0 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..64f85f7 --- /dev/null +++ b/tests/CMakeLists.txt | |||
@@ -0,0 +1,12 @@ | |||
1 | enable_testing() | ||
2 | include_directories(../src) | ||
3 | add_library(testdll SHARED testdll.c) | ||
4 | set_target_properties(testdll PROPERTIES PREFIX "") | ||
5 | add_library(testdll2 SHARED testdll2.c) | ||
6 | set_target_properties(testdll2 PROPERTIES PREFIX "") | ||
7 | target_link_libraries(testdll2 dl) | ||
8 | add_library(testdll3 SHARED testdll3.c) | ||
9 | set_target_properties(testdll3 PROPERTIES PREFIX "") | ||
10 | add_executable(t_dlfcn test.c) | ||
11 | target_link_libraries(t_dlfcn dl) | ||
12 | add_test (NAME t_dlfcn COMMAND t_dlfcn) | ||
diff --git a/tests/test.c b/tests/test.c new file mode 100644 index 0000000..5d060d2 --- /dev/null +++ b/tests/test.c | |||
@@ -0,0 +1,687 @@ | |||
1 | /* | ||
2 | * dlfcn-win32 | ||
3 | * Copyright (c) 2007-2009 Ramiro Polla | ||
4 | * Copyright (c) 2014 Tiancheng "Timothy" Gu | ||
5 | * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com> | ||
6 | * | ||
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
8 | * of this software and associated documentation files (the "Software"), to deal | ||
9 | * in the Software without restriction, including without limitation the rights | ||
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
11 | * copies of the Software, and to permit persons to whom the Software is | ||
12 | * furnished to do so, subject to the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice shall be included in | ||
15 | * all copies or substantial portions of the Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
23 | * THE SOFTWARE. | ||
24 | */ | ||
25 | |||
26 | #ifdef _DEBUG | ||
27 | #define _CRTDBG_MAP_ALLOC | ||
28 | #include <stdlib.h> | ||
29 | #include <crtdbg.h> | ||
30 | #endif | ||
31 | #include <stdio.h> | ||
32 | #include <string.h> | ||
33 | #include <windows.h> | ||
34 | #include <wchar.h> | ||
35 | #include <io.h> | ||
36 | #include <fcntl.h> | ||
37 | #include <direct.h> | ||
38 | #include "dlfcn.h" | ||
39 | |||
40 | /* If these dlclose's fails, we don't care as the handles are going to be | ||
41 | closed eventually when the program ends. */ | ||
42 | #define CLOSE_LIB dlclose( library ) | ||
43 | #define CLOSE_GLOBAL dlclose( global ) | ||
44 | |||
45 | #define RETURN_ERROR printf("From line %d\n", __LINE__); return 1 | ||
46 | |||
47 | #define RUNFUNC do { \ | ||
48 | ret = function (); \ | ||
49 | if( ret != 0) { \ | ||
50 | CLOSE_LIB; \ | ||
51 | CLOSE_GLOBAL; \ | ||
52 | RETURN_ERROR; \ | ||
53 | } \ | ||
54 | } while( 0 ) | ||
55 | |||
56 | /* This is what this test does: | ||
57 | * - Open library with RTLD_GLOBAL | ||
58 | * - Get global object | ||
59 | * - Get symbol from library through library object <- works | ||
60 | * - Run function if it worked | ||
61 | * - Get nonexistent symbol from library through library object <- fails | ||
62 | * - Get symbol from library through global object <- works | ||
63 | * - Run function if it worked | ||
64 | * - Get nonexistent symbol from library through global object <- fails | ||
65 | * - Close library | ||
66 | * - Open library with RTLD_LOCAL | ||
67 | * - Get symbol from library through library object <- works | ||
68 | * - Run function if it worked | ||
69 | * - Get nonexistent symbol from library through library object <- fails | ||
70 | * - Get local symbol from library through global object <- fails | ||
71 | * - Get nonexistent local symbol from library through global object <- fails | ||
72 | * - Open library again (without closing it first) with RTLD_GLOBAL | ||
73 | * - Get symbol from library through global object <- works | ||
74 | * - Get nonexistent symbol from library through global object <- fails | ||
75 | * - Close library | ||
76 | * - Close global object | ||
77 | * | ||
78 | * If one test fails, the program terminates itself. | ||
79 | */ | ||
80 | |||
81 | int main() | ||
82 | { | ||
83 | void *global; | ||
84 | void *library2; | ||
85 | void *library; | ||
86 | char *error; | ||
87 | int (*function)( void ); | ||
88 | int (*function2_from_library2)( void ); | ||
89 | size_t (*fwrite_local) ( const void *, size_t, size_t, FILE * ); | ||
90 | size_t (*fputs_default) ( const char *, FILE * ); | ||
91 | int (*nonexistentfunction)( void ); | ||
92 | int fd; | ||
93 | int ret; | ||
94 | HMODULE library3; | ||
95 | char toolongfile[32767]; | ||
96 | DWORD code; | ||
97 | char nonlibraryfile[MAX_PATH]; | ||
98 | char bytename[sizeof("testdll2.dll")+4]; | ||
99 | WCHAR widename[sizeof("testdll2.dll")+1]; | ||
100 | DWORD length; | ||
101 | HANDLE tempfile; | ||
102 | DWORD dummy; | ||
103 | UINT uMode; | ||
104 | |||
105 | #ifdef _DEBUG | ||
106 | _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); | ||
107 | _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT); | ||
108 | _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); | ||
109 | _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT); | ||
110 | _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); | ||
111 | _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT); | ||
112 | #endif | ||
113 | |||
114 | length = GetTempPathA( sizeof( nonlibraryfile ) - sizeof( "temp.dll" ), nonlibraryfile ); | ||
115 | if( length == 0 || length > sizeof( nonlibraryfile ) - sizeof( "temp.dll" ) ) | ||
116 | { | ||
117 | printf( "ERROR\tGetTempPath failed\n" ); | ||
118 | RETURN_ERROR; | ||
119 | } | ||
120 | |||
121 | memcpy( nonlibraryfile + length, "temp.dll", sizeof( "temp.dll" ) ); | ||
122 | |||
123 | tempfile = CreateFileA( (LPCSTR) nonlibraryfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL ); | ||
124 | if( tempfile == INVALID_HANDLE_VALUE ) | ||
125 | { | ||
126 | printf( "ERROR\tCannot create temporary file %s: %lu\n", nonlibraryfile, (unsigned long)GetLastError( ) ); | ||
127 | RETURN_ERROR; | ||
128 | } | ||
129 | |||
130 | WriteFile( tempfile, "test content", 12, &dummy, NULL ); | ||
131 | |||
132 | CloseHandle( tempfile ); | ||
133 | |||
134 | uMode = SetErrorMode( SEM_FAILCRITICALERRORS ); | ||
135 | library3 = LoadLibraryA( nonlibraryfile ); | ||
136 | code = GetLastError( ); | ||
137 | SetErrorMode( uMode ); | ||
138 | if( library3 ) | ||
139 | { | ||
140 | printf( "ERROR\tNon-library file %s was opened via WINAPI\n", nonlibraryfile ); | ||
141 | CloseHandle( library3 ); | ||
142 | DeleteFileA( nonlibraryfile ); | ||
143 | RETURN_ERROR; | ||
144 | } | ||
145 | else if( code != ERROR_BAD_EXE_FORMAT ) | ||
146 | { | ||
147 | printf( "ERROR\tNon-library file %s was processed via WINAPI: %lu\n", nonlibraryfile, (unsigned long)code ); | ||
148 | DeleteFileA( nonlibraryfile ); | ||
149 | RETURN_ERROR; | ||
150 | } | ||
151 | else | ||
152 | printf( "SUCCESS\tCould not open non-library file %s via WINAPI: %lu\n", nonlibraryfile, (unsigned long)code ); | ||
153 | |||
154 | library = dlopen( nonlibraryfile, RTLD_GLOBAL ); | ||
155 | if( library ) | ||
156 | { | ||
157 | printf( "ERROR\tNon-library file %s was opened via dlopen\n", nonlibraryfile ); | ||
158 | dlclose( library ); | ||
159 | DeleteFileA( nonlibraryfile ); | ||
160 | RETURN_ERROR; | ||
161 | } | ||
162 | error = dlerror( ); | ||
163 | if( !error ) | ||
164 | { | ||
165 | printf( "ERROR\tNo error from dlopen for non-library file\n" ); | ||
166 | DeleteFileA( nonlibraryfile ); | ||
167 | RETURN_ERROR; | ||
168 | } | ||
169 | else | ||
170 | printf( "SUCCESS\tCould not open non-library file %s: %s\n", nonlibraryfile, error ); | ||
171 | |||
172 | DeleteFileA( nonlibraryfile ); | ||
173 | |||
174 | library = dlopen( "nonexistentfile.dll", RTLD_GLOBAL ); | ||
175 | if( library ) | ||
176 | { | ||
177 | printf( "ERROR\tNon-existent file nonexistentfile.dll was opened via dlopen\n" ); | ||
178 | RETURN_ERROR; | ||
179 | } | ||
180 | error = dlerror( ); | ||
181 | if( !error ) | ||
182 | { | ||
183 | printf( "ERROR\tNo error from dlopen for non-existent file\n" ); | ||
184 | RETURN_ERROR; | ||
185 | } | ||
186 | else | ||
187 | printf( "SUCCESS\tCould not open non-existent file nonexistentfile.dll: %s\n", error ); | ||
188 | |||
189 | memset( toolongfile, 'X', sizeof( toolongfile ) - 5 ); | ||
190 | memcpy( toolongfile + sizeof( toolongfile ) - 5, ".dll", 5 ); | ||
191 | |||
192 | library = dlopen( toolongfile, RTLD_GLOBAL ); | ||
193 | if( library ) | ||
194 | { | ||
195 | printf( "ERROR\tFile with too long file name was opened via dlopen\n" ); | ||
196 | RETURN_ERROR; | ||
197 | } | ||
198 | error = dlerror( ); | ||
199 | if( !error ) | ||
200 | { | ||
201 | printf( "ERROR\tNo error from dlopen for file with too long file name\n" ); | ||
202 | RETURN_ERROR; | ||
203 | } | ||
204 | else | ||
205 | printf( "SUCCESS\tCould not open file with too long file name: %s\n", error ); | ||
206 | |||
207 | uMode = SetErrorMode( SEM_FAILCRITICALERRORS ); | ||
208 | library3 = LoadLibraryA( toolongfile ); | ||
209 | code = GetLastError( ); | ||
210 | SetErrorMode( uMode ); | ||
211 | if( library3 ) | ||
212 | { | ||
213 | printf( "ERROR\tFile with too long file name was opened via WINAPI\n" ); | ||
214 | RETURN_ERROR; | ||
215 | } | ||
216 | else if( code != ERROR_FILENAME_EXCED_RANGE ) | ||
217 | { | ||
218 | printf( "ERROR\tFile with too long file name was processed via WINAPI: %lu\n", (unsigned long)code ); | ||
219 | RETURN_ERROR; | ||
220 | } | ||
221 | else | ||
222 | printf( "SUCCESS\tCould not open file with too long file name via WINAPI: %lu\n", (unsigned long)code ); | ||
223 | |||
224 | fd = _open( "testdll2.dll", _O_RDONLY | _O_BINARY ); | ||
225 | if( fd < 0 ) | ||
226 | { | ||
227 | if( _chdir( "Debug" ) == 0 ) | ||
228 | { | ||
229 | fd = _open( "testdll2.dll", _O_RDONLY | _O_BINARY ); | ||
230 | if( fd < 0 ) | ||
231 | _chdir( ".." ); | ||
232 | } | ||
233 | } | ||
234 | if( fd < 0 ) | ||
235 | { | ||
236 | if( _chdir( "Release" ) == 0 ) | ||
237 | { | ||
238 | fd = _open( "testdll2.dll", _O_RDONLY | _O_BINARY ); | ||
239 | if( fd < 0 ) | ||
240 | _chdir( ".." ); | ||
241 | } | ||
242 | } | ||
243 | if( fd < 0 ) | ||
244 | { | ||
245 | printf( "ERROR\tCould not open library2 file: %s\n", strerror( errno ) ); | ||
246 | RETURN_ERROR; | ||
247 | } | ||
248 | _close( fd ); | ||
249 | |||
250 | library2 = dlopen( "testdll2.dll", RTLD_GLOBAL ); | ||
251 | if( !library2 ) | ||
252 | { | ||
253 | error = dlerror( ); | ||
254 | printf( "ERROR\tCould not open library2 globally: %s\n", error ? error : "" ); | ||
255 | RETURN_ERROR; | ||
256 | } | ||
257 | else | ||
258 | printf( "SUCCESS\tOpened library2 globally: %p\n", library2 ); | ||
259 | |||
260 | widename[0] = 0xE1; /* wide non-ASCII character mappable to most ANSI codepages */ | ||
261 | wcscpy( widename+1, L"testdll2.dll" ); | ||
262 | if( !CopyFileW( L"testdll2.dll", widename, FALSE )) | ||
263 | { | ||
264 | printf( "ERROR\tCould not copy file testdll2.dll: %lu\n", (unsigned long)GetLastError( ) ); | ||
265 | RETURN_ERROR; | ||
266 | } | ||
267 | else | ||
268 | printf( "SUCCESS\tCopied testdll2.dll to wide name %ls\n", widename ); | ||
269 | |||
270 | ret = WideCharToMultiByte( CP_ACP, 0, widename, -1, bytename, sizeof( bytename ), NULL, NULL ); | ||
271 | /* if we cannot convert widename to current codepage (used by _open() function), skip this test */ | ||
272 | if( ret > 0 ) | ||
273 | { | ||
274 | bytename[ret] = 0; | ||
275 | |||
276 | fd = _wopen( widename, _O_RDONLY | _O_BINARY ); | ||
277 | if( fd < 0 ) | ||
278 | { | ||
279 | printf( "ERROR\tCould not open copied wide library2 file %ls: %s\n", widename, strerror( errno ) ); | ||
280 | DeleteFileW( widename ); | ||
281 | RETURN_ERROR; | ||
282 | } | ||
283 | _close( fd ); | ||
284 | |||
285 | fd = _open( bytename, _O_RDONLY | _O_BINARY ); | ||
286 | if( fd < 0 ) | ||
287 | { | ||
288 | printf( "ERROR\tCould not open copied wide library2 file %s: %s\n", bytename, strerror( errno ) ); | ||
289 | DeleteFileW( widename ); | ||
290 | RETURN_ERROR; | ||
291 | } | ||
292 | _close( fd ); | ||
293 | |||
294 | dlclose( library2 ); | ||
295 | library2 = dlopen( bytename, RTLD_GLOBAL ); | ||
296 | if( !library2 ) | ||
297 | { | ||
298 | error = dlerror( ); | ||
299 | printf( "ERROR\tCould not open copied wide library2 file %s globally: %s\n", bytename, error ? error : "" ); | ||
300 | DeleteFileW( widename ); | ||
301 | RETURN_ERROR; | ||
302 | } | ||
303 | else | ||
304 | printf( "SUCCESS\tOpened copied wide library2 file %s globally: %p\n", bytename, library2 ); | ||
305 | |||
306 | dlclose( library2 ); | ||
307 | DeleteFileW( widename ); | ||
308 | |||
309 | library2 = dlopen( "testdll2.dll", RTLD_GLOBAL ); | ||
310 | if( !library2 ) | ||
311 | { | ||
312 | error = dlerror( ); | ||
313 | printf( "ERROR\tCould not open library2 globally: %s\n", error ? error : "" ); | ||
314 | RETURN_ERROR; | ||
315 | } | ||
316 | else | ||
317 | printf( "SUCCESS\tOpened library2 globally: %p\n", library2 ); | ||
318 | } | ||
319 | |||
320 | library = dlopen( "testdll.dll", RTLD_GLOBAL ); | ||
321 | if( !library ) | ||
322 | { | ||
323 | error = dlerror( ); | ||
324 | printf( "ERROR\tCould not open library globally: %s\n", error ? error : "" ); | ||
325 | RETURN_ERROR; | ||
326 | } | ||
327 | else | ||
328 | printf( "SUCCESS\tOpened library globally: %p\n", library ); | ||
329 | |||
330 | global = dlopen( 0, RTLD_GLOBAL ); | ||
331 | if( !global ) | ||
332 | { | ||
333 | error = dlerror( ); | ||
334 | printf( "ERROR\tCould not open global handle: %s\n", error ? error : "" ); | ||
335 | CLOSE_LIB; | ||
336 | RETURN_ERROR; | ||
337 | } | ||
338 | else | ||
339 | printf( "SUCCESS\tGot global handle: %p\n", global ); | ||
340 | |||
341 | *(void **) (&fwrite_local) = dlsym( global, "fwrite" ); | ||
342 | if (!fwrite_local) | ||
343 | { | ||
344 | error = dlerror(); | ||
345 | printf("ERROR\tCould not get symbol from global handle: %s\n", | ||
346 | error ? error : ""); | ||
347 | CLOSE_LIB; | ||
348 | CLOSE_GLOBAL; | ||
349 | RETURN_ERROR; | ||
350 | } | ||
351 | else | ||
352 | printf( "SUCCESS\tGot symbol from global handle: %p\n", *(void **) (&fwrite_local) ); | ||
353 | { | ||
354 | const char *hello_world = "Hello world from local fwrite!\n"; | ||
355 | fwrite_local( hello_world, sizeof( char ), strlen( hello_world ), stderr ); | ||
356 | fflush( stderr ); | ||
357 | } | ||
358 | |||
359 | *(void **) (&fputs_default) = dlsym( RTLD_DEFAULT, "fputs" ); | ||
360 | if (!fputs_default) | ||
361 | { | ||
362 | error = dlerror(); | ||
363 | printf("ERROR\tCould not get symbol from default handle: %s\n", | ||
364 | error ? error : ""); | ||
365 | CLOSE_LIB; | ||
366 | CLOSE_GLOBAL; | ||
367 | RETURN_ERROR; | ||
368 | } | ||
369 | else | ||
370 | printf( "SUCCESS\tGot symbol from default handle: %p\n", *(void **) (&fputs_default) ); | ||
371 | { | ||
372 | const char *hello_world_fputs = "Hello world from default fputs!\n"; | ||
373 | fputs_default( hello_world_fputs, stderr ); | ||
374 | fflush( stderr ); | ||
375 | } | ||
376 | |||
377 | *(void **) (&function) = dlsym( library, "function" ); | ||
378 | if( !function ) | ||
379 | { | ||
380 | error = dlerror( ); | ||
381 | printf( "ERROR\tCould not get symbol from library handle: %s\n", | ||
382 | error ? error : "" ); | ||
383 | CLOSE_LIB; | ||
384 | CLOSE_GLOBAL; | ||
385 | RETURN_ERROR; | ||
386 | } | ||
387 | else | ||
388 | printf( "SUCCESS\tGot symbol from library handle: %p\n", *(void **) (&function) ); | ||
389 | |||
390 | RUNFUNC; | ||
391 | |||
392 | *(void **) (&function2_from_library2) = dlsym( library2, "function2" ); | ||
393 | if( !function2_from_library2 ) | ||
394 | { | ||
395 | error = dlerror( ); | ||
396 | printf( "ERROR\tCould not get symbol from library2 handle: %s\n", | ||
397 | error ? error : "" ); | ||
398 | CLOSE_LIB; | ||
399 | CLOSE_GLOBAL; | ||
400 | RETURN_ERROR; | ||
401 | } | ||
402 | else | ||
403 | printf( "SUCCESS\tGot symbol from library2 handle: %p\n", *(void **) (&function2_from_library2) ); | ||
404 | |||
405 | ret = function2_from_library2 (); | ||
406 | if( ret != 2 ) | ||
407 | { | ||
408 | CLOSE_LIB; | ||
409 | CLOSE_GLOBAL; | ||
410 | RETURN_ERROR; | ||
411 | } | ||
412 | |||
413 | *(void **) (&nonexistentfunction) = dlsym( library, "nonexistentfunction" ); | ||
414 | if( nonexistentfunction ) | ||
415 | { | ||
416 | error = dlerror( ); | ||
417 | printf( "ERROR\tGot nonexistent symbol from library handle: %p\n", *(void **) (&nonexistentfunction) ); | ||
418 | CLOSE_LIB; | ||
419 | CLOSE_GLOBAL; | ||
420 | RETURN_ERROR; | ||
421 | } | ||
422 | error = dlerror( ); | ||
423 | if( !error ) | ||
424 | { | ||
425 | printf( "ERROR\tNo error from dlsym for nonexistent symbol\n" ); | ||
426 | RETURN_ERROR; | ||
427 | } | ||
428 | else | ||
429 | printf( "SUCCESS\tCould not get nonexistent symbol from library handle: %s\n", error ); | ||
430 | |||
431 | *(void **) (&function) = dlsym( global, "function" ); | ||
432 | if( !function ) | ||
433 | { | ||
434 | error = dlerror( ); | ||
435 | printf( "ERROR\tCould not get symbol from global handle: %s\n", | ||
436 | error ? error : "" ); | ||
437 | CLOSE_LIB; | ||
438 | CLOSE_GLOBAL; | ||
439 | RETURN_ERROR; | ||
440 | } | ||
441 | else | ||
442 | printf( "SUCCESS\tGot symbol from global handle: %p\n", *(void **) (&function) ); | ||
443 | |||
444 | RUNFUNC; | ||
445 | |||
446 | *(void **) (&nonexistentfunction) = dlsym( global, "nonexistentfunction" ); | ||
447 | if( nonexistentfunction ) | ||
448 | { | ||
449 | error = dlerror( ); | ||
450 | printf( "ERROR\tGot nonexistent symbol from global handle: %p\n", *(void **) (&nonexistentfunction) ); | ||
451 | CLOSE_LIB; | ||
452 | CLOSE_GLOBAL; | ||
453 | RETURN_ERROR; | ||
454 | } | ||
455 | error = dlerror( ); | ||
456 | if( !error ) | ||
457 | { | ||
458 | printf( "ERROR\tNo error from dlsym for nonexistent symbol\n" ); | ||
459 | RETURN_ERROR; | ||
460 | } | ||
461 | else | ||
462 | printf( "SUCCESS\tCould not get nonexistent symbol from global handle: %s\n", error ); | ||
463 | |||
464 | ret = dlclose( library ); | ||
465 | if( ret ) | ||
466 | { | ||
467 | error = dlerror( ); | ||
468 | printf( "ERROR\tCould not close library: %s\n", error ? error : "" ); | ||
469 | RETURN_ERROR; | ||
470 | } | ||
471 | else | ||
472 | printf( "SUCCESS\tClosed library.\n" ); | ||
473 | |||
474 | ret = dlclose( library2 ); | ||
475 | if( ret ) | ||
476 | { | ||
477 | error = dlerror( ); | ||
478 | printf( "ERROR\tCould not close library2: %s\n", error ? error : "" ); | ||
479 | RETURN_ERROR; | ||
480 | } | ||
481 | else | ||
482 | printf( "SUCCESS\tClosed library2.\n" ); | ||
483 | |||
484 | library = dlopen( "testdll.dll", RTLD_LOCAL ); | ||
485 | if( !library ) | ||
486 | { | ||
487 | error = dlerror( ); | ||
488 | printf( "ERROR\tCould not open library locally: %s\n", error ? error : "" ); | ||
489 | CLOSE_LIB; | ||
490 | CLOSE_GLOBAL; | ||
491 | RETURN_ERROR; | ||
492 | } | ||
493 | else | ||
494 | printf( "SUCCESS\tOpened library locally: %p\n", library ); | ||
495 | |||
496 | *(void **) (&function) = dlsym( library, "function" ); | ||
497 | if( !function ) | ||
498 | { | ||
499 | error = dlerror( ); | ||
500 | printf( "ERROR\tCould not get symbol from library handle: %s\n", | ||
501 | error ? error : "" ); | ||
502 | CLOSE_LIB; | ||
503 | CLOSE_GLOBAL; | ||
504 | RETURN_ERROR; | ||
505 | } | ||
506 | else | ||
507 | printf( "SUCCESS\tGot symbol from library handle: %p\n", *(void **) (&function) ); | ||
508 | |||
509 | RUNFUNC; | ||
510 | |||
511 | *(void **) (&nonexistentfunction) = dlsym( library, "nonexistentfunction" ); | ||
512 | if( nonexistentfunction ) | ||
513 | { | ||
514 | error = dlerror( ); | ||
515 | printf( "ERROR\tGot nonexistent symbol from library handle: %p\n", *(void **) (&nonexistentfunction) ); | ||
516 | CLOSE_LIB; | ||
517 | CLOSE_GLOBAL; | ||
518 | RETURN_ERROR; | ||
519 | } | ||
520 | error = dlerror( ); | ||
521 | if( !error ) | ||
522 | { | ||
523 | printf( "ERROR\tNo error from dlsym for nonexistent symbol\n" ); | ||
524 | RETURN_ERROR; | ||
525 | } | ||
526 | else | ||
527 | printf( "SUCCESS\tCould not get nonexistent symbol from library handle: %s\n", error ); | ||
528 | |||
529 | *(void **) (&function) = dlsym( global, "function" ); | ||
530 | if( function ) | ||
531 | { | ||
532 | error = dlerror( ); | ||
533 | printf( "ERROR\tGot local symbol from global handle: %s @ %p\n", | ||
534 | error ? error : "", *(void **) (&function) ); | ||
535 | CLOSE_LIB; | ||
536 | CLOSE_GLOBAL; | ||
537 | RETURN_ERROR; | ||
538 | } | ||
539 | else | ||
540 | printf( "SUCCESS\tDid not get local symbol from global handle.\n" ); | ||
541 | |||
542 | *(void **) (&nonexistentfunction) = dlsym( global, "nonexistentfunction" ); | ||
543 | if( nonexistentfunction ) | ||
544 | { | ||
545 | error = dlerror( ); | ||
546 | printf( "ERROR\tGot nonexistent local symbol from global handle: %p\n", *(void **) (&nonexistentfunction) ); | ||
547 | CLOSE_LIB; | ||
548 | CLOSE_GLOBAL; | ||
549 | RETURN_ERROR; | ||
550 | } | ||
551 | error = dlerror( ); | ||
552 | if( !error ) | ||
553 | { | ||
554 | printf( "ERROR\tNo error from dlsym for nonexistent symbol\n" ); | ||
555 | RETURN_ERROR; | ||
556 | } | ||
557 | else | ||
558 | printf( "SUCCESS\tDid not get nonexistent local symbol from global handle: %s\n", error ); | ||
559 | |||
560 | library = dlopen( "testdll.dll", RTLD_GLOBAL ); | ||
561 | if( !library ) | ||
562 | { | ||
563 | error = dlerror( ); | ||
564 | printf( "ERROR\tCould not open library globally without closing it first: %s\n", error ? error : "" ); | ||
565 | CLOSE_LIB; | ||
566 | CLOSE_GLOBAL; | ||
567 | RETURN_ERROR; | ||
568 | } | ||
569 | else | ||
570 | printf( "SUCCESS\tOpened library globally without closing it first: %p\n", library ); | ||
571 | |||
572 | *(void **) (&function) = dlsym( global, "function" ); | ||
573 | if( !function ) | ||
574 | { | ||
575 | error = dlerror( ); | ||
576 | printf( "ERROR\tCould not get symbol from global handle: %s\n", | ||
577 | error ? error : "" ); | ||
578 | CLOSE_LIB; | ||
579 | CLOSE_GLOBAL; | ||
580 | RETURN_ERROR; | ||
581 | } | ||
582 | else | ||
583 | printf( "SUCCESS\tGot symbol from global handle: %p\n", *(void **) (&function) ); | ||
584 | |||
585 | RUNFUNC; | ||
586 | |||
587 | *(void **) (&nonexistentfunction) = dlsym( global, "nonexistentfunction" ); | ||
588 | if( nonexistentfunction ) | ||
589 | { | ||
590 | error = dlerror( ); | ||
591 | printf( "ERROR\tGot nonexistent symbol from global handle: %p\n", *(void **) (&nonexistentfunction) ); | ||
592 | CLOSE_LIB; | ||
593 | CLOSE_GLOBAL; | ||
594 | RETURN_ERROR; | ||
595 | } | ||
596 | error = dlerror( ); | ||
597 | if( !error ) | ||
598 | { | ||
599 | printf( "ERROR\tNo error from dlsym for nonexistent symbol\n" ); | ||
600 | RETURN_ERROR; | ||
601 | } | ||
602 | else | ||
603 | { | ||
604 | printf( "SUCCESS\tCould not get nonexistent symbol from global handle: %s\n", error ); | ||
605 | |||
606 | /* Test that the second call to dlerror() returns null as in the specs | ||
607 | See https://github.com/dlfcn-win32/dlfcn-win32/issues/34 */ | ||
608 | error = dlerror( ); | ||
609 | if( error == NULL ) | ||
610 | { | ||
611 | printf( "SUCCESS\tSecond consecutive call to dlerror returned NULL\n"); | ||
612 | } | ||
613 | else | ||
614 | { | ||
615 | printf( "ERROR\tSecond consecutive call to dlerror returned a non-NULL pointer: %p\n", error ); | ||
616 | CLOSE_LIB; | ||
617 | CLOSE_GLOBAL; | ||
618 | RETURN_ERROR; | ||
619 | } | ||
620 | } | ||
621 | |||
622 | *(void **) (&function) = dlsym( global, "fwrite" ); | ||
623 | if (!function) | ||
624 | { | ||
625 | error = dlerror(); | ||
626 | printf("ERROR\tCould not get symbol from global handle: %s\n", | ||
627 | error ? error : ""); | ||
628 | CLOSE_LIB; | ||
629 | CLOSE_GLOBAL; | ||
630 | RETURN_ERROR; | ||
631 | } | ||
632 | else | ||
633 | printf( "SUCCESS\tGot symbol from global handle: %p\n", *(void **) (&function) ); | ||
634 | |||
635 | |||
636 | uMode = SetErrorMode( SEM_FAILCRITICALERRORS ); | ||
637 | library3 = LoadLibraryA("testdll3.dll"); | ||
638 | SetErrorMode( uMode ); | ||
639 | if (!library3) | ||
640 | { | ||
641 | printf( "ERROR\tCould not open library3 via WINAPI\n" ); | ||
642 | RETURN_ERROR; | ||
643 | } | ||
644 | else | ||
645 | printf( "SUCCESS\tOpened library3 via WINAPI: %p\n", (void *)library3 ); | ||
646 | |||
647 | ret = dlclose( library ); | ||
648 | if( ret ) | ||
649 | { | ||
650 | error = dlerror( ); | ||
651 | printf( "ERROR\tCould not close library: %s\n", error ? error : "" ); | ||
652 | CLOSE_GLOBAL; | ||
653 | RETURN_ERROR; | ||
654 | } | ||
655 | else | ||
656 | printf( "SUCCESS\tClosed library.\n" ); | ||
657 | |||
658 | *(void **) (&function) = dlsym( global, "function3" ); | ||
659 | if (!function) | ||
660 | { | ||
661 | error = dlerror(); | ||
662 | printf("ERROR\tCould not get symbol from global handle: %s\n", | ||
663 | error ? error : ""); | ||
664 | CLOSE_LIB; | ||
665 | CLOSE_GLOBAL; | ||
666 | RETURN_ERROR; | ||
667 | } | ||
668 | else | ||
669 | printf( "SUCCESS\tGot symbol from global handle: %p\n", *(void **) (&function) ); | ||
670 | |||
671 | RUNFUNC; | ||
672 | |||
673 | ret = dlclose( global ); | ||
674 | if( ret ) | ||
675 | { | ||
676 | error = dlerror( ); | ||
677 | printf( "ERROR\tCould not close global handle: %s\n", error ? error : "" ); | ||
678 | RETURN_ERROR; | ||
679 | } | ||
680 | else | ||
681 | printf( "SUCCESS\tClosed global handle.\n" ); | ||
682 | |||
683 | #ifdef _DEBUG | ||
684 | _CrtDumpMemoryLeaks(); | ||
685 | #endif | ||
686 | return 0; | ||
687 | } | ||
diff --git a/tests/testdll.c b/tests/testdll.c new file mode 100644 index 0000000..5bb0f43 --- /dev/null +++ b/tests/testdll.c | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * dlfcn-win32 | ||
3 | * Copyright (c) 2007 Ramiro Polla | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | * of this software and associated documentation files (the "Software"), to deal | ||
7 | * in the Software without restriction, including without limitation the rights | ||
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | * copies of the Software, and to permit persons to whom the Software is | ||
10 | * furnished to do so, subject to the following conditions: | ||
11 | * | ||
12 | * The above copyright notice and this permission notice shall be included in | ||
13 | * all copies or substantial portions of the Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | * THE SOFTWARE. | ||
22 | */ | ||
23 | |||
24 | #ifdef _DEBUG | ||
25 | #define _CRTDBG_MAP_ALLOC | ||
26 | #include <stdlib.h> | ||
27 | #include <crtdbg.h> | ||
28 | #endif | ||
29 | #include <stdio.h> | ||
30 | |||
31 | #if defined(_WIN32) | ||
32 | #define EXPORT __declspec(dllexport) | ||
33 | #else | ||
34 | #define EXPORT | ||
35 | #endif | ||
36 | |||
37 | EXPORT int function2( void ) | ||
38 | { | ||
39 | printf( "Hello, world! from original library\n" ); | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | EXPORT int function( void ) | ||
44 | { | ||
45 | printf( "Hello, world!\n" ); | ||
46 | return 0; | ||
47 | } | ||
diff --git a/tests/testdll2.c b/tests/testdll2.c new file mode 100644 index 0000000..1560738 --- /dev/null +++ b/tests/testdll2.c | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * dlfcn-win32 | ||
3 | * Copyright (c) 2007 Ramiro Polla | ||
4 | * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com> | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #ifdef _DEBUG | ||
26 | #define _CRTDBG_MAP_ALLOC | ||
27 | #include <stdlib.h> | ||
28 | #include <crtdbg.h> | ||
29 | #endif | ||
30 | #include <stdio.h> | ||
31 | |||
32 | #include "dlfcn.h" | ||
33 | |||
34 | #if defined(_WIN32) | ||
35 | #define EXPORT __declspec(dllexport) | ||
36 | #else | ||
37 | #define EXPORT | ||
38 | #endif | ||
39 | |||
40 | EXPORT int function2( void ) | ||
41 | { | ||
42 | char *error; | ||
43 | int (*function2_orig)(void); | ||
44 | printf( "Hello, world! from wrapper library\n" ); | ||
45 | *(void **) (&function2_orig) = dlsym( RTLD_NEXT, "function2" ); | ||
46 | if (!function2_orig) | ||
47 | { | ||
48 | error = dlerror( ); | ||
49 | printf( "ERROR\tCould not get symbol from RTLD_NEXT handle: %s\n", | ||
50 | error ? error : "" ); | ||
51 | return 1; | ||
52 | } | ||
53 | if (function2_orig() != 0) | ||
54 | { | ||
55 | printf( "ERROR\tOriginal function from RTLD_NEXT handle did not return correct value\n" ); | ||
56 | return 1; | ||
57 | } | ||
58 | return 2; | ||
59 | } | ||
diff --git a/tests/testdll3.c b/tests/testdll3.c new file mode 100644 index 0000000..b6f4f5b --- /dev/null +++ b/tests/testdll3.c | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * dlfcn-win32 | ||
3 | * Copyright (c) 2007 Ramiro Polla | ||
4 | * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com> | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #ifdef _DEBUG | ||
26 | #define _CRTDBG_MAP_ALLOC | ||
27 | #include <stdlib.h> | ||
28 | #include <crtdbg.h> | ||
29 | #endif | ||
30 | #include <stdio.h> | ||
31 | |||
32 | #if defined(_WIN32) | ||
33 | #define EXPORT __declspec(dllexport) | ||
34 | #else | ||
35 | #define EXPORT | ||
36 | #endif | ||
37 | |||
38 | EXPORT int function3( void ) | ||
39 | { | ||
40 | printf( "Hello, world!\n" ); | ||
41 | return 0; | ||
42 | } | ||