1 // Copyright 2011-2012 Renato Tegon Forti
2 // Copyright 2015-2019 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