1 // Copyright 2011-2012 Renato Tegon Forti
2 // Copyright 2015-2020 Antony Polukhin
3 //
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt
6 // or copy at http://www.boost.org/LICENSE_1_0.txt)
7
8 // For more information, see http://www.boost.org
9
10 #include "../example/b2_workarounds.hpp"
11 #include <boost/dll.hpp>
12 #include <boost/core/lightweight_test.hpp>
13 // Unit Tests
14
15 namespace boost { namespace dll { namespace fs {
16
17 #ifdef BOOST_DLL_USE_STD_FS
18 using std::filesystem::remove;
19 using std::filesystem::copy;
20 #else
21 using boost::filesystem::remove;
22 using boost::filesystem::copy;
23 #endif
24
25 }}}
26
drop_version(const boost::dll::fs::path & lhs)27 inline boost::dll::fs::path drop_version(const boost::dll::fs::path& lhs) {
28 boost::dll::fs::path ext = lhs.filename().extension();
29 if (ext.native().size() > 1 && std::isdigit(ext.string()[1])) {
30 ext = lhs;
31 ext.replace_extension().replace_extension().replace_extension();
32 return ext;
33 }
34
35 return lhs;
36 }
37
lib_path_equal(const boost::dll::fs::path & lhs,const boost::dll::fs::path & rhs)38 inline bool lib_path_equal(const boost::dll::fs::path& lhs, const boost::dll::fs::path& rhs) {
39 const bool res = (drop_version(lhs).filename() == drop_version(rhs).filename());
40 if (!res) {
41 std::cerr << "lhs != rhs: " << lhs << " != " << rhs << '\n';
42 }
43 return res;
44 }
45
46 struct fs_copy_guard {
47 const boost::dll::fs::path actual_path_;
48 const bool same_;
49
fs_copy_guardfs_copy_guard50 inline explicit fs_copy_guard(const boost::dll::fs::path& shared_library_path)
51 : actual_path_( drop_version(shared_library_path) )
52 , same_(actual_path_ == shared_library_path)
53 {
54 if (!same_) {
55 boost::dll::fs::error_code ignore;
56 boost::dll::fs::remove(actual_path_, ignore);
57 boost::dll::fs::copy(shared_library_path, actual_path_, ignore);
58 }
59 }
60
~fs_copy_guardfs_copy_guard61 inline ~fs_copy_guard() {
62 if (!same_) {
63 boost::dll::fs::error_code ignore;
64 boost::dll::fs::remove(actual_path_, ignore);
65 }
66 }
67 };
68
69 // Disgusting workarounds for b2 on Windows platform
do_find_correct_libs_path(int argc,char * argv[],const char * lib_name)70 inline boost::dll::fs::path do_find_correct_libs_path(int argc, char* argv[], const char* lib_name) {
71 boost::dll::fs::path ret;
72
73 for (int i = 1; i < argc; ++i) {
74 ret = argv[i];
75 if (ret.string().find(lib_name) != std::string::npos && b2_workarounds::is_shared_library(ret)) {
76 return ret;
77 }
78 }
79
80 return lib_name;
81 }
82
main(int argc,char * argv[])83 int main(int argc, char* argv[])
84 {
85 using namespace boost::dll;
86
87 BOOST_TEST(argc >= 3);
88 boost::dll::fs::path shared_library_path = do_find_correct_libs_path(argc, argv, "test_library");
89 std::cout << "Library: " << shared_library_path;
90
91 {
92 shared_library sl(shared_library_path);
93 BOOST_TEST(sl.is_loaded());
94 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
95
96 shared_library sl2;
97 BOOST_TEST(!sl2.is_loaded());
98 BOOST_TEST(!sl2);
99
100 swap(sl, sl2);
101 BOOST_TEST(!sl.is_loaded());
102 BOOST_TEST(!sl);
103 BOOST_TEST(sl2.is_loaded());
104 BOOST_TEST(sl2);
105
106 sl.assign(sl2);
107 BOOST_TEST(sl.is_loaded());
108 BOOST_TEST(sl);
109 BOOST_TEST(sl2.is_loaded());
110 BOOST_TEST(sl2);
111 BOOST_TEST(sl2.location() == sl.location());
112
113 sl.assign(sl2);
114 BOOST_TEST(sl.is_loaded());
115 BOOST_TEST(sl);
116 BOOST_TEST(sl2.is_loaded());
117 BOOST_TEST(sl2);
118 BOOST_TEST(sl2.location() == sl.location());
119
120 sl2.assign(sl);
121 BOOST_TEST(sl.is_loaded());
122 BOOST_TEST(sl);
123 BOOST_TEST(sl2.is_loaded());
124 BOOST_TEST(sl2);
125 BOOST_TEST(sl2.location() == sl.location());
126
127 // Assigning an empty shared library
128 sl2.assign(shared_library());
129 BOOST_TEST(sl.is_loaded());
130 BOOST_TEST(sl);
131 BOOST_TEST(!sl2.is_loaded());
132 BOOST_TEST(!sl2);
133 boost::dll::fs::error_code ec;
134 BOOST_TEST(sl2.location(ec) != sl.location());
135 BOOST_TEST(ec);
136 }
137
138 {
139 boost::dll::fs::error_code ec;
140 shared_library sl(shared_library_path, ec);
141 BOOST_TEST(sl.is_loaded());
142 BOOST_TEST(sl);
143 BOOST_TEST(!ec);
144 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
145 BOOST_TEST(lib_path_equal(sl.location(ec), shared_library_path));
146 BOOST_TEST(!ec);
147
148 // Checking self assignment #1
149 sl.assign(sl);
150 BOOST_TEST(sl.is_loaded());
151 BOOST_TEST(sl);
152 BOOST_TEST(!ec);
153 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
154 BOOST_TEST(lib_path_equal(sl.location(ec), shared_library_path));
155
156 // Checking self assignment #2
157 sl.assign(sl, ec);
158 BOOST_TEST(sl.is_loaded());
159 BOOST_TEST(sl);
160 BOOST_TEST(!ec);
161 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
162 BOOST_TEST(lib_path_equal(sl.location(ec), shared_library_path));
163 }
164
165 {
166 shared_library sl;
167 BOOST_TEST(!sl.is_loaded());
168
169 sl.assign(sl);
170 BOOST_TEST(!sl);
171
172 shared_library sl2(sl);
173 BOOST_TEST(!sl);
174 BOOST_TEST(!sl2);
175
176 sl2.assign(sl);
177 BOOST_TEST(!sl);
178 BOOST_TEST(!sl2);
179 }
180
181 {
182 shared_library sl;
183 sl.load(shared_library_path);
184 BOOST_TEST(sl.is_loaded());
185 BOOST_TEST(sl);
186 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
187 }
188
189 {
190 shared_library sl;
191 boost::dll::fs::error_code ec;
192 sl.load(shared_library_path, ec);
193 BOOST_TEST(sl.is_loaded());
194 BOOST_TEST(sl);
195 BOOST_TEST(!ec);
196 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
197 }
198
199 {
200 shared_library sl(shared_library_path, load_mode::load_with_altered_search_path );
201 BOOST_TEST(sl.is_loaded());
202 BOOST_TEST(sl);
203 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
204 }
205
206 {
207 boost::dll::fs::error_code ec;
208 shared_library sl(shared_library_path, load_mode::load_with_altered_search_path, ec);
209 BOOST_TEST(sl.is_loaded());
210 BOOST_TEST(sl);
211 BOOST_TEST(!ec);
212 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
213 BOOST_TEST(lib_path_equal(sl.location(ec), shared_library_path));
214 BOOST_TEST(!ec);
215 }
216
217 {
218 boost::dll::fs::error_code ec;
219 shared_library sl(shared_library_path, load_mode::search_system_folders, ec);
220 BOOST_TEST(sl.is_loaded());
221 BOOST_TEST(sl);
222 BOOST_TEST(!ec);
223 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
224 BOOST_TEST(lib_path_equal(sl.location(ec), shared_library_path));
225 BOOST_TEST(!ec);
226 }
227
228 {
229 try {
230 #if BOOST_OS_WINDOWS
231 boost::dll::shared_library("winmm.dll");
232 #elif BOOST_OS_LINUX
233 boost::dll::shared_library("libdl.so");
234 #endif
235 BOOST_TEST(false);
236 } catch (...) {}
237 }
238
239 {
240 try {
241 #if BOOST_OS_WINDOWS
242 boost::dll::shared_library("winmm", load_mode::search_system_folders | load_mode::append_decorations);
243 #elif BOOST_OS_LINUX
244 boost::dll::shared_library("dl", boost::dll::load_mode::search_system_folders | load_mode::append_decorations);
245 #endif
246 } catch (...) {
247 BOOST_TEST(false);
248 }
249 }
250
251 {
252 shared_library sl;
253 sl.load(shared_library_path, load_mode::load_with_altered_search_path);
254 BOOST_TEST(sl.is_loaded());
255 BOOST_TEST(sl);
256 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
257 }
258
259 {
260 shared_library sl;
261 boost::dll::fs::error_code ec;
262 sl.load(shared_library_path, load_mode::load_with_altered_search_path, ec);
263 BOOST_TEST(sl.is_loaded());
264 BOOST_TEST(sl);
265 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
266 }
267
268 {
269 shared_library sl(shared_library_path, load_mode::rtld_lazy | load_mode::rtld_global);
270 BOOST_TEST(sl.is_loaded());
271 BOOST_TEST(sl);
272 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
273 }
274
275 {
276 shared_library sl(shared_library_path, load_mode::rtld_local);
277 BOOST_TEST(sl.is_loaded());
278 BOOST_TEST(sl);
279 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
280 }
281
282 {
283 shared_library sl(shared_library_path, load_mode::rtld_now);
284 BOOST_TEST(sl.is_loaded());
285 BOOST_TEST(sl);
286 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
287 }
288
289 {
290 fs_copy_guard guard(shared_library_path);
291
292 boost::dll::fs::path platform_independent_path = guard.actual_path_;
293 platform_independent_path.replace_extension();
294 if (platform_independent_path.filename().wstring().find(L"lib") == 0) {
295 platform_independent_path
296 = platform_independent_path.parent_path() / platform_independent_path.filename().wstring().substr(3);
297 }
298 std::cerr << "platform_independent_path: " << platform_independent_path << '\n';
299
300 shared_library sl(platform_independent_path, load_mode::append_decorations);
301 BOOST_TEST(sl.is_loaded());
302 BOOST_TEST(sl);
303 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
304
305 sl.unload();
306 BOOST_TEST(!sl.is_loaded());
307 BOOST_TEST(!sl);
308 }
309
310 {
311 shared_library sl(shared_library_path, load_mode::rtld_now | load_mode::rtld_global | load_mode::load_with_altered_search_path);
312 BOOST_TEST(sl.is_loaded());
313 BOOST_TEST(sl);
314 }
315
316 {
317 boost::dll::fs::error_code ec;
318 shared_library sl(shared_library_path, load_mode::rtld_lazy | load_mode::rtld_global, ec);
319 BOOST_TEST(sl.is_loaded());
320 BOOST_TEST(sl);
321 BOOST_TEST(!ec);
322 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
323 }
324
325 {
326 shared_library sl;
327 sl.load(shared_library_path, load_mode::rtld_lazy | load_mode::rtld_global);
328 BOOST_TEST(sl.is_loaded());
329 BOOST_TEST(sl);
330 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
331 }
332
333
334 { // Non-default flags with assignment
335 shared_library sl(shared_library_path,
336 load_mode::rtld_now | load_mode::rtld_global | load_mode::load_with_altered_search_path
337
338 // `load_mode::rtld_deepbind` is incompatible with sanitizers:
339 // You are trying to dlopen a libtest_library.so shared library with RTLD_DEEPBIND flag which is incompatibe with sanitizer runtime
340 // (see https://github.com/google/sanitizers/issues/611 for details).
341 #ifndef BOOST_TRAVISCI_BUILD
342 | load_mode::rtld_deepbind
343 #endif
344
345 );
346 BOOST_TEST(sl.is_loaded());
347 BOOST_TEST(sl);
348
349 boost::dll::fs::error_code ec;
350 shared_library sl2(sl, ec);
351 BOOST_TEST(!ec);
352 BOOST_TEST(sl.is_loaded());
353 BOOST_TEST(sl);
354 BOOST_TEST(sl2.is_loaded());
355 BOOST_TEST(sl2);
356 BOOST_TEST(sl2.location() == sl.location());
357
358 shared_library sl3(sl);
359 BOOST_TEST(sl.is_loaded());
360 BOOST_TEST(sl);
361 BOOST_TEST(sl3.is_loaded());
362 BOOST_TEST(sl3);
363
364 shared_library sl4;
365 sl4.assign(sl, ec);
366 BOOST_TEST(!ec);
367 BOOST_TEST(sl.is_loaded());
368 BOOST_TEST(sl);
369 BOOST_TEST(sl4.is_loaded());
370 BOOST_TEST(sl4);
371 }
372
373 { // Non-default flags with assignment and error_code
374 boost::dll::fs::error_code ec;
375 shared_library sl(shared_library_path, load_mode::rtld_lazy | load_mode::rtld_global, ec);
376 BOOST_TEST(sl.is_loaded());
377 BOOST_TEST(sl);
378 BOOST_TEST(!ec);
379 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
380
381 shared_library sl2(sl, ec);
382 BOOST_TEST(!ec);
383 BOOST_TEST(sl.is_loaded());
384 BOOST_TEST(sl);
385 BOOST_TEST(sl2.is_loaded());
386 BOOST_TEST(sl2);
387 BOOST_TEST(sl2.location() == sl.location());
388
389 shared_library sl3(sl);
390 BOOST_TEST(sl.is_loaded());
391 BOOST_TEST(sl);
392 BOOST_TEST(sl3.is_loaded());
393 BOOST_TEST(sl3);
394 BOOST_TEST(sl3.location() == sl.location());
395 }
396
397 { // self_load
398 shared_library sl(program_location());
399 BOOST_TEST(sl.is_loaded());
400 BOOST_TEST(sl);
401 std::cout << "\nProgram location: " << program_location();
402 std::cout << "\nLibrary location: " << sl.location();
403 BOOST_TEST( boost::dll::fs::equivalent(sl.location(), program_location()) );
404
405 boost::dll::fs::error_code ec;
406 shared_library sl2(program_location());
407 BOOST_TEST(sl2.is_loaded());
408 BOOST_TEST( boost::dll::fs::equivalent(sl2.location(), program_location()) );
409 BOOST_TEST(sl2);
410 BOOST_TEST(!ec);
411
412 BOOST_TEST(sl == sl2);
413 BOOST_TEST(!(sl < sl2 || sl2 <sl));
414 BOOST_TEST(!(sl != sl2));
415
416 sl.load(shared_library_path);
417 BOOST_TEST(sl != sl2);
418 BOOST_TEST(sl < sl2 || sl2 <sl);
419 BOOST_TEST(!(sl == sl2));
420
421 sl.unload();
422 BOOST_TEST(!sl);
423 BOOST_TEST(sl != sl2);
424 BOOST_TEST(sl < sl2 || sl2 <sl);
425 BOOST_TEST(!(sl == sl2));
426
427 sl2.unload();
428 BOOST_TEST(!sl2);
429 BOOST_TEST(sl == sl2);
430 BOOST_TEST(!(sl < sl2 || sl2 <sl));
431 BOOST_TEST(!(sl != sl2));
432
433 // assigning self
434 sl.load(program_location());
435 sl2 = sl;
436 BOOST_TEST(sl == sl2);
437 BOOST_TEST(sl.location() == sl2.location());
438 }
439
440 {
441 shared_library sl;
442 boost::dll::fs::error_code ec;
443 sl.load(shared_library_path, load_mode::rtld_lazy | load_mode::rtld_global, ec);
444 BOOST_TEST(sl.is_loaded());
445 BOOST_TEST(sl);
446 BOOST_TEST(!ec);
447 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
448
449 sl.load(program_location());
450 BOOST_TEST(sl.is_loaded());
451 BOOST_TEST(sl);
452
453 sl.load(program_location());
454 BOOST_TEST(sl.is_loaded());
455 BOOST_TEST(sl);
456 BOOST_TEST(!ec);
457 }
458
459 { // self_load
460 shared_library sl;
461 boost::dll::fs::error_code ec;
462 sl.load(program_location());
463 BOOST_TEST(sl.is_loaded());
464 BOOST_TEST(sl);
465 BOOST_TEST(!ec);
466 }
467
468 { // unload
469 shared_library sl(shared_library_path);
470 BOOST_TEST(sl.is_loaded());
471 BOOST_TEST(sl);
472 BOOST_TEST(lib_path_equal(sl.location(), shared_library_path));
473 sl.unload();
474 BOOST_TEST(!sl.is_loaded());
475 BOOST_TEST(!sl);
476 }
477
478
479 { // error_code load calls test
480 boost::dll::fs::error_code ec;
481 shared_library sl(shared_library_path / "dir_that_does_not_exist", ec);
482 BOOST_TEST(ec);
483 BOOST_TEST(!sl.is_loaded());
484 BOOST_TEST(!sl);
485
486 boost::dll::fs::path bad_path(shared_library_path);
487 bad_path += ".1.1.1.1.1.1";
488 sl.load(bad_path, ec);
489 BOOST_TEST(ec);
490 BOOST_TEST(!sl.is_loaded());
491 BOOST_TEST(!sl);
492
493 sl.load(shared_library_path, ec);
494 BOOST_TEST(!ec);
495 BOOST_TEST(sl.is_loaded());
496 BOOST_TEST(sl);
497
498 shared_library sl2(bad_path, ec);
499 BOOST_TEST(ec);
500 BOOST_TEST(!sl2.is_loaded());
501 BOOST_TEST(!sl2);
502
503 shared_library sl3(shared_library_path, ec);
504 BOOST_TEST(!ec);
505 BOOST_TEST(sl3.is_loaded());
506 BOOST_TEST(sl3);
507
508 sl.load("", ec);
509 BOOST_TEST(ec);
510 BOOST_TEST(!sl.is_loaded());
511 BOOST_TEST(!sl);
512 }
513
514
515 shared_library_path = do_find_correct_libs_path(argc, argv, "library1");
516 fs_copy_guard guard(shared_library_path);
517 shared_library starts_with_lib(
518 boost::dll::fs::path(guard.actual_path_).replace_extension(),
519 load_mode::append_decorations
520 );
521
522 starts_with_lib.load(
523 boost::dll::fs::path(guard.actual_path_).replace_extension(),
524 load_mode::append_decorations
525 );
526
527 return boost::report_errors();
528 }
529