dlfcn_test.cpp revision 554374693408cd7c74d0cae596fca7349661edea
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <gtest/gtest.h>
18
19#include <dlfcn.h>
20#include <libgen.h>
21#include <limits.h>
22#include <stdio.h>
23#include <stdint.h>
24
25#include "private/ScopeGuard.h"
26
27#include <string>
28
29#include "utils.h"
30
31#define ASSERT_SUBSTR(needle, haystack) \
32    ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
33
34
35static bool g_called = false;
36extern "C" void DlSymTestFunction() {
37  g_called = true;
38}
39
40static int g_ctor_function_called = 0;
41static int g_ctor_argc = 0;
42static char** g_ctor_argv = reinterpret_cast<char**>(0xDEADBEEF);
43static char** g_ctor_envp = g_ctor_envp;
44
45extern "C" void ctor_function(int argc, char** argv, char** envp) __attribute__ ((constructor));
46
47extern "C" void ctor_function(int argc, char** argv, char** envp) {
48  g_ctor_function_called = 17;
49  g_ctor_argc = argc;
50  g_ctor_argv = argv;
51  g_ctor_envp = envp;
52}
53
54TEST(dlfcn, ctor_function_call) {
55  ASSERT_EQ(17, g_ctor_function_called);
56  ASSERT_TRUE(g_ctor_argc = get_argc());
57  ASSERT_TRUE(g_ctor_argv = get_argv());
58  ASSERT_TRUE(g_ctor_envp = get_envp());
59}
60
61TEST(dlfcn, dlsym_in_executable) {
62  dlerror(); // Clear any pending errors.
63  void* self = dlopen(nullptr, RTLD_NOW);
64  ASSERT_TRUE(self != nullptr);
65  ASSERT_TRUE(dlerror() == nullptr);
66
67  void* sym = dlsym(self, "DlSymTestFunction");
68  ASSERT_TRUE(sym != nullptr);
69
70  void (*function)() = reinterpret_cast<void(*)()>(sym);
71
72  g_called = false;
73  function();
74  ASSERT_TRUE(g_called);
75
76  ASSERT_EQ(0, dlclose(self));
77}
78
79TEST(dlfcn, dlsym_from_sofile) {
80  void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_LAZY | RTLD_LOCAL);
81  ASSERT_TRUE(handle != nullptr) << dlerror();
82
83  // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
84  void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
85  ASSERT_TRUE(symbol == nullptr);
86  ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
87
88  typedef int* (*fn_t)();
89  fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT =
90      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
91  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror();
92
93  int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT();
94  ASSERT_TRUE(ptr != nullptr) << dlerror();
95  ASSERT_EQ(42, *ptr);
96
97  fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT =
98      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT"));
99  ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror();
100
101  ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT();
102  ASSERT_TRUE(ptr != nullptr) << dlerror();
103  ASSERT_EQ(44, *ptr);
104
105  fn_t lookup_dlsym_symbol_using_RTLD_NEXT =
106      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT"));
107  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror();
108
109  ptr = lookup_dlsym_symbol_using_RTLD_NEXT();
110  ASSERT_TRUE(ptr != nullptr) << dlerror();
111  ASSERT_EQ(43, *ptr);
112
113  dlclose(handle);
114}
115
116TEST(dlfcn, dlsym_from_sofile_with_preload) {
117  void* preload = dlopen("libtest_dlsym_from_this_grandchild.so", RTLD_NOW | RTLD_LOCAL);
118  ASSERT_TRUE(preload != nullptr) << dlerror();
119
120  void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW | RTLD_LOCAL);
121  ASSERT_TRUE(handle != nullptr) << dlerror();
122
123  // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
124  void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
125  ASSERT_TRUE(symbol == nullptr);
126  ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
127
128  typedef int* (*fn_t)();
129  fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT =
130      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
131  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror();
132
133  int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT();
134  ASSERT_TRUE(ptr != nullptr) << dlerror();
135  ASSERT_EQ(42, *ptr);
136
137  fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT =
138      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT"));
139  ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror();
140
141  ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT();
142  ASSERT_TRUE(ptr != nullptr) << dlerror();
143  ASSERT_EQ(44, *ptr);
144
145  fn_t lookup_dlsym_symbol_using_RTLD_NEXT =
146      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT"));
147  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror();
148
149  ptr = lookup_dlsym_symbol_using_RTLD_NEXT();
150  ASSERT_TRUE(ptr != nullptr) << dlerror();
151  ASSERT_EQ(43, *ptr);
152
153  dlclose(handle);
154  dlclose(preload);
155}
156
157TEST(dlfcn, dlsym_handle_global_sym) {
158  // check that we do not look into global group
159  // when looking up symbol by handle
160  void* handle = dlopen("libtest_empty.so", RTLD_NOW);
161  dlopen("libtest_with_dependency.so", RTLD_NOW | RTLD_GLOBAL);
162  void* sym = dlsym(handle, "getRandomNumber");
163  ASSERT_TRUE(sym == nullptr);
164  ASSERT_SUBSTR("undefined symbol: getRandomNumber", dlerror());
165
166  sym = dlsym(handle, "DlSymTestFunction");
167  ASSERT_TRUE(sym == nullptr);
168  ASSERT_SUBSTR("undefined symbol: DlSymTestFunction", dlerror());
169  dlclose(handle);
170}
171
172TEST(dlfcn, dlsym_with_dependencies) {
173  void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
174  ASSERT_TRUE(handle != nullptr);
175  dlerror();
176  // This symbol is in DT_NEEDED library.
177  void* sym = dlsym(handle, "getRandomNumber");
178  ASSERT_TRUE(sym != nullptr) << dlerror();
179  int (*fn)(void);
180  fn = reinterpret_cast<int (*)(void)>(sym);
181  EXPECT_EQ(4, fn());
182  dlclose(handle);
183}
184
185TEST(dlfcn, dlopen_noload) {
186  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
187  ASSERT_TRUE(handle == nullptr);
188  handle = dlopen("libtest_simple.so", RTLD_NOW);
189  void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
190  ASSERT_TRUE(handle != nullptr);
191  ASSERT_TRUE(handle2 != nullptr);
192  ASSERT_TRUE(handle == handle2);
193  ASSERT_EQ(0, dlclose(handle));
194  ASSERT_EQ(0, dlclose(handle2));
195}
196
197TEST(dlfcn, dlopen_by_soname) {
198  static const char* soname = "libdlext_test_soname.so";
199  static const char* filename = "libdlext_test_different_soname.so";
200  // 1. Make sure there is no library with soname in default search path
201  void* handle = dlopen(soname, RTLD_NOW);
202  ASSERT_TRUE(handle == nullptr);
203
204  // 2. Load a library using filename
205  handle = dlopen(filename, RTLD_NOW);
206  ASSERT_TRUE(handle != nullptr) << dlerror();
207
208  // 3. Find library by soname
209  void* handle_soname = dlopen(soname, RTLD_NOW | RTLD_NOLOAD);
210  ASSERT_TRUE(handle_soname != nullptr) << dlerror();
211  ASSERT_EQ(handle, handle_soname);
212
213  // 4. RTLD_NOLOAD should still work with filename
214  void* handle_filename = dlopen(filename, RTLD_NOW | RTLD_NOLOAD);
215  ASSERT_TRUE(handle_filename != nullptr) << dlerror();
216  ASSERT_EQ(handle, handle_filename);
217
218  dlclose(handle_filename);
219  dlclose(handle_soname);
220  dlclose(handle);
221}
222
223// mips doesn't support ifuncs
224#if !defined(__mips__)
225TEST(dlfcn, ifunc) {
226  typedef const char* (*fn_ptr)();
227
228  // ifunc's choice depends on whether IFUNC_CHOICE has a value
229  // first check the set case
230  setenv("IFUNC_CHOICE", "set", 1);
231  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
232  ASSERT_TRUE(handle != nullptr);
233  fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
234  fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
235  ASSERT_TRUE(foo_ptr != nullptr);
236  ASSERT_TRUE(foo_library_ptr != nullptr);
237  ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
238  ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
239  dlclose(handle);
240
241  // then check the unset case
242  unsetenv("IFUNC_CHOICE");
243  handle = dlopen("libtest_ifunc.so", RTLD_NOW);
244  ASSERT_TRUE(handle != nullptr);
245  foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
246  foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
247  ASSERT_TRUE(foo_ptr != nullptr);
248  ASSERT_TRUE(foo_library_ptr != nullptr);
249  ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
250  ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
251  dlclose(handle);
252}
253
254TEST(dlfcn, ifunc_ctor_call) {
255  typedef const char* (*fn_ptr)();
256
257  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
258  ASSERT_TRUE(handle != nullptr) << dlerror();
259  fn_ptr is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
260  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
261  ASSERT_STREQ("false", is_ctor_called());
262
263  is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
264  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
265  ASSERT_STREQ("true", is_ctor_called());
266  dlclose(handle);
267}
268
269TEST(dlfcn, ifunc_ctor_call_rtld_lazy) {
270  typedef const char* (*fn_ptr)();
271
272  void* handle = dlopen("libtest_ifunc.so", RTLD_LAZY);
273  ASSERT_TRUE(handle != nullptr) << dlerror();
274  fn_ptr is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
275  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
276  ASSERT_STREQ("false", is_ctor_called());
277
278  is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
279  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
280  ASSERT_STREQ("true", is_ctor_called());
281  dlclose(handle);
282}
283#endif
284
285TEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
286  // This is the structure of the test library and
287  // its dt_needed libraries
288  // libtest_relo_check_dt_needed_order.so
289  // |
290  // +-> libtest_relo_check_dt_needed_order_1.so
291  // |
292  // +-> libtest_relo_check_dt_needed_order_2.so
293  //
294  // The root library references relo_test_get_answer_lib - which is defined
295  // in both dt_needed libraries, the correct relocation should
296  // use the function defined in libtest_relo_check_dt_needed_order_1.so
297  void* handle = nullptr;
298  auto guard = make_scope_guard([&]() {
299    dlclose(handle);
300  });
301
302  handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
303  ASSERT_TRUE(handle != nullptr) << dlerror();
304
305  typedef int (*fn_t) (void);
306  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
307  ASSERT_TRUE(fn != nullptr) << dlerror();
308  ASSERT_EQ(1, fn());
309}
310
311TEST(dlfcn, dlopen_check_order_dlsym) {
312  // Here is how the test library and its dt_needed
313  // libraries are arranged
314  //
315  //  libtest_check_order_children.so
316  //  |
317  //  +-> ..._1_left.so
318  //  |   |
319  //  |   +-> ..._a.so
320  //  |   |
321  //  |   +-> ...r_b.so
322  //  |
323  //  +-> ..._2_right.so
324  //  |   |
325  //  |   +-> ..._d.so
326  //  |       |
327  //  |       +-> ..._b.so
328  //  |
329  //  +-> ..._3_c.so
330  //
331  //  load order should be (1, 2, 3, a, b, d)
332  //
333  // get_answer() is defined in (2, 3, a, b, c)
334  // get_answer2() is defined in (b, d)
335  void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer");
336  ASSERT_TRUE(sym == nullptr);
337  void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL);
338  ASSERT_TRUE(handle != nullptr) << dlerror();
339  typedef int (*fn_t) (void);
340  fn_t fn, fn2;
341  fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"));
342  ASSERT_TRUE(fn != nullptr) << dlerror();
343  fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2"));
344  ASSERT_TRUE(fn2 != nullptr) << dlerror();
345
346  ASSERT_EQ(42, fn());
347  ASSERT_EQ(43, fn2());
348  dlclose(handle);
349}
350
351TEST(dlfcn, dlopen_check_order_reloc_siblings) {
352  // This is how this one works:
353  // we lookup and call get_answer which is defined in '_2.so'
354  // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so'
355  // the correct _impl() is implemented by '_a.so';
356  //
357  // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?)
358  //
359  // Here is the picture:
360  //
361  // libtest_check_order_reloc_siblings.so
362  // |
363  // +-> ..._1.so <- empty
364  // |   |
365  // |   +-> ..._a.so <- exports correct answer_impl()
366  // |   |
367  // |   +-> ..._b.so <- every other letter exporting incorrect one.
368  // |
369  // +-> ..._2.so <- empty
370  // |   |
371  // |   +-> ..._c.so
372  // |   |
373  // |   +-> ..._d.so
374  // |
375  // +-> ..._3.so <- empty
376  //     |
377  //     +-> ..._e.so
378  //     |
379  //     +-> ..._f.so <- exports get_answer() that calls get_anser_impl();
380  //                     implements incorrect get_answer_impl()
381
382  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
383  ASSERT_TRUE(handle == nullptr);
384#ifdef __BIONIC__
385  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
386  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
387#endif
388
389  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
390  ASSERT_TRUE(handle != nullptr) << dlerror();
391
392  typedef int (*fn_t) (void);
393  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
394  ASSERT_TRUE(fn != nullptr) << dlerror();
395  ASSERT_EQ(42, fn());
396
397  ASSERT_EQ(0, dlclose(handle));
398}
399
400TEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) {
401  // This test uses the same library as dlopen_check_order_reloc_siblings.
402  // Unlike dlopen_check_order_reloc_siblings it preloads
403  // libtest_check_order_reloc_siblings_1.so (first dependency) prior to
404  // dlopen(libtest_check_order_reloc_siblings.so)
405
406  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
407  ASSERT_TRUE(handle == nullptr);
408  handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD);
409  ASSERT_TRUE(handle == nullptr);
410
411  void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL);
412  ASSERT_TRUE(handle_for_1 != nullptr) << dlerror();
413
414  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
415  ASSERT_TRUE(handle != nullptr) << dlerror();
416
417  ASSERT_EQ(0, dlclose(handle_for_1));
418
419  typedef int (*fn_t) (void);
420  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
421  ASSERT_TRUE(fn != nullptr) << dlerror();
422  ASSERT_EQ(42, fn());
423
424  ASSERT_EQ(0, dlclose(handle));
425}
426
427TEST(dlfcn, dlopen_check_order_reloc_grandchild) {
428  // This is how this one works:
429  // we lookup and call grandchild_get_answer which is defined in '_2.so'
430  // and in turn calls external get_answer_impl() defined in '_c_1.so and _c_2.so'
431  // the correct _impl() is implemented by '_c_1.so';
432  //
433  // Here is the picture of subtree:
434  //
435  // libtest_check_order_reloc_siblings.so
436  // |
437  // +-> ..._2.so <- grandchild_get_answer()
438  //     |
439  //     +-> ..._c.so <- empty
440  //     |   |
441  //     |   +-> _c_1.so <- exports correct answer_impl()
442  //     |   |
443  //     |   +-> _c_2.so <- exports incorrect answer_impl()
444  //     |
445  //     +-> ..._d.so <- empty
446
447  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
448  ASSERT_TRUE(handle == nullptr);
449#ifdef __BIONIC__
450  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
451  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
452#endif
453
454  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
455  ASSERT_TRUE(handle != nullptr) << dlerror();
456
457  typedef int (*fn_t) (void);
458  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_grandchild_get_answer"));
459  ASSERT_TRUE(fn != nullptr) << dlerror();
460  ASSERT_EQ(42, fn());
461
462  ASSERT_EQ(0, dlclose(handle));
463}
464
465TEST(dlfcn, dlopen_check_order_reloc_nephew) {
466  // This is how this one works:
467  // we lookup and call nephew_get_answer which is defined in '_2.so'
468  // and in turn calls external get_answer_impl() defined in '_[a-f].so'
469  // the correct _impl() is implemented by '_a.so';
470  //
471  // Here is the picture:
472  //
473  // libtest_check_order_reloc_siblings.so
474  // |
475  // +-> ..._1.so <- empty
476  // |   |
477  // |   +-> ..._a.so <- exports correct answer_impl()
478  // |   |
479  // |   +-> ..._b.so <- every other letter exporting incorrect one.
480  // |
481  // +-> ..._2.so <- empty
482  // |   |
483  // |   +-> ..._c.so
484  // |   |
485  // |   +-> ..._d.so
486  // |
487  // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl();
488  //     |
489  //     +-> ..._e.so
490  //     |
491  //     +-> ..._f.so
492
493  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
494  ASSERT_TRUE(handle == nullptr);
495#ifdef __BIONIC__
496  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
497  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
498#endif
499
500  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
501  ASSERT_TRUE(handle != nullptr) << dlerror();
502
503  typedef int (*fn_t) (void);
504  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_nephew_get_answer"));
505  ASSERT_TRUE(fn != nullptr) << dlerror();
506  ASSERT_EQ(42, fn());
507
508  ASSERT_EQ(0, dlclose(handle));
509}
510
511TEST(dlfcn, check_unload_after_reloc) {
512  // This is how this one works:
513  // libtest_two_parents_parent1 <- answer_impl() used by libtest_two_parents_child
514  // |
515  // +-> libtest_two_parents_child
516  //
517  // libtest_two_parents_parent2 <- answer_impl() not used by libtest_two_parents_child
518  // |
519  // +-> libtest_two_parents_child
520  //
521  // Test dlopens parent1 which loads and relocates libtest_two_parents_child.so
522  // as a second step it dlopens parent2 and dlcloses parent1...
523
524  void* handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL);
525  ASSERT_TRUE(handle != nullptr) << dlerror();
526
527  void* handle2 = dlopen("libtest_two_parents_parent2.so", RTLD_NOW | RTLD_LOCAL);
528  ASSERT_TRUE(handle2 != nullptr) << dlerror();
529
530  typedef int (*fn_t) (void);
531  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
532  ASSERT_TRUE(fn != nullptr) << dlerror();
533  ASSERT_EQ(42, fn());
534
535  ASSERT_EQ(0, dlclose(handle));
536
537  handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
538  ASSERT_TRUE(handle != nullptr);
539  ASSERT_EQ(0, dlclose(handle));
540
541  fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
542  ASSERT_TRUE(fn != nullptr) << dlerror();
543  ASSERT_EQ(42, fn());
544
545  ASSERT_EQ(0, dlclose(handle2));
546
547  handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
548  ASSERT_TRUE(handle == nullptr);
549}
550
551extern "C" int check_order_reloc_root_get_answer_impl() {
552  return 42;
553}
554
555TEST(dlfcn, dlopen_check_order_reloc_main_executable) {
556  // This is how this one works:
557  // we lookup and call get_answer3 which is defined in 'root.so'
558  // and in turn calls external root_get_answer_impl() defined in _2.so and
559  // above the correct _impl() is one in the executable.
560  //
561  // libtest_check_order_reloc_root.so
562  // |
563  // +-> ..._1.so <- empty
564  // |
565  // +-> ..._2.so <- gives incorrect answer for answer_main_impl()
566  //
567
568  void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD);
569  ASSERT_TRUE(handle == nullptr);
570#ifdef __BIONIC__
571  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
572  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
573#endif
574
575  handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL);
576  ASSERT_TRUE(handle != nullptr) << dlerror();
577
578  typedef int (*fn_t) (void);
579  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_root_get_answer"));
580  ASSERT_TRUE(fn != nullptr) << dlerror();
581  ASSERT_EQ(42, fn());
582
583  ASSERT_EQ(0, dlclose(handle));
584}
585
586TEST(dlfcn, dlopen_check_rtld_local) {
587  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
588  ASSERT_TRUE(sym == nullptr);
589
590  // implicit RTLD_LOCAL
591  void* handle = dlopen("libtest_simple.so", RTLD_NOW);
592  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
593  ASSERT_TRUE(sym == nullptr);
594  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
595  sym = dlsym(handle, "dlopen_testlib_simple_func");
596  ASSERT_TRUE(sym != nullptr);
597  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
598  dlclose(handle);
599
600  // explicit RTLD_LOCAL
601  handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL);
602  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
603  ASSERT_TRUE(sym == nullptr);
604  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
605  sym = dlsym(handle, "dlopen_testlib_simple_func");
606  ASSERT_TRUE(sym != nullptr);
607  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
608  dlclose(handle);
609}
610
611TEST(dlfcn, dlopen_check_rtld_global) {
612  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
613  ASSERT_TRUE(sym == nullptr);
614
615  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL);
616  ASSERT_TRUE(handle != nullptr) << dlerror();
617  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
618  ASSERT_TRUE(sym != nullptr) << dlerror();
619  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
620  dlclose(handle);
621
622  // RTLD_GLOBAL implies RTLD_NODELETE, let's check that
623  void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
624  ASSERT_EQ(sym, sym_after_dlclose);
625
626  // Check if dlsym() for main program's handle searches RTLD_GLOBAL
627  // shared libraries after symbol was not found in the main executable
628  // and dependent libraries.
629  void* handle_for_main_executable = dlopen(nullptr, RTLD_NOW);
630  sym = dlsym(handle_for_main_executable, "dlopen_testlib_simple_func");
631  ASSERT_TRUE(sym != nullptr) << dlerror();
632
633  dlclose(handle_for_main_executable);
634}
635
636// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
637// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so ->
638// libtest_with_dependency_loop_a.so
639TEST(dlfcn, dlopen_check_loop) {
640  void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW);
641  ASSERT_TRUE(handle != nullptr) << dlerror();
642  void* f = dlsym(handle, "dlopen_test_loopy_function");
643  ASSERT_TRUE(f != nullptr) << dlerror();
644  EXPECT_TRUE(reinterpret_cast<bool (*)(void)>(f)());
645  ASSERT_EQ(0, dlclose(handle));
646
647  // dlopen second time to make sure that the library was unloaded correctly
648  handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
649  ASSERT_TRUE(handle == nullptr);
650#ifdef __BIONIC__
651  ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
652#else
653  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
654  ASSERT_TRUE(dlerror() == nullptr);
655#endif
656
657  handle = dlopen("libtest_with_dependency_a.so", RTLD_NOW | RTLD_NOLOAD);
658  ASSERT_TRUE(handle == nullptr);
659}
660
661TEST(dlfcn, dlopen_nodelete) {
662  static bool is_unloaded = false;
663
664  void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE);
665  ASSERT_TRUE(handle != nullptr) << dlerror();
666  void (*set_unload_flag_ptr)(bool*);
667  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr"));
668  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
669  set_unload_flag_ptr(&is_unloaded);
670
671  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
672  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
673  ASSERT_EQ(1729U, *taxicab_number);
674  *taxicab_number = 2;
675
676  dlclose(handle);
677  ASSERT_TRUE(!is_unloaded);
678
679  uint32_t* taxicab_number_after_dlclose = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
680  ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number);
681  ASSERT_EQ(2U, *taxicab_number_after_dlclose);
682
683
684  handle = dlopen("libtest_nodelete_1.so", RTLD_NOW);
685  uint32_t* taxicab_number2 = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
686  ASSERT_EQ(taxicab_number2, taxicab_number);
687
688  ASSERT_EQ(2U, *taxicab_number2);
689
690  dlclose(handle);
691  ASSERT_TRUE(!is_unloaded);
692}
693
694TEST(dlfcn, dlopen_nodelete_on_second_dlopen) {
695  static bool is_unloaded = false;
696
697  void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW);
698  ASSERT_TRUE(handle != nullptr) << dlerror();
699  void (*set_unload_flag_ptr)(bool*);
700  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr"));
701  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
702  set_unload_flag_ptr(&is_unloaded);
703
704  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_2_taxicab_number"));
705  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
706
707  ASSERT_EQ(1729U, *taxicab_number);
708  *taxicab_number = 2;
709
710  // This RTLD_NODELETE should be ignored
711  void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE);
712  ASSERT_TRUE(handle1 != nullptr) << dlerror();
713  ASSERT_EQ(handle, handle1);
714
715  dlclose(handle1);
716  dlclose(handle);
717
718  ASSERT_TRUE(is_unloaded);
719}
720
721TEST(dlfcn, dlopen_nodelete_dt_flags_1) {
722  static bool is_unloaded = false;
723
724  void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW);
725  ASSERT_TRUE(handle != nullptr) << dlerror();
726  void (*set_unload_flag_ptr)(bool*);
727  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr"));
728  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
729  set_unload_flag_ptr(&is_unloaded);
730
731  dlclose(handle);
732  ASSERT_TRUE(!is_unloaded);
733}
734
735TEST(dlfcn, dlsym_df_1_global) {
736  void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW);
737  ASSERT_TRUE(handle != nullptr) << dlerror();
738  int (*get_answer)();
739  get_answer = reinterpret_cast<int (*)()>(dlsym(handle, "dl_df_1_global_get_answer"));
740  ASSERT_TRUE(get_answer != nullptr) << dlerror();
741  ASSERT_EQ(42, get_answer());
742  ASSERT_EQ(0, dlclose(handle));
743}
744
745TEST(dlfcn, dlopen_failure) {
746  void* self = dlopen("/does/not/exist", RTLD_NOW);
747  ASSERT_TRUE(self == nullptr);
748#if defined(__BIONIC__)
749  ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
750#else
751  ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
752#endif
753}
754
755static void* ConcurrentDlErrorFn(void*) {
756  dlopen("/child/thread", RTLD_NOW);
757  return reinterpret_cast<void*>(strdup(dlerror()));
758}
759
760TEST(dlfcn, dlerror_concurrent) {
761  dlopen("/main/thread", RTLD_NOW);
762  const char* main_thread_error = dlerror();
763  ASSERT_SUBSTR("/main/thread", main_thread_error);
764
765  pthread_t t;
766  ASSERT_EQ(0, pthread_create(&t, nullptr, ConcurrentDlErrorFn, nullptr));
767  void* result;
768  ASSERT_EQ(0, pthread_join(t, &result));
769  char* child_thread_error = static_cast<char*>(result);
770  ASSERT_SUBSTR("/child/thread", child_thread_error);
771  free(child_thread_error);
772
773  ASSERT_SUBSTR("/main/thread", main_thread_error);
774}
775
776TEST(dlfcn, dlsym_failures) {
777  dlerror(); // Clear any pending errors.
778  void* self = dlopen(nullptr, RTLD_NOW);
779  ASSERT_TRUE(self != nullptr);
780  ASSERT_TRUE(dlerror() == nullptr);
781
782  void* sym;
783
784#if defined(__BIONIC__) && !defined(__LP64__)
785  // RTLD_DEFAULT in lp32 bionic is not (void*)0
786  // so it can be distinguished from the NULL handle.
787  sym = dlsym(nullptr, "test");
788  ASSERT_TRUE(sym == nullptr);
789  ASSERT_STREQ("dlsym failed: library handle is null", dlerror());
790#endif
791
792  // Symbol that doesn't exist.
793  sym = dlsym(self, "ThisSymbolDoesNotExist");
794  ASSERT_TRUE(sym == nullptr);
795  ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
796
797  ASSERT_EQ(0, dlclose(self));
798}
799
800TEST(dlfcn, dladdr_executable) {
801  dlerror(); // Clear any pending errors.
802  void* self = dlopen(nullptr, RTLD_NOW);
803  ASSERT_TRUE(self != nullptr);
804  ASSERT_TRUE(dlerror() == nullptr);
805
806  void* sym = dlsym(self, "DlSymTestFunction");
807  ASSERT_TRUE(sym != nullptr);
808
809  // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
810  void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
811
812  Dl_info info;
813  int rc = dladdr(addr, &info);
814  ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
815
816  // Get the name of this executable.
817  const std::string& executable_path = get_executable_path();
818
819  // The filename should be that of this executable.
820  char dli_realpath[PATH_MAX];
821  ASSERT_TRUE(realpath(info.dli_fname, dli_realpath) != nullptr);
822  ASSERT_STREQ(executable_path.c_str(), dli_realpath);
823
824  // The symbol name should be the symbol we looked up.
825  ASSERT_STREQ(info.dli_sname, "DlSymTestFunction");
826
827  // The address should be the exact address of the symbol.
828  ASSERT_EQ(info.dli_saddr, sym);
829
830  std::vector<map_record> maps;
831  ASSERT_TRUE(Maps::parse_maps(&maps));
832
833  void* base_address = nullptr;
834  for (const map_record& rec : maps) {
835    if (executable_path == rec.pathname) {
836      base_address = reinterpret_cast<void*>(rec.addr_start);
837      break;
838    }
839  }
840
841  // The base address should be the address we were loaded at.
842  ASSERT_EQ(info.dli_fbase, base_address);
843
844  ASSERT_EQ(0, dlclose(self));
845}
846
847TEST(dlfcn, dlopen_executable_by_absolute_path) {
848  void* handle1 = dlopen(nullptr, RTLD_NOW);
849  ASSERT_TRUE(handle1 != nullptr) << dlerror();
850
851  void* handle2 = dlopen(get_executable_path().c_str(), RTLD_NOW);
852  ASSERT_TRUE(handle2 != nullptr) << dlerror();
853
854#if defined(__BIONIC__)
855  ASSERT_EQ(handle1, handle2);
856#else
857  GTEST_LOG_(INFO) << "Skipping ASSERT_EQ(handle1, handle2) for glibc: "
858                      "it loads a separate copy of the main executable "
859                      "on dlopen by absolute path.";
860#endif
861}
862
863#if defined(__LP64__)
864#define PATH_TO_SYSTEM_LIB "/system/lib64/"
865#else
866#define PATH_TO_SYSTEM_LIB "/system/lib/"
867#endif
868#define PATH_TO_LIBC PATH_TO_SYSTEM_LIB "libc.so"
869
870TEST(dlfcn, dladdr_libc) {
871#if defined(__BIONIC__)
872  Dl_info info;
873  void* addr = reinterpret_cast<void*>(puts); // well-known libc function
874  ASSERT_TRUE(dladdr(addr, &info) != 0);
875
876  // /system/lib is symlink when this test is executed on host.
877  char libc_realpath[PATH_MAX];
878  ASSERT_TRUE(realpath(PATH_TO_LIBC, libc_realpath) == libc_realpath);
879
880  ASSERT_STREQ(libc_realpath, info.dli_fname);
881  // TODO: add check for dfi_fbase
882  ASSERT_STREQ("puts", info.dli_sname);
883  ASSERT_EQ(addr, info.dli_saddr);
884#else
885  GTEST_LOG_(INFO) << "This test does nothing for glibc. Glibc returns path from ldconfig "
886      "for libc.so, which is symlink itself (not a realpath).\n";
887#endif
888}
889
890TEST(dlfcn, dladdr_invalid) {
891  Dl_info info;
892
893  dlerror(); // Clear any pending errors.
894
895  // No symbol corresponding to NULL.
896  ASSERT_EQ(dladdr(nullptr, &info), 0); // Zero on error, non-zero on success.
897  ASSERT_TRUE(dlerror() == nullptr); // dladdr(3) doesn't set dlerror(3).
898
899  // No symbol corresponding to a stack address.
900  ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
901  ASSERT_TRUE(dlerror() == nullptr); // dladdr(3) doesn't set dlerror(3).
902}
903
904// GNU-style ELF hash tables are incompatible with the MIPS ABI.
905// MIPS requires .dynsym to be sorted to match the GOT but GNU-style requires sorting by hash code.
906TEST(dlfcn, dlopen_library_with_only_gnu_hash) {
907#if !defined(__mips__)
908  dlerror(); // Clear any pending errors.
909  void* handle = dlopen("libgnu-hash-table-library.so", RTLD_NOW);
910  ASSERT_TRUE(handle != nullptr) << dlerror();
911  auto guard = make_scope_guard([&]() {
912    dlclose(handle);
913  });
914  void* sym = dlsym(handle, "getRandomNumber");
915  ASSERT_TRUE(sym != nullptr) << dlerror();
916  int (*fn)(void);
917  fn = reinterpret_cast<int (*)(void)>(sym);
918  EXPECT_EQ(4, fn());
919
920  Dl_info dlinfo;
921  ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
922
923  ASSERT_TRUE(fn == dlinfo.dli_saddr);
924  ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
925  ASSERT_SUBSTR("libgnu-hash-table-library.so", dlinfo.dli_fname);
926#else
927  GTEST_LOG_(INFO) << "This test does nothing for mips/mips64; mips toolchain does not support '--hash-style=gnu'\n";
928#endif
929}
930
931TEST(dlfcn, dlopen_library_with_only_sysv_hash) {
932  void* handle = dlopen("libsysv-hash-table-library.so", RTLD_NOW);
933  ASSERT_TRUE(handle != nullptr) << dlerror();
934  auto guard = make_scope_guard([&]() {
935    dlclose(handle);
936  });
937  void* sym = dlsym(handle, "getRandomNumber");
938  ASSERT_TRUE(sym != nullptr) << dlerror();
939  int (*fn)(void);
940  fn = reinterpret_cast<int (*)(void)>(sym);
941  EXPECT_EQ(4, fn());
942
943  Dl_info dlinfo;
944  ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
945
946  ASSERT_TRUE(fn == dlinfo.dli_saddr);
947  ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
948  ASSERT_SUBSTR("libsysv-hash-table-library.so", dlinfo.dli_fname);
949}
950
951TEST(dlfcn, dlopen_bad_flags) {
952  dlerror(); // Clear any pending errors.
953  void* handle;
954
955#if defined(__GLIBC__)
956  // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
957  handle = dlopen(nullptr, 0);
958  ASSERT_TRUE(handle == nullptr);
959  ASSERT_SUBSTR("invalid", dlerror());
960#endif
961
962  handle = dlopen(nullptr, 0xffffffff);
963  ASSERT_TRUE(handle == nullptr);
964  ASSERT_SUBSTR("invalid", dlerror());
965
966  // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
967  handle = dlopen(nullptr, RTLD_NOW|RTLD_LAZY);
968  ASSERT_TRUE(handle != nullptr);
969  ASSERT_SUBSTR(nullptr, dlerror());
970}
971
972TEST(dlfcn, rtld_default_unknown_symbol) {
973  void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
974  ASSERT_TRUE(addr == nullptr);
975}
976
977TEST(dlfcn, rtld_default_known_symbol) {
978  void* addr = dlsym(RTLD_DEFAULT, "fopen");
979  ASSERT_TRUE(addr != nullptr);
980}
981
982TEST(dlfcn, rtld_next_unknown_symbol) {
983  void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
984  ASSERT_TRUE(addr == nullptr);
985}
986
987TEST(dlfcn, rtld_next_known_symbol) {
988  void* addr = dlsym(RTLD_NEXT, "fopen");
989  ASSERT_TRUE(addr != nullptr);
990}
991
992TEST(dlfcn, dlsym_weak_func) {
993  dlerror();
994  void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW);
995  ASSERT_TRUE(handle != nullptr);
996
997  int (*weak_func)();
998  weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
999  ASSERT_TRUE(weak_func != nullptr) << "dlerror: " << dlerror();
1000  EXPECT_EQ(42, weak_func());
1001  dlclose(handle);
1002}
1003
1004TEST(dlfcn, dlopen_undefined_weak_func) {
1005  void* handle = dlopen("libtest_dlopen_weak_undefined_func.so", RTLD_NOW);
1006  ASSERT_TRUE(handle != nullptr) << dlerror();
1007  int (*weak_func)();
1008  weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "use_weak_undefined_func"));
1009  ASSERT_TRUE(weak_func != nullptr) << dlerror();
1010  EXPECT_EQ(6551, weak_func());
1011  dlclose(handle);
1012}
1013
1014TEST(dlfcn, dlopen_symlink) {
1015  void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
1016  void* handle2 = dlopen("libdlext_test_v2.so", RTLD_NOW);
1017  ASSERT_TRUE(handle1 != nullptr);
1018  ASSERT_TRUE(handle2 != nullptr);
1019  ASSERT_EQ(handle1, handle2);
1020  dlclose(handle1);
1021  dlclose(handle2);
1022}
1023
1024// libtest_dlopen_from_ctor_main.so depends on
1025// libtest_dlopen_from_ctor.so which has a constructor
1026// that calls dlopen(libc...). This is to test the situation
1027// described in b/7941716.
1028TEST(dlfcn, dlopen_dlopen_from_ctor) {
1029#if defined(__BIONIC__)
1030  void* handle = dlopen("libtest_dlopen_from_ctor_main.so", RTLD_NOW);
1031  ASSERT_TRUE(handle != nullptr) << dlerror();
1032  dlclose(handle);
1033#else
1034  GTEST_LOG_(INFO) << "This test is disabled for glibc (glibc segfaults if you try to call dlopen from a constructor).\n";
1035#endif
1036}
1037
1038TEST(dlfcn, symbol_versioning_use_v1) {
1039  void* handle = dlopen("libtest_versioned_uselibv1.so", RTLD_NOW);
1040  ASSERT_TRUE(handle != nullptr) << dlerror();
1041  typedef int (*fn_t)();
1042  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
1043  ASSERT_TRUE(fn != nullptr) << dlerror();
1044  ASSERT_EQ(1, fn());
1045  dlclose(handle);
1046}
1047
1048TEST(dlfcn, symbol_versioning_use_v2) {
1049  void* handle = dlopen("libtest_versioned_uselibv2.so", RTLD_NOW);
1050  ASSERT_TRUE(handle != nullptr) << dlerror();
1051  typedef int (*fn_t)();
1052  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
1053  ASSERT_TRUE(fn != nullptr) << dlerror();
1054  ASSERT_EQ(2, fn());
1055  dlclose(handle);
1056}
1057
1058TEST(dlfcn, symbol_versioning_use_other_v2) {
1059  void* handle = dlopen("libtest_versioned_uselibv2_other.so", RTLD_NOW);
1060  ASSERT_TRUE(handle != nullptr) << dlerror();
1061  typedef int (*fn_t)();
1062  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
1063  ASSERT_TRUE(fn != nullptr) << dlerror();
1064  ASSERT_EQ(20, fn());
1065  dlclose(handle);
1066}
1067
1068TEST(dlfcn, symbol_versioning_use_other_v3) {
1069  void* handle = dlopen("libtest_versioned_uselibv3_other.so", RTLD_NOW);
1070  ASSERT_TRUE(handle != nullptr) << dlerror();
1071  typedef int (*fn_t)();
1072  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
1073  ASSERT_TRUE(fn != nullptr) << dlerror();
1074  ASSERT_EQ(3, fn());
1075  dlclose(handle);
1076}
1077
1078TEST(dlfcn, symbol_versioning_default_via_dlsym) {
1079  void* handle = dlopen("libtest_versioned_lib.so", RTLD_NOW);
1080  ASSERT_TRUE(handle != nullptr) << dlerror();
1081  typedef int (*fn_t)();
1082  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "versioned_function"));
1083  ASSERT_TRUE(fn != nullptr) << dlerror();
1084  ASSERT_EQ(3, fn()); // the default version is 3
1085  dlclose(handle);
1086}
1087
1088TEST(dlfcn, dlvsym_smoke) {
1089  void* handle = dlopen("libtest_versioned_lib.so", RTLD_NOW);
1090  ASSERT_TRUE(handle != nullptr) << dlerror();
1091  typedef int (*fn_t)();
1092
1093  {
1094    fn_t fn = reinterpret_cast<fn_t>(dlvsym(handle, "versioned_function", "nonversion"));
1095    ASSERT_TRUE(fn == nullptr);
1096    ASSERT_SUBSTR("undefined symbol: versioned_function, version nonversion", dlerror());
1097  }
1098
1099  {
1100    fn_t fn = reinterpret_cast<fn_t>(dlvsym(handle, "versioned_function", "TESTLIB_V2"));
1101    ASSERT_TRUE(fn != nullptr) << dlerror();
1102    ASSERT_EQ(2, fn());
1103  }
1104
1105  dlclose(handle);
1106}
1107
1108// This preempts the implementation from libtest_versioned_lib.so
1109extern "C" int version_zero_function() {
1110  return 0;
1111}
1112
1113// This preempts the implementation from libtest_versioned_uselibv*.so
1114extern "C" int version_zero_function2() {
1115  return 0;
1116}
1117
1118TEST(dlfcn, dt_runpath_smoke) {
1119  void* handle = dlopen("libtest_dt_runpath_d.so", RTLD_NOW);
1120  ASSERT_TRUE(handle != nullptr) << dlerror();
1121
1122  typedef void *(* dlopen_b_fn)();
1123  dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
1124  ASSERT_TRUE(fn != nullptr) << dlerror();
1125
1126  void *p = fn();
1127  ASSERT_TRUE(p != nullptr);
1128
1129  dlclose(handle);
1130}
1131
1132TEST(dlfcn, dt_runpath_absolute_path) {
1133  void* handle = dlopen(PATH_TO_SYSTEM_LIB "libtest_dt_runpath_d.so", RTLD_NOW);
1134  ASSERT_TRUE(handle != nullptr) << dlerror();
1135
1136  typedef void *(* dlopen_b_fn)();
1137  dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
1138  ASSERT_TRUE(fn != nullptr) << dlerror();
1139
1140  void *p = fn();
1141  ASSERT_TRUE(p != nullptr);
1142
1143  dlclose(handle);
1144}
1145