dlfcn_test.cpp revision 279a22f96e639e76c801bdb39aee5576f2280fe0
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 "gtest_ex.h"
26#include "private/ScopeGuard.h"
27
28#include <string>
29
30#define ASSERT_SUBSTR(needle, haystack) \
31    ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
32
33static bool g_called = false;
34extern "C" void DlSymTestFunction() {
35  g_called = true;
36}
37
38static int g_ctor_function_called = 0;
39
40extern "C" void ctor_function() __attribute__ ((constructor));
41
42extern "C" void ctor_function() {
43  g_ctor_function_called = 17;
44}
45
46TEST(dlfcn, ctor_function_call) {
47  ASSERT_EQ(17, g_ctor_function_called);
48}
49
50TEST(dlfcn, dlsym_in_self) {
51  dlerror(); // Clear any pending errors.
52  void* self = dlopen(NULL, RTLD_NOW);
53  ASSERT_TRUE(self != NULL);
54  ASSERT_TRUE(dlerror() == NULL);
55
56  void* sym = dlsym(self, "DlSymTestFunction");
57  ASSERT_TRUE(sym != NULL);
58
59  void (*function)() = reinterpret_cast<void(*)()>(sym);
60
61  g_called = false;
62  function();
63  ASSERT_TRUE(g_called);
64
65  ASSERT_EQ(0, dlclose(self));
66}
67
68TEST(dlfcn, dlsym_with_dependencies) {
69  void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
70  ASSERT_TRUE(handle != NULL);
71  dlerror();
72  // This symbol is in DT_NEEDED library.
73  void* sym = dlsym(handle, "getRandomNumber");
74  ASSERT_TRUE(sym != NULL);
75  int (*fn)(void);
76  fn = reinterpret_cast<int (*)(void)>(sym);
77  EXPECT_EQ(4, fn());
78  dlclose(handle);
79}
80
81TEST(dlfcn, dlopen_noload) {
82  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
83  ASSERT_TRUE(handle == NULL);
84  handle = dlopen("libtest_simple.so", RTLD_NOW);
85  void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
86  ASSERT_TRUE(handle != NULL);
87  ASSERT_TRUE(handle2 != NULL);
88  ASSERT_TRUE(handle == handle2);
89  ASSERT_EQ(0, dlclose(handle));
90  ASSERT_EQ(0, dlclose(handle2));
91}
92
93// ifuncs are only supported on intel and arm64 for now
94#if defined (__aarch64__) || defined(__i386__) || defined(__x86_64__)
95TEST(dlfcn, ifunc) {
96  typedef const char* (*fn_ptr)();
97
98  // ifunc's choice depends on whether IFUNC_CHOICE has a value
99  // first check the set case
100  setenv("IFUNC_CHOICE", "set", 1);
101  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
102  ASSERT_TRUE(handle != NULL);
103  fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
104  fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
105  ASSERT_TRUE(foo_ptr != NULL);
106  ASSERT_TRUE(foo_library_ptr != NULL);
107  ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
108  ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
109  dlclose(handle);
110
111  // then check the unset case
112  unsetenv("IFUNC_CHOICE");
113  handle = dlopen("libtest_ifunc.so", RTLD_NOW);
114  ASSERT_TRUE(handle != NULL);
115  foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
116  foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
117  ASSERT_TRUE(foo_ptr != NULL);
118  ASSERT_TRUE(foo_library_ptr != NULL);
119  ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
120  ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
121  dlclose(handle);
122}
123
124TEST(dlfcn, ifunc_ctor_call) {
125  typedef const char* (*fn_ptr)();
126
127  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
128  ASSERT_TRUE(handle != nullptr) << dlerror();
129  fn_ptr is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
130  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
131  ASSERT_STREQ("false", is_ctor_called());
132
133  is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
134  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
135  ASSERT_STREQ("true", is_ctor_called());
136  dlclose(handle);
137}
138#endif
139
140TEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
141  // This is the structure of the test library and
142  // its dt_needed libraries
143  // libtest_relo_check_dt_needed_order.so
144  // |
145  // +-> libtest_relo_check_dt_needed_order_1.so
146  // |
147  // +-> libtest_relo_check_dt_needed_order_2.so
148  //
149  // The root library references relo_test_get_answer_lib - which is defined
150  // in both dt_needed libraries, the correct relocation should
151  // use the function defined in libtest_relo_check_dt_needed_order_1.so
152  void* handle = nullptr;
153  auto guard = make_scope_guard([&]() {
154    dlclose(handle);
155  });
156
157  handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
158  ASSERT_TRUE(handle != nullptr) << dlerror();
159
160  typedef int (*fn_t) (void);
161  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
162  ASSERT_TRUE(fn != nullptr) << dlerror();
163  ASSERT_EQ(1, fn());
164}
165
166TEST(dlfcn, dlopen_check_order_dlsym) {
167  // Here is how the test library and its dt_needed
168  // libraries are arranged
169  //
170  //  libtest_check_order_children.so
171  //  |
172  //  +-> ..._1_left.so
173  //  |   |
174  //  |   +-> ..._a.so
175  //  |   |
176  //  |   +-> ...r_b.so
177  //  |
178  //  +-> ..._2_right.so
179  //  |   |
180  //  |   +-> ..._d.so
181  //  |       |
182  //  |       +-> ..._b.so
183  //  |
184  //  +-> ..._3_c.so
185  //
186  //  load order should be (1, 2, 3, a, b, d)
187  //
188  // get_answer() is defined in (2, 3, a, b, c)
189  // get_answer2() is defined in (b, d)
190  void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer");
191  ASSERT_TRUE(sym == nullptr);
192  void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL);
193  ASSERT_TRUE(handle != nullptr) << dlerror();
194  typedef int (*fn_t) (void);
195  fn_t fn, fn2;
196  fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"));
197  ASSERT_TRUE(fn != NULL) << dlerror();
198  fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2"));
199  ASSERT_TRUE(fn2 != NULL) << dlerror();
200
201  ASSERT_EQ(42, fn());
202  ASSERT_EQ(43, fn2());
203  dlclose(handle);
204}
205
206TEST(dlfcn, dlopen_check_order_reloc_siblings) {
207  // This is how this one works:
208  // we lookup and call get_answer which is defined in '_2.so'
209  // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so'
210  // the correct _impl() is implemented by '_a.so';
211  //
212  // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?)
213  //
214  // Here is the picture:
215  //
216  // libtest_check_order_reloc_siblings.so
217  // |
218  // +-> ..._1.so <- empty
219  // |   |
220  // |   +-> ..._a.so <- exports correct answer_impl()
221  // |   |
222  // |   +-> ..._b.so <- every other letter exporting incorrect one.
223  // |
224  // +-> ..._2.so <- empty
225  // |   |
226  // |   +-> ..._c.so
227  // |   |
228  // |   +-> ..._d.so
229  // |
230  // +-> ..._3.so <- empty
231  //     |
232  //     +-> ..._e.so
233  //     |
234  //     +-> ..._f.so <- exports get_answer() that calls get_anser_impl();
235  //                     implements incorrect get_answer_impl()
236
237  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
238  ASSERT_TRUE(handle == nullptr);
239#ifdef __BIONIC__
240  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
241  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
242#endif
243
244  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
245  ASSERT_TRUE(handle != nullptr) << dlerror();
246
247  typedef int (*fn_t) (void);
248  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
249  ASSERT_TRUE(fn != nullptr) << dlerror();
250  ASSERT_EQ(42, fn());
251
252  ASSERT_EQ(0, dlclose(handle));
253}
254
255TEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) {
256  // This test uses the same library as dlopen_check_order_reloc_siblings.
257  // Unlike dlopen_check_order_reloc_siblings it preloads
258  // libtest_check_order_reloc_siblings_1.so (first dependency) prior to
259  // dlopen(libtest_check_order_reloc_siblings.so)
260
261  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
262  ASSERT_TRUE(handle == nullptr);
263  handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD);
264  ASSERT_TRUE(handle == nullptr);
265
266  void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL);
267  ASSERT_TRUE(handle_for_1 != nullptr) << dlerror();
268
269  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
270  ASSERT_TRUE(handle != nullptr) << dlerror();
271
272  ASSERT_EQ(0, dlclose(handle_for_1));
273
274  typedef int (*fn_t) (void);
275  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
276  ASSERT_TRUE(fn != nullptr) << dlerror();
277  ASSERT_EQ(42, fn());
278
279  ASSERT_EQ(0, dlclose(handle));
280}
281
282TEST(dlfcn, dlopen_check_order_reloc_grandchild) {
283  // This is how this one works:
284  // we lookup and call grandchild_get_answer which is defined in '_2.so'
285  // and in turn calls external get_answer_impl() defined in '_c_1.so and _c_2.so'
286  // the correct _impl() is implemented by '_c_1.so';
287  //
288  // Here is the picture of subtree:
289  //
290  // libtest_check_order_reloc_siblings.so
291  // |
292  // +-> ..._2.so <- grandchild_get_answer()
293  //     |
294  //     +-> ..._c.so <- empty
295  //     |   |
296  //     |   +-> _c_1.so <- exports correct answer_impl()
297  //     |   |
298  //     |   +-> _c_2.so <- exports incorrect answer_impl()
299  //     |
300  //     +-> ..._d.so <- empty
301
302  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
303  ASSERT_TRUE(handle == nullptr);
304#ifdef __BIONIC__
305  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
306  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
307#endif
308
309  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
310  ASSERT_TRUE(handle != nullptr) << dlerror();
311
312  typedef int (*fn_t) (void);
313  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_grandchild_get_answer"));
314  ASSERT_TRUE(fn != nullptr) << dlerror();
315  ASSERT_EQ(42, fn());
316
317  ASSERT_EQ(0, dlclose(handle));
318}
319
320TEST(dlfcn, dlopen_check_order_reloc_nephew) {
321  // This is how this one works:
322  // we lookup and call nephew_get_answer which is defined in '_2.so'
323  // and in turn calls external get_answer_impl() defined in '_[a-f].so'
324  // the correct _impl() is implemented by '_a.so';
325  //
326  // Here is the picture:
327  //
328  // libtest_check_order_reloc_siblings.so
329  // |
330  // +-> ..._1.so <- empty
331  // |   |
332  // |   +-> ..._a.so <- exports correct answer_impl()
333  // |   |
334  // |   +-> ..._b.so <- every other letter exporting incorrect one.
335  // |
336  // +-> ..._2.so <- empty
337  // |   |
338  // |   +-> ..._c.so
339  // |   |
340  // |   +-> ..._d.so
341  // |
342  // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl();
343  //     |
344  //     +-> ..._e.so
345  //     |
346  //     +-> ..._f.so
347
348  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
349  ASSERT_TRUE(handle == nullptr);
350#ifdef __BIONIC__
351  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
352  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
353#endif
354
355  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
356  ASSERT_TRUE(handle != nullptr) << dlerror();
357
358  typedef int (*fn_t) (void);
359  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_nephew_get_answer"));
360  ASSERT_TRUE(fn != nullptr) << dlerror();
361  ASSERT_EQ(42, fn());
362
363  ASSERT_EQ(0, dlclose(handle));
364}
365
366TEST(dlfcn, check_unload_after_reloc) {
367  // This is how this one works:
368  // libtest_two_parents_parent1 <- answer_impl() used by libtest_two_parents_child
369  // |
370  // +-> libtest_two_parents_child
371  //
372  // libtest_two_parents_parent2 <- answer_impl() not used by libtest_two_parents_child
373  // |
374  // +-> libtest_two_parents_child
375  //
376  // Test dlopens parent1 which loads and relocates libtest_two_parents_child.so
377  // as a second step it dlopens parent2 and dlcloses parent1...
378
379  test_isolated([] {
380    void* handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL);
381    ASSERT_TRUE(handle != nullptr) << dlerror();
382
383    void* handle2 = dlopen("libtest_two_parents_parent2.so", RTLD_NOW | RTLD_LOCAL);
384    ASSERT_TRUE(handle2 != nullptr) << dlerror();
385
386    typedef int (*fn_t) (void);
387    fn_t fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
388    ASSERT_TRUE(fn != nullptr) << dlerror();
389    ASSERT_EQ(42, fn());
390
391    ASSERT_EQ(0, dlclose(handle));
392
393    handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
394    ASSERT_TRUE(handle != nullptr);
395    ASSERT_EQ(0, dlclose(handle));
396
397    fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
398    ASSERT_TRUE(fn != nullptr) << dlerror();
399    ASSERT_EQ(42, fn());
400
401    ASSERT_EQ(0, dlclose(handle2));
402
403    handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
404    ASSERT_TRUE(handle == nullptr);
405  });
406}
407
408extern "C" int check_order_reloc_root_get_answer_impl() {
409  return 42;
410}
411
412TEST(dlfcn, dlopen_check_order_reloc_main_executable) {
413  // This is how this one works:
414  // we lookup and call get_answer3 which is defined in 'root.so'
415  // and in turn calls external root_get_answer_impl() defined in _2.so and
416  // above the correct _impl() is one in the executable.
417  //
418  // libtest_check_order_reloc_root.so
419  // |
420  // +-> ..._1.so <- empty
421  // |
422  // +-> ..._2.so <- gives incorrect answer for answer_main_impl()
423  //
424
425  void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD);
426  ASSERT_TRUE(handle == nullptr);
427#ifdef __BIONIC__
428  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
429  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
430#endif
431
432  handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL);
433  ASSERT_TRUE(handle != nullptr) << dlerror();
434
435  typedef int (*fn_t) (void);
436  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_root_get_answer"));
437  ASSERT_TRUE(fn != nullptr) << dlerror();
438  ASSERT_EQ(42, fn());
439
440  ASSERT_EQ(0, dlclose(handle));
441}
442
443TEST(dlfcn, dlopen_check_rtld_local) {
444  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
445  ASSERT_TRUE(sym == nullptr);
446
447  // implicit RTLD_LOCAL
448  void* handle = dlopen("libtest_simple.so", RTLD_NOW);
449  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
450  ASSERT_TRUE(sym == nullptr);
451  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
452  sym = dlsym(handle, "dlopen_testlib_simple_func");
453  ASSERT_TRUE(sym != nullptr);
454  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
455  dlclose(handle);
456
457  // explicit RTLD_LOCAL
458  handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL);
459  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
460  ASSERT_TRUE(sym == nullptr);
461  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
462  sym = dlsym(handle, "dlopen_testlib_simple_func");
463  ASSERT_TRUE(sym != nullptr);
464  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
465  dlclose(handle);
466}
467
468TEST(dlfcn, dlopen_check_rtld_global) {
469  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
470  ASSERT_TRUE(sym == nullptr);
471
472  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL);
473  ASSERT_TRUE(handle != nullptr) << dlerror();
474  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
475  ASSERT_TRUE(sym != nullptr) << dlerror();
476  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
477  dlclose(handle);
478
479  // RTLD_GLOBAL implies RTLD_NODELETE, let's check that
480  void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
481  ASSERT_EQ(sym, sym_after_dlclose);
482}
483
484// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
485// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so ->
486// libtest_with_dependency_loop_a.so
487TEST(dlfcn, dlopen_check_loop) {
488  test_isolated([] {
489    void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW);
490    ASSERT_TRUE(handle != nullptr) << dlerror();
491    void* f = dlsym(handle, "dlopen_test_loopy_function");
492    ASSERT_TRUE(f != nullptr) << dlerror();
493    EXPECT_TRUE(reinterpret_cast<bool (*)(void)>(f)());
494    ASSERT_EQ(0, dlclose(handle));
495
496    // dlopen second time to make sure that the library was unloaded correctly
497    handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
498    ASSERT_TRUE(handle == nullptr);
499#ifdef __BIONIC__
500    // TODO: glibc returns nullptr on dlerror() here. Is it bug?
501    ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
502#endif
503
504    handle = dlopen("libtest_with_dependency_a.so", RTLD_NOW | RTLD_NOLOAD);
505    ASSERT_TRUE(handle == nullptr);
506  });
507}
508
509TEST(dlfcn, dlopen_nodelete) {
510  static bool is_unloaded = false;
511
512  void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE);
513  ASSERT_TRUE(handle != nullptr) << dlerror();
514  void (*set_unload_flag_ptr)(bool*);
515  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr"));
516  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
517  set_unload_flag_ptr(&is_unloaded);
518
519  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
520  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
521  ASSERT_EQ(1729U, *taxicab_number);
522  *taxicab_number = 2;
523
524  dlclose(handle);
525  ASSERT_TRUE(!is_unloaded);
526
527  uint32_t* taxicab_number_after_dlclose = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
528  ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number);
529  ASSERT_EQ(2U, *taxicab_number_after_dlclose);
530
531
532  handle = dlopen("libtest_nodelete_1.so", RTLD_NOW);
533  uint32_t* taxicab_number2 = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
534  ASSERT_EQ(taxicab_number2, taxicab_number);
535
536  ASSERT_EQ(2U, *taxicab_number2);
537
538  dlclose(handle);
539  ASSERT_TRUE(!is_unloaded);
540}
541
542TEST(dlfcn, dlopen_nodelete_on_second_dlopen) {
543  static bool is_unloaded = false;
544
545  void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW);
546  ASSERT_TRUE(handle != nullptr) << dlerror();
547  void (*set_unload_flag_ptr)(bool*);
548  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr"));
549  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
550  set_unload_flag_ptr(&is_unloaded);
551
552  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_2_taxicab_number"));
553  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
554
555  ASSERT_EQ(1729U, *taxicab_number);
556  *taxicab_number = 2;
557
558  // This RTLD_NODELETE should be ignored
559  void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE);
560  ASSERT_TRUE(handle1 != nullptr) << dlerror();
561  ASSERT_EQ(handle, handle1);
562
563  dlclose(handle1);
564  dlclose(handle);
565
566  ASSERT_TRUE(is_unloaded);
567}
568
569TEST(dlfcn, dlopen_nodelete_dt_flags_1) {
570  static bool is_unloaded = false;
571
572  void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW);
573  ASSERT_TRUE(handle != nullptr) << dlerror();
574  void (*set_unload_flag_ptr)(bool*);
575  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr"));
576  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
577  set_unload_flag_ptr(&is_unloaded);
578
579  dlclose(handle);
580  ASSERT_TRUE(!is_unloaded);
581}
582
583TEST(dlfcn, dlsym_df_1_global) {
584#if !defined(__arm__) && !defined(__aarch64__)
585  void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW);
586  ASSERT_TRUE(handle != nullptr) << dlerror();
587  int (*get_answer)();
588  get_answer = reinterpret_cast<int (*)()>(dlsym(handle, "dl_df_1_global_get_answer"));
589  ASSERT_TRUE(get_answer != nullptr) << dlerror();
590  ASSERT_EQ(42, get_answer());
591  ASSERT_EQ(0, dlclose(handle));
592#else
593  GTEST_LOG_(INFO) << "This test does nothing on arm/arm64 (to be reenabled once b/18137520 or b/18130452 are fixed).\n";
594#endif
595}
596
597TEST(dlfcn, dlopen_failure) {
598  void* self = dlopen("/does/not/exist", RTLD_NOW);
599  ASSERT_TRUE(self == NULL);
600#if defined(__BIONIC__)
601  ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
602#else
603  ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
604#endif
605}
606
607static void* ConcurrentDlErrorFn(void*) {
608  dlopen("/child/thread", RTLD_NOW);
609  return reinterpret_cast<void*>(strdup(dlerror()));
610}
611
612TEST(dlfcn, dlerror_concurrent) {
613  dlopen("/main/thread", RTLD_NOW);
614  const char* main_thread_error = dlerror();
615  ASSERT_SUBSTR("/main/thread", main_thread_error);
616
617  pthread_t t;
618  ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentDlErrorFn, NULL));
619  void* result;
620  ASSERT_EQ(0, pthread_join(t, &result));
621  char* child_thread_error = static_cast<char*>(result);
622  ASSERT_SUBSTR("/child/thread", child_thread_error);
623  free(child_thread_error);
624
625  ASSERT_SUBSTR("/main/thread", main_thread_error);
626}
627
628TEST(dlfcn, dlsym_failures) {
629  dlerror(); // Clear any pending errors.
630  void* self = dlopen(NULL, RTLD_NOW);
631  ASSERT_TRUE(self != NULL);
632  ASSERT_TRUE(dlerror() == NULL);
633
634  void* sym;
635
636#if defined(__BIONIC__) && !defined(__LP64__)
637  // RTLD_DEFAULT in lp32 bionic is not (void*)0
638  // so it can be distinguished from the NULL handle.
639  sym = dlsym(NULL, "test");
640  ASSERT_TRUE(sym == NULL);
641  ASSERT_SUBSTR("dlsym library handle is null", dlerror());
642#endif
643
644  // NULL symbol name.
645#if defined(__BIONIC__)
646  // glibc marks this parameter non-null and SEGVs if you cheat.
647  sym = dlsym(self, NULL);
648  ASSERT_TRUE(sym == NULL);
649  ASSERT_SUBSTR("", dlerror());
650#endif
651
652  // Symbol that doesn't exist.
653  sym = dlsym(self, "ThisSymbolDoesNotExist");
654  ASSERT_TRUE(sym == NULL);
655  ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
656
657  ASSERT_EQ(0, dlclose(self));
658}
659
660TEST(dlfcn, dladdr) {
661  dlerror(); // Clear any pending errors.
662  void* self = dlopen(NULL, RTLD_NOW);
663  ASSERT_TRUE(self != NULL);
664  ASSERT_TRUE(dlerror() == NULL);
665
666  void* sym = dlsym(self, "DlSymTestFunction");
667  ASSERT_TRUE(sym != NULL);
668
669  // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
670  void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
671
672  Dl_info info;
673  int rc = dladdr(addr, &info);
674  ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
675
676  // Get the name of this executable.
677  char executable_path[PATH_MAX];
678  rc = readlink("/proc/self/exe", executable_path, sizeof(executable_path));
679  ASSERT_NE(rc, -1);
680  executable_path[rc] = '\0';
681  std::string executable_name(basename(executable_path));
682
683  // The filename should be that of this executable.
684  // Note that we don't know whether or not we have the full path, so we want an "ends_with" test.
685  std::string dli_fname(info.dli_fname);
686  dli_fname = basename(&dli_fname[0]);
687  ASSERT_EQ(dli_fname, executable_name);
688
689  // The symbol name should be the symbol we looked up.
690  ASSERT_STREQ(info.dli_sname, "DlSymTestFunction");
691
692  // The address should be the exact address of the symbol.
693  ASSERT_EQ(info.dli_saddr, sym);
694
695  // Look in /proc/pid/maps to find out what address we were loaded at.
696  // TODO: factor /proc/pid/maps parsing out into a class and reuse all over bionic.
697  void* base_address = NULL;
698  char line[BUFSIZ];
699  FILE* fp = fopen("/proc/self/maps", "r");
700  ASSERT_TRUE(fp != NULL);
701  while (fgets(line, sizeof(line), fp) != NULL) {
702    uintptr_t start = strtoul(line, 0, 16);
703    line[strlen(line) - 1] = '\0'; // Chomp the '\n'.
704    char* path = strchr(line, '/');
705    if (path != NULL && strcmp(executable_path, path) == 0) {
706      base_address = reinterpret_cast<void*>(start);
707      break;
708    }
709  }
710  fclose(fp);
711
712  // The base address should be the address we were loaded at.
713  ASSERT_EQ(info.dli_fbase, base_address);
714
715  ASSERT_EQ(0, dlclose(self));
716}
717
718TEST(dlfcn, dladdr_invalid) {
719  Dl_info info;
720
721  dlerror(); // Clear any pending errors.
722
723  // No symbol corresponding to NULL.
724  ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success.
725  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
726
727  // No symbol corresponding to a stack address.
728  ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
729  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
730}
731
732// GNU-style ELF hash tables are incompatible with the MIPS ABI.
733// MIPS requires .dynsym to be sorted to match the GOT but GNU-style requires sorting by hash code.
734TEST(dlfcn, dlopen_library_with_only_gnu_hash) {
735#if !defined(__mips__)
736  dlerror(); // Clear any pending errors.
737  void* handle = dlopen("libgnu-hash-table-library.so", RTLD_NOW);
738  ASSERT_TRUE(handle != nullptr) << dlerror();
739  auto guard = make_scope_guard([&]() {
740    dlclose(handle);
741  });
742  void* sym = dlsym(handle, "getRandomNumber");
743  ASSERT_TRUE(sym != nullptr) << dlerror();
744  int (*fn)(void);
745  fn = reinterpret_cast<int (*)(void)>(sym);
746  EXPECT_EQ(4, fn());
747
748  Dl_info dlinfo;
749  ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
750
751  ASSERT_TRUE(fn == dlinfo.dli_saddr);
752  ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
753  ASSERT_SUBSTR("libgnu-hash-table-library.so", dlinfo.dli_fname);
754#else
755  GTEST_LOG_(INFO) << "This test does nothing for mips/mips64; mips toolchain does not support '--hash-style=gnu'\n";
756#endif
757}
758
759TEST(dlfcn, dlopen_library_with_only_sysv_hash) {
760  void* handle = dlopen("libsysv-hash-table-library.so", RTLD_NOW);
761  ASSERT_TRUE(handle != nullptr) << dlerror();
762  auto guard = make_scope_guard([&]() {
763    dlclose(handle);
764  });
765  void* sym = dlsym(handle, "getRandomNumber");
766  ASSERT_TRUE(sym != nullptr) << dlerror();
767  int (*fn)(void);
768  fn = reinterpret_cast<int (*)(void)>(sym);
769  EXPECT_EQ(4, fn());
770
771  Dl_info dlinfo;
772  ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
773
774  ASSERT_TRUE(fn == dlinfo.dli_saddr);
775  ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
776  ASSERT_SUBSTR("libsysv-hash-table-library.so", dlinfo.dli_fname);
777}
778
779TEST(dlfcn, dlopen_bad_flags) {
780  dlerror(); // Clear any pending errors.
781  void* handle;
782
783#if defined(__GLIBC__)
784  // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
785  handle = dlopen(NULL, 0);
786  ASSERT_TRUE(handle == NULL);
787  ASSERT_SUBSTR("invalid", dlerror());
788#endif
789
790  handle = dlopen(NULL, 0xffffffff);
791  ASSERT_TRUE(handle == NULL);
792  ASSERT_SUBSTR("invalid", dlerror());
793
794  // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
795  handle = dlopen(NULL, RTLD_NOW|RTLD_LAZY);
796  ASSERT_TRUE(handle != NULL);
797  ASSERT_SUBSTR(NULL, dlerror());
798}
799
800TEST(dlfcn, rtld_default_unknown_symbol) {
801  void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
802  ASSERT_TRUE(addr == NULL);
803}
804
805TEST(dlfcn, rtld_default_known_symbol) {
806  void* addr = dlsym(RTLD_DEFAULT, "fopen");
807  ASSERT_TRUE(addr != NULL);
808}
809
810TEST(dlfcn, rtld_next_unknown_symbol) {
811  void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
812  ASSERT_TRUE(addr == NULL);
813}
814
815TEST(dlfcn, rtld_next_known_symbol) {
816  void* addr = dlsym(RTLD_NEXT, "fopen");
817  ASSERT_TRUE(addr != NULL);
818}
819
820TEST(dlfcn, dlsym_weak_func) {
821  dlerror();
822  void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW);
823  ASSERT_TRUE(handle != NULL);
824
825  int (*weak_func)();
826  weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
827  ASSERT_TRUE(weak_func != NULL) << "dlerror: " << dlerror();
828  EXPECT_EQ(42, weak_func());
829  dlclose(handle);
830}
831
832TEST(dlfcn, dlopen_undefined_weak_func) {
833  test_isolated([] {
834    void* handle = dlopen("libtest_dlopen_weak_undefined_func.so", RTLD_NOW);
835    ASSERT_TRUE(handle != nullptr) << dlerror();
836    int (*weak_func)();
837    weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "use_weak_undefined_func"));
838    ASSERT_TRUE(weak_func != nullptr) << dlerror();
839    EXPECT_EQ(6551, weak_func());
840    dlclose(handle);
841  });
842}
843
844TEST(dlfcn, dlopen_symlink) {
845  void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
846  void* handle2 = dlopen("libdlext_test_v2.so", RTLD_NOW);
847  ASSERT_TRUE(handle1 != NULL);
848  ASSERT_TRUE(handle2 != NULL);
849  ASSERT_EQ(handle1, handle2);
850  dlclose(handle1);
851  dlclose(handle2);
852}
853
854// libtest_dlopen_from_ctor_main.so depends on
855// libtest_dlopen_from_ctor.so which has a constructor
856// that calls dlopen(libc...). This is to test the situation
857// described in b/7941716.
858TEST(dlfcn, dlopen_dlopen_from_ctor) {
859#if defined(__BIONIC__)
860  void* handle = dlopen("libtest_dlopen_from_ctor_main.so", RTLD_NOW);
861  ASSERT_TRUE(handle != nullptr) << dlerror();
862  dlclose(handle);
863#else
864  GTEST_LOG_(INFO) << "This test is disabled for glibc (glibc segfaults if you try to call dlopen from a constructor).\n";
865#endif
866}
867