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 <limits.h>
21#include <stdio.h>
22#include <stdint.h>
23#include <string.h>
24#if __has_include(<sys/auxv.h>)
25#include <sys/auxv.h>
26#endif
27#include <sys/user.h>
28
29#include <string>
30#include <thread>
31
32#include <android-base/scopeguard.h>
33
34#include "gtest_globals.h"
35#include "dlfcn_symlink_support.h"
36#include "utils.h"
37
38#if defined(__BIONIC__) && (defined(__arm__) || defined(__i386__))
39#pragma clang diagnostic push
40#pragma clang diagnostic ignored "-Wunused-parameter"
41
42#include <llvm/ADT/StringRef.h>
43#include <llvm/Object/Binary.h>
44#include <llvm/Object/ELFObjectFile.h>
45#include <llvm/Object/ObjectFile.h>
46
47#pragma clang diagnostic pop
48#endif //  defined(__ANDROID__) && (defined(__arm__) || defined(__i386__))
49
50#define ASSERT_SUBSTR(needle, haystack) \
51    ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
52
53
54static bool g_called = false;
55extern "C" void DlSymTestFunction() {
56  g_called = true;
57}
58
59static int g_ctor_function_called = 0;
60static int g_ctor_argc = 0;
61static char** g_ctor_argv = reinterpret_cast<char**>(0xDEADBEEF);
62static char** g_ctor_envp = g_ctor_envp;
63
64extern "C" void ctor_function(int argc, char** argv, char** envp) __attribute__ ((constructor));
65
66extern "C" void ctor_function(int argc, char** argv, char** envp) {
67  g_ctor_function_called = 17;
68  g_ctor_argc = argc;
69  g_ctor_argv = argv;
70  g_ctor_envp = envp;
71}
72
73TEST(dlfcn, ctor_function_call) {
74  ASSERT_EQ(17, g_ctor_function_called);
75  ASSERT_TRUE(g_ctor_argc = get_argc());
76  ASSERT_TRUE(g_ctor_argv = get_argv());
77  ASSERT_TRUE(g_ctor_envp = get_envp());
78}
79
80TEST(dlfcn, dlsym_in_executable) {
81  dlerror(); // Clear any pending errors.
82  void* self = dlopen(nullptr, RTLD_NOW);
83  ASSERT_TRUE(self != nullptr);
84  ASSERT_TRUE(dlerror() == nullptr);
85
86  void* sym = dlsym(self, "DlSymTestFunction");
87  ASSERT_TRUE(sym != nullptr);
88
89  void (*function)() = reinterpret_cast<void(*)()>(sym);
90
91  g_called = false;
92  function();
93  ASSERT_TRUE(g_called);
94
95  ASSERT_EQ(0, dlclose(self));
96}
97
98TEST(dlfcn, dlsym_from_sofile) {
99  void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_LAZY | RTLD_LOCAL);
100  ASSERT_TRUE(handle != nullptr) << dlerror();
101
102  // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
103  void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
104  ASSERT_TRUE(symbol == nullptr);
105  ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
106
107  typedef int* (*fn_t)();
108  fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT =
109      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
110  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror();
111
112  int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT();
113  ASSERT_TRUE(ptr != nullptr) << dlerror();
114  ASSERT_EQ(42, *ptr);
115
116  fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT =
117      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT"));
118  ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror();
119
120  ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT();
121  ASSERT_TRUE(ptr != nullptr) << dlerror();
122  ASSERT_EQ(44, *ptr);
123
124  fn_t lookup_dlsym_symbol_using_RTLD_NEXT =
125      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT"));
126  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror();
127
128  ptr = lookup_dlsym_symbol_using_RTLD_NEXT();
129  ASSERT_TRUE(ptr != nullptr) << dlerror();
130  ASSERT_EQ(43, *ptr);
131
132  dlclose(handle);
133}
134
135TEST(dlfcn, dlsym_from_sofile_with_preload) {
136  void* preload = dlopen("libtest_dlsym_from_this_grandchild.so", RTLD_NOW | RTLD_LOCAL);
137  ASSERT_TRUE(preload != nullptr) << dlerror();
138
139  void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW | RTLD_LOCAL);
140  ASSERT_TRUE(handle != nullptr) << dlerror();
141
142  // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
143  void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
144  ASSERT_TRUE(symbol == nullptr);
145  ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
146
147  typedef int* (*fn_t)();
148  fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT =
149      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
150  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror();
151
152  int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT();
153  ASSERT_TRUE(ptr != nullptr) << dlerror();
154  ASSERT_EQ(42, *ptr);
155
156  fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT =
157      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT"));
158  ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror();
159
160  ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT();
161  ASSERT_TRUE(ptr != nullptr) << dlerror();
162  ASSERT_EQ(44, *ptr);
163
164  fn_t lookup_dlsym_symbol_using_RTLD_NEXT =
165      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT"));
166  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror();
167
168  ptr = lookup_dlsym_symbol_using_RTLD_NEXT();
169  ASSERT_TRUE(ptr != nullptr) << dlerror();
170  ASSERT_EQ(43, *ptr);
171
172  dlclose(handle);
173  dlclose(preload);
174}
175
176TEST(dlfcn, dlsym_handle_global_sym) {
177  // check that we do not look into global group
178  // when looking up symbol by handle
179  void* handle = dlopen("libtest_empty.so", RTLD_NOW);
180  dlopen("libtest_with_dependency.so", RTLD_NOW | RTLD_GLOBAL);
181  void* sym = dlsym(handle, "getRandomNumber");
182  ASSERT_TRUE(sym == nullptr);
183  ASSERT_SUBSTR("undefined symbol: getRandomNumber", dlerror());
184
185  sym = dlsym(handle, "DlSymTestFunction");
186  ASSERT_TRUE(sym == nullptr);
187  ASSERT_SUBSTR("undefined symbol: DlSymTestFunction", dlerror());
188  dlclose(handle);
189}
190
191TEST(dlfcn, dlsym_handle_empty_symbol) {
192  // check that dlsym of an empty symbol fails (see http://b/33530622)
193  void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW);
194  ASSERT_TRUE(handle != nullptr) << dlerror();
195  void* sym = dlsym(handle, "");
196  ASSERT_TRUE(sym == nullptr);
197  ASSERT_SUBSTR("undefined symbol: ", dlerror());
198  dlclose(handle);
199}
200
201TEST(dlfcn, dlsym_with_dependencies) {
202  void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
203  ASSERT_TRUE(handle != nullptr);
204  dlerror();
205  // This symbol is in DT_NEEDED library.
206  void* sym = dlsym(handle, "getRandomNumber");
207  ASSERT_TRUE(sym != nullptr) << dlerror();
208  int (*fn)(void);
209  fn = reinterpret_cast<int (*)(void)>(sym);
210  EXPECT_EQ(4, fn());
211  dlclose(handle);
212}
213
214TEST(dlfcn, dlopen_noload) {
215  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
216  ASSERT_TRUE(handle == nullptr);
217  handle = dlopen("libtest_simple.so", RTLD_NOW);
218  void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
219  ASSERT_TRUE(handle != nullptr);
220  ASSERT_TRUE(handle2 != nullptr);
221  ASSERT_TRUE(handle == handle2);
222  ASSERT_EQ(0, dlclose(handle));
223  ASSERT_EQ(0, dlclose(handle2));
224}
225
226TEST(dlfcn, dlopen_by_soname) {
227  static const char* soname = "libdlext_test_soname.so";
228  static const char* filename = "libdlext_test_different_soname.so";
229  // 1. Make sure there is no library with soname in default search path
230  void* handle = dlopen(soname, RTLD_NOW);
231  ASSERT_TRUE(handle == nullptr);
232
233  // 2. Load a library using filename
234  handle = dlopen(filename, RTLD_NOW);
235  ASSERT_TRUE(handle != nullptr) << dlerror();
236
237  // 3. Find library by soname
238  void* handle_soname = dlopen(soname, RTLD_NOW | RTLD_NOLOAD);
239  ASSERT_TRUE(handle_soname != nullptr) << dlerror();
240  ASSERT_EQ(handle, handle_soname);
241
242  // 4. RTLD_NOLOAD should still work with filename
243  void* handle_filename = dlopen(filename, RTLD_NOW | RTLD_NOLOAD);
244  ASSERT_TRUE(handle_filename != nullptr) << dlerror();
245  ASSERT_EQ(handle, handle_filename);
246
247  dlclose(handle_filename);
248  dlclose(handle_soname);
249  dlclose(handle);
250}
251
252TEST(dlfcn, dlopen_vdso) {
253#if __has_include(<sys/auxv.h>)
254  if (getauxval(AT_SYSINFO_EHDR) == 0) {
255    GTEST_LOG_(INFO) << "getauxval(AT_SYSINFO_EHDR) == 0, skipping this test.";
256    return;
257  }
258#endif
259
260  const char* vdso_name = "linux-vdso.so.1";
261#if defined(__i386__)
262  vdso_name = "linux-gate.so.1";
263#endif
264  void* handle = dlopen(vdso_name, RTLD_NOW);
265  ASSERT_TRUE(handle != nullptr) << dlerror();
266  dlclose(handle);
267}
268
269// mips doesn't support ifuncs
270#if !defined(__mips__)
271TEST(dlfcn, ifunc_variable) {
272  typedef const char* (*fn_ptr)();
273
274  // ifunc's choice depends on whether IFUNC_CHOICE has a value
275  // first check the set case
276  setenv("IFUNC_CHOICE", "set", 1);
277  // preload libtest_ifunc_variable_impl.so
278  void* handle_impl = dlopen("libtest_ifunc_variable_impl.so", RTLD_NOW);
279  void* handle = dlopen("libtest_ifunc_variable.so", RTLD_NOW);
280  ASSERT_TRUE(handle != nullptr) << dlerror();
281  const char** foo_ptr = reinterpret_cast<const char**>(dlsym(handle, "foo"));
282  fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
283  ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
284  ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
285  ASSERT_EQ(strncmp("set", *foo_ptr, 3), 0);
286  ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
287  dlclose(handle);
288  dlclose(handle_impl);
289
290  // then check the unset case
291  unsetenv("IFUNC_CHOICE");
292  handle_impl = dlopen("libtest_ifunc_variable_impl.so", RTLD_NOW);
293  handle = dlopen("libtest_ifunc_variable.so", RTLD_NOW);
294  ASSERT_TRUE(handle != nullptr) << dlerror();
295  foo_ptr = reinterpret_cast<const char**>(dlsym(handle, "foo"));
296  foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
297  ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
298  ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
299  ASSERT_EQ(strncmp("unset", *foo_ptr, 5), 0);
300  ASSERT_EQ(strncmp("unset", foo_library_ptr(), 5), 0);
301  dlclose(handle);
302  dlclose(handle_impl);
303}
304
305TEST(dlfcn, ifunc) {
306  typedef const char* (*fn_ptr)();
307
308  // ifunc's choice depends on whether IFUNC_CHOICE has a value
309  // first check the set case
310  setenv("IFUNC_CHOICE", "set", 1);
311  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
312  ASSERT_TRUE(handle != nullptr) << dlerror();
313  fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
314  fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
315  ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
316  ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
317  ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
318  ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
319  dlclose(handle);
320
321  // then check the unset case
322  unsetenv("IFUNC_CHOICE");
323  handle = dlopen("libtest_ifunc.so", RTLD_NOW);
324  ASSERT_TRUE(handle != nullptr) << dlerror();
325  foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
326  foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
327  ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
328  ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
329  ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
330  ASSERT_EQ(strncmp("unset", foo_library_ptr(), 5), 0);
331  dlclose(handle);
332}
333
334TEST(dlfcn, ifunc_ctor_call) {
335  typedef const char* (*fn_ptr)();
336
337  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
338  ASSERT_TRUE(handle != nullptr) << dlerror();
339  fn_ptr is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
340  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
341  ASSERT_STREQ("false", is_ctor_called());
342
343  is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
344  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
345  ASSERT_STREQ("true", is_ctor_called());
346  dlclose(handle);
347}
348
349TEST(dlfcn, ifunc_ctor_call_rtld_lazy) {
350  typedef const char* (*fn_ptr)();
351
352  void* handle = dlopen("libtest_ifunc.so", RTLD_LAZY);
353  ASSERT_TRUE(handle != nullptr) << dlerror();
354  fn_ptr is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
355  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
356  ASSERT_STREQ("false", is_ctor_called());
357
358  is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
359  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
360  ASSERT_STREQ("true", is_ctor_called());
361  dlclose(handle);
362}
363#endif
364
365TEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
366  // This is the structure of the test library and
367  // its dt_needed libraries
368  // libtest_relo_check_dt_needed_order.so
369  // |
370  // +-> libtest_relo_check_dt_needed_order_1.so
371  // |
372  // +-> libtest_relo_check_dt_needed_order_2.so
373  //
374  // The root library references relo_test_get_answer_lib - which is defined
375  // in both dt_needed libraries, the correct relocation should
376  // use the function defined in libtest_relo_check_dt_needed_order_1.so
377  void* handle = nullptr;
378  auto guard = android::base::make_scope_guard([&]() { dlclose(handle); });
379
380  handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
381  ASSERT_TRUE(handle != nullptr) << dlerror();
382
383  typedef int (*fn_t) (void);
384  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
385  ASSERT_TRUE(fn != nullptr) << dlerror();
386  ASSERT_EQ(1, fn());
387}
388
389TEST(dlfcn, dlopen_check_order_dlsym) {
390  // Here is how the test library and its dt_needed
391  // libraries are arranged
392  //
393  //  libtest_check_order_children.so
394  //  |
395  //  +-> ..._1_left.so
396  //  |   |
397  //  |   +-> ..._a.so
398  //  |   |
399  //  |   +-> ...r_b.so
400  //  |
401  //  +-> ..._2_right.so
402  //  |   |
403  //  |   +-> ..._d.so
404  //  |       |
405  //  |       +-> ..._b.so
406  //  |
407  //  +-> ..._3_c.so
408  //
409  //  load order should be (1, 2, 3, a, b, d)
410  //
411  // get_answer() is defined in (2, 3, a, b, c)
412  // get_answer2() is defined in (b, d)
413  void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer");
414  ASSERT_TRUE(sym == nullptr);
415  void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL);
416  ASSERT_TRUE(handle != nullptr) << dlerror();
417  typedef int (*fn_t) (void);
418  fn_t fn, fn2;
419  fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"));
420  ASSERT_TRUE(fn != nullptr) << dlerror();
421  fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2"));
422  ASSERT_TRUE(fn2 != nullptr) << dlerror();
423
424  ASSERT_EQ(42, fn());
425  ASSERT_EQ(43, fn2());
426  dlclose(handle);
427}
428
429TEST(dlfcn, dlopen_check_order_reloc_siblings) {
430  // This is how this one works:
431  // we lookup and call get_answer which is defined in '_2.so'
432  // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so'
433  // the correct _impl() is implemented by '_a.so';
434  //
435  // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?)
436  //
437  // Here is the picture:
438  //
439  // libtest_check_order_reloc_siblings.so
440  // |
441  // +-> ..._1.so <- empty
442  // |   |
443  // |   +-> ..._a.so <- exports correct answer_impl()
444  // |   |
445  // |   +-> ..._b.so <- every other letter exporting incorrect one.
446  // |
447  // +-> ..._2.so <- empty
448  // |   |
449  // |   +-> ..._c.so
450  // |   |
451  // |   +-> ..._d.so
452  // |
453  // +-> ..._3.so <- empty
454  //     |
455  //     +-> ..._e.so
456  //     |
457  //     +-> ..._f.so <- exports get_answer() that calls get_anser_impl();
458  //                     implements incorrect get_answer_impl()
459
460  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
461  ASSERT_TRUE(handle == nullptr);
462#ifdef __BIONIC__
463  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
464  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
465#endif
466
467  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
468  ASSERT_TRUE(handle != nullptr) << dlerror();
469
470  typedef int (*fn_t) (void);
471  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
472  ASSERT_TRUE(fn != nullptr) << dlerror();
473  ASSERT_EQ(42, fn());
474
475  ASSERT_EQ(0, dlclose(handle));
476}
477
478TEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) {
479  // This test uses the same library as dlopen_check_order_reloc_siblings.
480  // Unlike dlopen_check_order_reloc_siblings it preloads
481  // libtest_check_order_reloc_siblings_1.so (first dependency) prior to
482  // dlopen(libtest_check_order_reloc_siblings.so)
483
484  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
485  ASSERT_TRUE(handle == nullptr);
486  handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD);
487  ASSERT_TRUE(handle == nullptr);
488
489  void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL);
490  ASSERT_TRUE(handle_for_1 != nullptr) << dlerror();
491
492  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
493  ASSERT_TRUE(handle != nullptr) << dlerror();
494
495  ASSERT_EQ(0, dlclose(handle_for_1));
496
497  typedef int (*fn_t) (void);
498  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
499  ASSERT_TRUE(fn != nullptr) << dlerror();
500  ASSERT_EQ(42, fn());
501
502  ASSERT_EQ(0, dlclose(handle));
503}
504
505TEST(dlfcn, dlopen_check_order_reloc_grandchild) {
506  // This is how this one works:
507  // we lookup and call grandchild_get_answer which is defined in '_2.so'
508  // and in turn calls external get_answer_impl() defined in '_c_1.so and _c_2.so'
509  // the correct _impl() is implemented by '_c_1.so';
510  //
511  // Here is the picture of subtree:
512  //
513  // libtest_check_order_reloc_siblings.so
514  // |
515  // +-> ..._2.so <- grandchild_get_answer()
516  //     |
517  //     +-> ..._c.so <- empty
518  //     |   |
519  //     |   +-> _c_1.so <- exports correct answer_impl()
520  //     |   |
521  //     |   +-> _c_2.so <- exports incorrect answer_impl()
522  //     |
523  //     +-> ..._d.so <- empty
524
525  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
526  ASSERT_TRUE(handle == nullptr);
527#ifdef __BIONIC__
528  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
529  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
530#endif
531
532  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
533  ASSERT_TRUE(handle != nullptr) << dlerror();
534
535  typedef int (*fn_t) (void);
536  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_grandchild_get_answer"));
537  ASSERT_TRUE(fn != nullptr) << dlerror();
538  ASSERT_EQ(42, fn());
539
540  ASSERT_EQ(0, dlclose(handle));
541}
542
543TEST(dlfcn, dlopen_check_order_reloc_nephew) {
544  // This is how this one works:
545  // we lookup and call nephew_get_answer which is defined in '_2.so'
546  // and in turn calls external get_answer_impl() defined in '_[a-f].so'
547  // the correct _impl() is implemented by '_a.so';
548  //
549  // Here is the picture:
550  //
551  // libtest_check_order_reloc_siblings.so
552  // |
553  // +-> ..._1.so <- empty
554  // |   |
555  // |   +-> ..._a.so <- exports correct answer_impl()
556  // |   |
557  // |   +-> ..._b.so <- every other letter exporting incorrect one.
558  // |
559  // +-> ..._2.so <- empty
560  // |   |
561  // |   +-> ..._c.so
562  // |   |
563  // |   +-> ..._d.so
564  // |
565  // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl();
566  //     |
567  //     +-> ..._e.so
568  //     |
569  //     +-> ..._f.so
570
571  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
572  ASSERT_TRUE(handle == nullptr);
573#ifdef __BIONIC__
574  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
575  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
576#endif
577
578  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
579  ASSERT_TRUE(handle != nullptr) << dlerror();
580
581  typedef int (*fn_t) (void);
582  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_nephew_get_answer"));
583  ASSERT_TRUE(fn != nullptr) << dlerror();
584  ASSERT_EQ(42, fn());
585
586  ASSERT_EQ(0, dlclose(handle));
587}
588
589TEST(dlfcn, check_unload_after_reloc) {
590  // This is how this one works:
591  // libtest_two_parents_parent1 <- answer_impl() used by libtest_two_parents_child
592  // |
593  // +-> libtest_two_parents_child
594  //
595  // libtest_two_parents_parent2 <- answer_impl() not used by libtest_two_parents_child
596  // |
597  // +-> libtest_two_parents_child
598  //
599  // Test dlopens parent1 which loads and relocates libtest_two_parents_child.so
600  // as a second step it dlopens parent2 and dlcloses parent1...
601
602  void* handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL);
603  ASSERT_TRUE(handle != nullptr) << dlerror();
604
605  void* handle2 = dlopen("libtest_two_parents_parent2.so", RTLD_NOW | RTLD_LOCAL);
606  ASSERT_TRUE(handle2 != nullptr) << dlerror();
607
608  typedef int (*fn_t) (void);
609  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
610  ASSERT_TRUE(fn != nullptr) << dlerror();
611  ASSERT_EQ(42, fn());
612
613  ASSERT_EQ(0, dlclose(handle));
614
615  handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
616  ASSERT_TRUE(handle != nullptr);
617  ASSERT_EQ(0, dlclose(handle));
618
619  fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
620  ASSERT_TRUE(fn != nullptr) << dlerror();
621  ASSERT_EQ(42, fn());
622
623  ASSERT_EQ(0, dlclose(handle2));
624
625  handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
626  ASSERT_TRUE(handle == nullptr);
627}
628
629extern "C" int check_order_reloc_root_get_answer_impl() {
630  return 42;
631}
632
633TEST(dlfcn, dlopen_check_order_reloc_main_executable) {
634  // This is how this one works:
635  // we lookup and call get_answer3 which is defined in 'root.so'
636  // and in turn calls external root_get_answer_impl() defined in _2.so and
637  // above the correct _impl() is one in the executable.
638  //
639  // libtest_check_order_reloc_root.so
640  // |
641  // +-> ..._1.so <- empty
642  // |
643  // +-> ..._2.so <- gives incorrect answer for answer_main_impl()
644  //
645
646  void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD);
647  ASSERT_TRUE(handle == nullptr);
648#ifdef __BIONIC__
649  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
650  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
651#endif
652
653  handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL);
654  ASSERT_TRUE(handle != nullptr) << dlerror();
655
656  typedef int (*fn_t) (void);
657  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_root_get_answer"));
658  ASSERT_TRUE(fn != nullptr) << dlerror();
659  ASSERT_EQ(42, fn());
660
661  ASSERT_EQ(0, dlclose(handle));
662}
663
664TEST(dlfcn, dlopen_check_rtld_local) {
665  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
666  ASSERT_TRUE(sym == nullptr);
667
668  // implicit RTLD_LOCAL
669  void* handle = dlopen("libtest_simple.so", RTLD_NOW);
670  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
671  ASSERT_TRUE(sym == nullptr);
672  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
673  sym = dlsym(handle, "dlopen_testlib_simple_func");
674  ASSERT_TRUE(sym != nullptr);
675  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
676  dlclose(handle);
677
678  // explicit RTLD_LOCAL
679  handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL);
680  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
681  ASSERT_TRUE(sym == nullptr);
682  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
683  sym = dlsym(handle, "dlopen_testlib_simple_func");
684  ASSERT_TRUE(sym != nullptr);
685  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
686  dlclose(handle);
687}
688
689TEST(dlfcn, dlopen_check_rtld_global) {
690  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
691  ASSERT_TRUE(sym == nullptr);
692
693  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL);
694  ASSERT_TRUE(handle != nullptr) << dlerror();
695  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
696  ASSERT_TRUE(sym != nullptr) << dlerror();
697  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
698  dlclose(handle);
699
700  // RTLD_GLOBAL implies RTLD_NODELETE, let's check that
701  void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
702  ASSERT_EQ(sym, sym_after_dlclose);
703
704  // Check if dlsym() for main program's handle searches RTLD_GLOBAL
705  // shared libraries after symbol was not found in the main executable
706  // and dependent libraries.
707  void* handle_for_main_executable = dlopen(nullptr, RTLD_NOW);
708  sym = dlsym(handle_for_main_executable, "dlopen_testlib_simple_func");
709  ASSERT_TRUE(sym != nullptr) << dlerror();
710
711  dlclose(handle_for_main_executable);
712}
713
714// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
715// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so ->
716// libtest_with_dependency_loop_a.so
717TEST(dlfcn, dlopen_check_loop) {
718  void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW);
719  ASSERT_TRUE(handle != nullptr) << dlerror();
720  void* f = dlsym(handle, "dlopen_test_loopy_function");
721  ASSERT_TRUE(f != nullptr) << dlerror();
722  EXPECT_TRUE(reinterpret_cast<bool (*)(void)>(f)());
723  ASSERT_EQ(0, dlclose(handle));
724
725  // dlopen second time to make sure that the library was unloaded correctly
726  handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
727  ASSERT_TRUE(handle == nullptr);
728#ifdef __BIONIC__
729  ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
730#else
731  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
732  ASSERT_TRUE(dlerror() == nullptr);
733#endif
734
735  handle = dlopen("libtest_with_dependency_a.so", RTLD_NOW | RTLD_NOLOAD);
736  ASSERT_TRUE(handle == nullptr);
737}
738
739TEST(dlfcn, dlopen_nodelete) {
740  static bool is_unloaded = false;
741
742  void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE);
743  ASSERT_TRUE(handle != nullptr) << dlerror();
744  void (*set_unload_flag_ptr)(bool*);
745  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr"));
746  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
747  set_unload_flag_ptr(&is_unloaded);
748
749  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
750  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
751  ASSERT_EQ(1729U, *taxicab_number);
752  *taxicab_number = 2;
753
754  dlclose(handle);
755  ASSERT_TRUE(!is_unloaded);
756
757  uint32_t* taxicab_number_after_dlclose = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
758  ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number);
759  ASSERT_EQ(2U, *taxicab_number_after_dlclose);
760
761
762  handle = dlopen("libtest_nodelete_1.so", RTLD_NOW);
763  uint32_t* taxicab_number2 = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
764  ASSERT_EQ(taxicab_number2, taxicab_number);
765
766  ASSERT_EQ(2U, *taxicab_number2);
767
768  dlclose(handle);
769  ASSERT_TRUE(!is_unloaded);
770}
771
772TEST(dlfcn, dlopen_nodelete_on_second_dlopen) {
773  static bool is_unloaded = false;
774
775  void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW);
776  ASSERT_TRUE(handle != nullptr) << dlerror();
777  void (*set_unload_flag_ptr)(bool*);
778  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr"));
779  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
780  set_unload_flag_ptr(&is_unloaded);
781
782  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_2_taxicab_number"));
783  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
784
785  ASSERT_EQ(1729U, *taxicab_number);
786  *taxicab_number = 2;
787
788  // This RTLD_NODELETE should be ignored
789  void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE);
790  ASSERT_TRUE(handle1 != nullptr) << dlerror();
791  ASSERT_EQ(handle, handle1);
792
793  dlclose(handle1);
794  dlclose(handle);
795
796  ASSERT_TRUE(is_unloaded);
797}
798
799TEST(dlfcn, dlopen_nodelete_dt_flags_1) {
800  static bool is_unloaded = false;
801
802  void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW);
803  ASSERT_TRUE(handle != nullptr) << dlerror();
804  void (*set_unload_flag_ptr)(bool*);
805  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr"));
806  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
807  set_unload_flag_ptr(&is_unloaded);
808
809  dlclose(handle);
810  ASSERT_TRUE(!is_unloaded);
811}
812
813TEST(dlfcn, dlsym_df_1_global) {
814  void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW);
815  ASSERT_TRUE(handle != nullptr) << dlerror();
816  int (*get_answer)();
817  get_answer = reinterpret_cast<int (*)()>(dlsym(handle, "dl_df_1_global_get_answer"));
818  ASSERT_TRUE(get_answer != nullptr) << dlerror();
819  ASSERT_EQ(42, get_answer());
820  ASSERT_EQ(0, dlclose(handle));
821}
822
823TEST(dlfcn, dlopen_failure) {
824  void* self = dlopen("/does/not/exist", RTLD_NOW);
825  ASSERT_TRUE(self == nullptr);
826#if defined(__BIONIC__)
827  ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
828#else
829  ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
830#endif
831}
832
833TEST(dlfcn, dlclose_unload) {
834  void* handle = dlopen("libtest_simple.so", RTLD_NOW);
835  ASSERT_TRUE(handle != nullptr) << dlerror();
836  uint32_t* taxicab_number = static_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
837  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
838  EXPECT_EQ(1729U, *taxicab_number);
839  dlclose(handle);
840  // Making sure that the library has been unmapped as part of library unload
841  // process. Note that mprotect somewhat counter-intuitively returns ENOMEM in
842  // this case.
843  uintptr_t page_start = reinterpret_cast<uintptr_t>(taxicab_number) & ~(PAGE_SIZE - 1);
844  ASSERT_TRUE(mprotect(reinterpret_cast<void*>(page_start), PAGE_SIZE, PROT_NONE) != 0);
845  ASSERT_EQ(ENOMEM, errno) << strerror(errno);
846}
847
848static void ConcurrentDlErrorFn(std::string& error) {
849  ASSERT_TRUE(dlerror() == nullptr);
850
851  void* handle = dlopen("/child/thread", RTLD_NOW);
852  ASSERT_TRUE(handle == nullptr);
853
854  const char* err = dlerror();
855  ASSERT_TRUE(err != nullptr);
856
857  error = err;
858}
859
860TEST(dlfcn, dlerror_concurrent_buffer) {
861  void* handle = dlopen("/main/thread", RTLD_NOW);
862  ASSERT_TRUE(handle == nullptr);
863  const char* main_thread_error = dlerror();
864  ASSERT_TRUE(main_thread_error != nullptr);
865  ASSERT_SUBSTR("/main/thread", main_thread_error);
866
867  std::string child_thread_error;
868  std::thread t(ConcurrentDlErrorFn, std::ref(child_thread_error));
869  t.join();
870  ASSERT_SUBSTR("/child/thread", child_thread_error.c_str());
871
872  // Check that main thread local buffer was not modified.
873  ASSERT_SUBSTR("/main/thread", main_thread_error);
874}
875
876TEST(dlfcn, dlerror_concurrent) {
877  void* handle = dlopen("/main/thread", RTLD_NOW);
878  ASSERT_TRUE(handle == nullptr);
879
880  std::string child_thread_error;
881  std::thread t(ConcurrentDlErrorFn, std::ref(child_thread_error));
882  t.join();
883  ASSERT_SUBSTR("/child/thread", child_thread_error.c_str());
884
885  const char* main_thread_error = dlerror();
886  ASSERT_TRUE(main_thread_error != nullptr);
887  ASSERT_SUBSTR("/main/thread", main_thread_error);
888}
889
890TEST(dlfcn, dlsym_failures) {
891  dlerror(); // Clear any pending errors.
892  void* self = dlopen(nullptr, RTLD_NOW);
893  ASSERT_TRUE(self != nullptr);
894  ASSERT_TRUE(dlerror() == nullptr);
895
896  void* sym;
897
898#if defined(__BIONIC__) && !defined(__LP64__)
899  // RTLD_DEFAULT in lp32 bionic is not (void*)0
900  // so it can be distinguished from the NULL handle.
901  sym = dlsym(nullptr, "test");
902  ASSERT_TRUE(sym == nullptr);
903  ASSERT_STREQ("dlsym failed: library handle is null", dlerror());
904#endif
905
906  // Symbol that doesn't exist.
907  sym = dlsym(self, "ThisSymbolDoesNotExist");
908  ASSERT_TRUE(sym == nullptr);
909  ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
910
911  ASSERT_EQ(0, dlclose(self));
912}
913
914TEST(dlfcn, dladdr_executable) {
915  dlerror(); // Clear any pending errors.
916  void* self = dlopen(nullptr, RTLD_NOW);
917  ASSERT_TRUE(self != nullptr);
918  ASSERT_TRUE(dlerror() == nullptr);
919
920  void* sym = dlsym(self, "DlSymTestFunction");
921  ASSERT_TRUE(sym != nullptr);
922
923  // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
924  void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
925
926  Dl_info info;
927  int rc = dladdr(addr, &info);
928  ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
929
930  // Get the name of this executable.
931  const std::string& executable_path = get_executable_path();
932
933  // The filename should be that of this executable.
934  char dli_realpath[PATH_MAX];
935  ASSERT_TRUE(realpath(info.dli_fname, dli_realpath) != nullptr);
936  ASSERT_STREQ(executable_path.c_str(), dli_realpath);
937
938  // The symbol name should be the symbol we looked up.
939  ASSERT_STREQ(info.dli_sname, "DlSymTestFunction");
940
941  // The address should be the exact address of the symbol.
942  ASSERT_EQ(info.dli_saddr, sym);
943
944  std::vector<map_record> maps;
945  ASSERT_TRUE(Maps::parse_maps(&maps));
946
947  void* base_address = nullptr;
948  for (const map_record& rec : maps) {
949    if (executable_path == rec.pathname) {
950      base_address = reinterpret_cast<void*>(rec.addr_start);
951      break;
952    }
953  }
954
955  // The base address should be the address we were loaded at.
956  ASSERT_EQ(info.dli_fbase, base_address);
957
958  ASSERT_EQ(0, dlclose(self));
959}
960
961TEST(dlfcn, dlopen_executable_by_absolute_path) {
962  void* handle1 = dlopen(nullptr, RTLD_NOW);
963  ASSERT_TRUE(handle1 != nullptr) << dlerror();
964
965  void* handle2 = dlopen(get_executable_path().c_str(), RTLD_NOW);
966  ASSERT_TRUE(handle2 != nullptr) << dlerror();
967
968#if defined(__BIONIC__)
969  ASSERT_EQ(handle1, handle2);
970#else
971  GTEST_LOG_(INFO) << "Skipping ASSERT_EQ(handle1, handle2) for glibc: "
972                      "it loads a separate copy of the main executable "
973                      "on dlopen by absolute path.";
974#endif
975}
976
977#if defined (__aarch64__)
978#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/arm64/"
979#elif defined (__arm__)
980#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/arm/"
981#elif defined (__i386__)
982#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/x86/"
983#elif defined (__x86_64__)
984#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/x86_64/"
985#elif defined (__mips__)
986#if defined(__LP64__)
987#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/mips64/"
988#else
989#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/mips/"
990#endif
991#else
992#error "Unknown architecture"
993#endif
994#define PATH_TO_LIBC PATH_TO_SYSTEM_LIB "libc.so"
995#define ALTERNATE_PATH_TO_LIBC ALTERNATE_PATH_TO_SYSTEM_LIB "libc.so"
996
997TEST(dlfcn, dladdr_libc) {
998#if defined(__BIONIC__)
999  Dl_info info;
1000  void* addr = reinterpret_cast<void*>(puts); // well-known libc function
1001  ASSERT_TRUE(dladdr(addr, &info) != 0);
1002
1003  char libc_realpath[PATH_MAX];
1004
1005  // Check if libc is in canonical path or in alternate path.
1006  if (strncmp(ALTERNATE_PATH_TO_SYSTEM_LIB,
1007              info.dli_fname,
1008              sizeof(ALTERNATE_PATH_TO_SYSTEM_LIB) - 1) == 0) {
1009    // Platform with emulated architecture.  Symlink on ARC++.
1010    ASSERT_TRUE(realpath(ALTERNATE_PATH_TO_LIBC, libc_realpath) == libc_realpath);
1011  } else {
1012    // /system/lib is symlink when this test is executed on host.
1013    ASSERT_TRUE(realpath(PATH_TO_LIBC, libc_realpath) == libc_realpath);
1014  }
1015
1016  ASSERT_STREQ(libc_realpath, info.dli_fname);
1017  // TODO: add check for dfi_fbase
1018  ASSERT_STREQ("puts", info.dli_sname);
1019  ASSERT_EQ(addr, info.dli_saddr);
1020#else
1021  GTEST_LOG_(INFO) << "This test does nothing for glibc. Glibc returns path from ldconfig "
1022      "for libc.so, which is symlink itself (not a realpath).\n";
1023#endif
1024}
1025
1026TEST(dlfcn, dladdr_invalid) {
1027  Dl_info info;
1028
1029  dlerror(); // Clear any pending errors.
1030
1031  // No symbol corresponding to NULL.
1032  ASSERT_EQ(dladdr(nullptr, &info), 0); // Zero on error, non-zero on success.
1033  ASSERT_TRUE(dlerror() == nullptr); // dladdr(3) doesn't set dlerror(3).
1034
1035  // No symbol corresponding to a stack address.
1036  ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
1037  ASSERT_TRUE(dlerror() == nullptr); // dladdr(3) doesn't set dlerror(3).
1038}
1039
1040// GNU-style ELF hash tables are incompatible with the MIPS ABI.
1041// MIPS requires .dynsym to be sorted to match the GOT but GNU-style requires sorting by hash code.
1042TEST(dlfcn, dlopen_library_with_only_gnu_hash) {
1043#if !defined(__mips__)
1044  dlerror(); // Clear any pending errors.
1045  void* handle = dlopen("libgnu-hash-table-library.so", RTLD_NOW);
1046  ASSERT_TRUE(handle != nullptr) << dlerror();
1047  auto guard = android::base::make_scope_guard([&]() { dlclose(handle); });
1048  void* sym = dlsym(handle, "getRandomNumber");
1049  ASSERT_TRUE(sym != nullptr) << dlerror();
1050  int (*fn)(void);
1051  fn = reinterpret_cast<int (*)(void)>(sym);
1052  EXPECT_EQ(4, fn());
1053
1054  Dl_info dlinfo;
1055  ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
1056
1057  ASSERT_TRUE(fn == dlinfo.dli_saddr);
1058  ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
1059  ASSERT_SUBSTR("libgnu-hash-table-library.so", dlinfo.dli_fname);
1060#else
1061  GTEST_LOG_(INFO) << "This test does nothing for mips/mips64; mips toolchain does not support '--hash-style=gnu'\n";
1062#endif
1063}
1064
1065TEST(dlfcn, dlopen_library_with_only_sysv_hash) {
1066  void* handle = dlopen("libsysv-hash-table-library.so", RTLD_NOW);
1067  ASSERT_TRUE(handle != nullptr) << dlerror();
1068  auto guard = android::base::make_scope_guard([&]() { dlclose(handle); });
1069  void* sym = dlsym(handle, "getRandomNumber");
1070  ASSERT_TRUE(sym != nullptr) << dlerror();
1071  int (*fn)(void);
1072  fn = reinterpret_cast<int (*)(void)>(sym);
1073  EXPECT_EQ(4, fn());
1074
1075  Dl_info dlinfo;
1076  ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
1077
1078  ASSERT_TRUE(fn == dlinfo.dli_saddr);
1079  ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
1080  ASSERT_SUBSTR("libsysv-hash-table-library.so", dlinfo.dli_fname);
1081}
1082
1083TEST(dlfcn, dlopen_library_with_ELF_TLS) {
1084  dlerror(); // Clear any pending errors.
1085  void* handle = dlopen("libelf-tls-library.so", RTLD_NOW);
1086  ASSERT_TRUE(handle == nullptr);
1087  ASSERT_SUBSTR("unsupported ELF TLS", dlerror());
1088}
1089
1090TEST(dlfcn, dlopen_bad_flags) {
1091  dlerror(); // Clear any pending errors.
1092  void* handle;
1093
1094#if defined(__GLIBC__)
1095  // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
1096  handle = dlopen(nullptr, 0);
1097  ASSERT_TRUE(handle == nullptr);
1098  ASSERT_SUBSTR("invalid", dlerror());
1099#endif
1100
1101  handle = dlopen(nullptr, 0xffffffff);
1102  ASSERT_TRUE(handle == nullptr);
1103  ASSERT_SUBSTR("invalid", dlerror());
1104
1105  // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
1106  handle = dlopen(nullptr, RTLD_NOW|RTLD_LAZY);
1107  ASSERT_TRUE(handle != nullptr);
1108  ASSERT_SUBSTR(nullptr, dlerror());
1109}
1110
1111TEST(dlfcn, rtld_default_unknown_symbol) {
1112  void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
1113  ASSERT_TRUE(addr == nullptr);
1114}
1115
1116TEST(dlfcn, rtld_default_known_symbol) {
1117  void* addr = dlsym(RTLD_DEFAULT, "fopen");
1118  ASSERT_TRUE(addr != nullptr);
1119}
1120
1121TEST(dlfcn, rtld_next_unknown_symbol) {
1122  void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
1123  ASSERT_TRUE(addr == nullptr);
1124}
1125
1126TEST(dlfcn, rtld_next_known_symbol) {
1127  void* addr = dlsym(RTLD_NEXT, "fopen");
1128  ASSERT_TRUE(addr != nullptr);
1129}
1130
1131// Check that RTLD_NEXT of a libc symbol works in dlopened library
1132TEST(dlfcn, rtld_next_from_library) {
1133  void* library_with_fclose = dlopen("libtest_check_rtld_next_from_library.so", RTLD_NOW | RTLD_GLOBAL);
1134  ASSERT_TRUE(library_with_fclose != nullptr) << dlerror();
1135  void* expected_addr = dlsym(RTLD_DEFAULT, "fclose");
1136  ASSERT_TRUE(expected_addr != nullptr) << dlerror();
1137  typedef void* (*get_libc_fclose_ptr_fn_t)();
1138  get_libc_fclose_ptr_fn_t get_libc_fclose_ptr =
1139      reinterpret_cast<get_libc_fclose_ptr_fn_t>(dlsym(library_with_fclose, "get_libc_fclose_ptr"));
1140  ASSERT_TRUE(get_libc_fclose_ptr != nullptr) << dlerror();
1141  ASSERT_EQ(expected_addr, get_libc_fclose_ptr());
1142
1143  dlclose(library_with_fclose);
1144}
1145
1146
1147TEST(dlfcn, dlsym_weak_func) {
1148  dlerror();
1149  void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW);
1150  ASSERT_TRUE(handle != nullptr);
1151
1152  int (*weak_func)();
1153  weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
1154  ASSERT_TRUE(weak_func != nullptr) << "dlerror: " << dlerror();
1155  EXPECT_EQ(42, weak_func());
1156  dlclose(handle);
1157}
1158
1159TEST(dlfcn, dlopen_undefined_weak_func) {
1160  void* handle = dlopen("libtest_dlopen_weak_undefined_func.so", RTLD_NOW);
1161  ASSERT_TRUE(handle != nullptr) << dlerror();
1162  int (*weak_func)();
1163  weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "use_weak_undefined_func"));
1164  ASSERT_TRUE(weak_func != nullptr) << dlerror();
1165  EXPECT_EQ(6551, weak_func());
1166  dlclose(handle);
1167}
1168
1169TEST(dlfcn, dlopen_symlink) {
1170  DlfcnSymlink symlink("dlopen_symlink");
1171  const std::string symlink_name = basename(symlink.get_symlink_path().c_str());
1172  void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
1173  void* handle2 = dlopen(symlink_name.c_str(), RTLD_NOW);
1174  ASSERT_TRUE(handle1 != nullptr);
1175  ASSERT_TRUE(handle2 != nullptr);
1176  ASSERT_EQ(handle1, handle2);
1177  dlclose(handle1);
1178  dlclose(handle2);
1179}
1180
1181// libtest_dlopen_from_ctor_main.so depends on
1182// libtest_dlopen_from_ctor.so which has a constructor
1183// that calls dlopen(libc...). This is to test the situation
1184// described in b/7941716.
1185TEST(dlfcn, dlopen_dlopen_from_ctor) {
1186#if defined(__BIONIC__)
1187  void* handle = dlopen("libtest_dlopen_from_ctor_main.so", RTLD_NOW);
1188  ASSERT_TRUE(handle != nullptr) << dlerror();
1189  dlclose(handle);
1190#else
1191  GTEST_LOG_(INFO) << "This test is disabled for glibc (glibc segfaults if you try to call dlopen from a constructor).\n";
1192#endif
1193}
1194
1195static std::string g_fini_call_order_str;
1196
1197static void register_fini_call(const char* s) {
1198  g_fini_call_order_str += s;
1199}
1200
1201static void test_init_fini_call_order_for(const char* libname) {
1202  g_fini_call_order_str.clear();
1203  void* handle = dlopen(libname, RTLD_NOW);
1204  ASSERT_TRUE(handle != nullptr) << dlerror();
1205  typedef int (*get_init_order_number_t)();
1206  get_init_order_number_t get_init_order_number =
1207          reinterpret_cast<get_init_order_number_t>(dlsym(handle, "get_init_order_number"));
1208  ASSERT_EQ(321, get_init_order_number());
1209
1210  typedef void (*set_fini_callback_t)(void (*f)(const char*));
1211  set_fini_callback_t set_fini_callback =
1212          reinterpret_cast<set_fini_callback_t>(dlsym(handle, "set_fini_callback"));
1213  set_fini_callback(register_fini_call);
1214  dlclose(handle);
1215  ASSERT_EQ("(root)(child)(grandchild)", g_fini_call_order_str);
1216}
1217
1218TEST(dlfcn, init_fini_call_order) {
1219  test_init_fini_call_order_for("libtest_init_fini_order_root.so");
1220  test_init_fini_call_order_for("libtest_init_fini_order_root2.so");
1221}
1222
1223TEST(dlfcn, symbol_versioning_use_v1) {
1224  void* handle = dlopen("libtest_versioned_uselibv1.so", RTLD_NOW);
1225  ASSERT_TRUE(handle != nullptr) << dlerror();
1226  typedef int (*fn_t)();
1227  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
1228  ASSERT_TRUE(fn != nullptr) << dlerror();
1229  ASSERT_EQ(1, fn());
1230  dlclose(handle);
1231}
1232
1233TEST(dlfcn, symbol_versioning_use_v2) {
1234  void* handle = dlopen("libtest_versioned_uselibv2.so", RTLD_NOW);
1235  ASSERT_TRUE(handle != nullptr) << dlerror();
1236  typedef int (*fn_t)();
1237  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
1238  ASSERT_TRUE(fn != nullptr) << dlerror();
1239  ASSERT_EQ(2, fn());
1240  dlclose(handle);
1241}
1242
1243TEST(dlfcn, symbol_versioning_use_other_v2) {
1244  void* handle = dlopen("libtest_versioned_uselibv2_other.so", RTLD_NOW);
1245  ASSERT_TRUE(handle != nullptr) << dlerror();
1246  typedef int (*fn_t)();
1247  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
1248  ASSERT_TRUE(fn != nullptr) << dlerror();
1249  ASSERT_EQ(20, fn());
1250  dlclose(handle);
1251}
1252
1253TEST(dlfcn, symbol_versioning_use_other_v3) {
1254  void* handle = dlopen("libtest_versioned_uselibv3_other.so", RTLD_NOW);
1255  ASSERT_TRUE(handle != nullptr) << dlerror();
1256  typedef int (*fn_t)();
1257  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
1258  ASSERT_TRUE(fn != nullptr) << dlerror();
1259  ASSERT_EQ(3, fn());
1260  dlclose(handle);
1261}
1262
1263TEST(dlfcn, symbol_versioning_default_via_dlsym) {
1264  void* handle = dlopen("libtest_versioned_lib.so", RTLD_NOW);
1265  ASSERT_TRUE(handle != nullptr) << dlerror();
1266  typedef int (*fn_t)();
1267  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "versioned_function"));
1268  ASSERT_TRUE(fn != nullptr) << dlerror();
1269  ASSERT_EQ(3, fn()); // the default version is 3
1270  dlclose(handle);
1271}
1272
1273TEST(dlfcn, dlvsym_smoke) {
1274  void* handle = dlopen("libtest_versioned_lib.so", RTLD_NOW);
1275  ASSERT_TRUE(handle != nullptr) << dlerror();
1276  typedef int (*fn_t)();
1277
1278  {
1279    fn_t fn = reinterpret_cast<fn_t>(dlvsym(handle, "versioned_function", "nonversion"));
1280    ASSERT_TRUE(fn == nullptr);
1281    ASSERT_SUBSTR("undefined symbol: versioned_function, version nonversion", dlerror());
1282  }
1283
1284  {
1285    fn_t fn = reinterpret_cast<fn_t>(dlvsym(handle, "versioned_function", "TESTLIB_V2"));
1286    ASSERT_TRUE(fn != nullptr) << dlerror();
1287    ASSERT_EQ(2, fn());
1288  }
1289
1290  dlclose(handle);
1291}
1292
1293// This preempts the implementation from libtest_versioned_lib.so
1294extern "C" int version_zero_function() {
1295  return 0;
1296}
1297
1298// This preempts the implementation from libtest_versioned_uselibv*.so
1299extern "C" int version_zero_function2() {
1300  return 0;
1301}
1302
1303TEST(dlfcn, dt_runpath_smoke) {
1304  void* handle = dlopen("libtest_dt_runpath_d.so", RTLD_NOW);
1305  ASSERT_TRUE(handle != nullptr) << dlerror();
1306
1307  typedef void *(* dlopen_b_fn)();
1308  dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
1309  ASSERT_TRUE(fn != nullptr) << dlerror();
1310
1311  void *p = fn();
1312  ASSERT_TRUE(p != nullptr);
1313
1314  dlclose(handle);
1315}
1316
1317TEST(dlfcn, dt_runpath_absolute_path) {
1318  std::string libpath = get_testlib_root() + "/libtest_dt_runpath_d.so";
1319  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1320  ASSERT_TRUE(handle != nullptr) << dlerror();
1321
1322  typedef void *(* dlopen_b_fn)();
1323  dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
1324  ASSERT_TRUE(fn != nullptr) << dlerror();
1325
1326  void *p = fn();
1327  ASSERT_TRUE(p != nullptr);
1328
1329  dlclose(handle);
1330}
1331
1332TEST(dlfcn, dlclose_after_thread_local_dtor) {
1333  bool is_dtor_triggered = false;
1334
1335  auto f = [](void* handle, bool* is_dtor_triggered) {
1336    typedef void (*fn_t)(bool*);
1337    fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "init_thread_local_variable"));
1338    ASSERT_TRUE(fn != nullptr) << dlerror();
1339
1340    fn(is_dtor_triggered);
1341
1342    ASSERT_TRUE(!*is_dtor_triggered);
1343  };
1344
1345  void* handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
1346  ASSERT_TRUE(handle == nullptr);
1347
1348  handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW);
1349  ASSERT_TRUE(handle != nullptr) << dlerror();
1350
1351  std::thread t(f, handle, &is_dtor_triggered);
1352  t.join();
1353
1354  ASSERT_TRUE(is_dtor_triggered);
1355  dlclose(handle);
1356
1357  handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
1358  ASSERT_TRUE(handle == nullptr);
1359}
1360
1361TEST(dlfcn, dlclose_before_thread_local_dtor) {
1362  bool is_dtor_triggered = false;
1363
1364  auto f = [](bool* is_dtor_triggered) {
1365    void* handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
1366    ASSERT_TRUE(handle == nullptr);
1367
1368    handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW);
1369    ASSERT_TRUE(handle != nullptr) << dlerror();
1370
1371    typedef void (*fn_t)(bool*);
1372    fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "init_thread_local_variable"));
1373    ASSERT_TRUE(fn != nullptr) << dlerror();
1374
1375    fn(is_dtor_triggered);
1376
1377    dlclose(handle);
1378
1379    ASSERT_TRUE(!*is_dtor_triggered);
1380
1381    // Since we have thread_atexit dtors associated with handle - the library should
1382    // still be availabe.
1383    handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
1384    ASSERT_TRUE(handle != nullptr) << dlerror();
1385    dlclose(handle);
1386  };
1387
1388  void* handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW);
1389  ASSERT_TRUE(handle != nullptr) << dlerror();
1390  dlclose(handle);
1391
1392  handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
1393  ASSERT_TRUE(handle == nullptr);
1394
1395  std::thread t(f, &is_dtor_triggered);
1396  t.join();
1397#if defined(__BIONIC__)
1398  // ld-android.so unloads unreferenced libraries on pthread_exit()
1399  ASSERT_TRUE(is_dtor_triggered);
1400  handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
1401  ASSERT_TRUE(handle == nullptr);
1402#else
1403  // GLIBC does not unload libraries with ref_count = 0 on pthread_exit
1404  ASSERT_TRUE(is_dtor_triggered);
1405  handle = dlopen("libtest_thread_local_dtor.so", RTLD_NOW | RTLD_NOLOAD);
1406  ASSERT_TRUE(handle != nullptr) << dlerror();
1407#endif
1408}
1409
1410TEST(dlfcn, RTLD_macros) {
1411#if !defined(RTLD_LOCAL)
1412#error no RTLD_LOCAL
1413#elif !defined(RTLD_LAZY)
1414#error no RTLD_LAZY
1415#elif !defined(RTLD_NOW)
1416#error no RTLD_NOW
1417#elif !defined(RTLD_NOLOAD)
1418#error no RTLD_NOLOAD
1419#elif !defined(RTLD_GLOBAL)
1420#error no RTLD_GLOBAL
1421#elif !defined(RTLD_NODELETE)
1422#error no RTLD_NODELETE
1423#endif
1424}
1425
1426// Bionic specific tests
1427#if defined(__BIONIC__)
1428
1429#if defined(__arm__)
1430const llvm::ELF::Elf32_Dyn* to_dynamic_table(const char* p) {
1431  return reinterpret_cast<const llvm::ELF::Elf32_Dyn*>(p);
1432}
1433
1434// Duplicate these definitions here because they are android specific
1435// note that we cannot include <elf.h> because #defines conflict with
1436// enum names provided by LLVM.
1437#define DT_ANDROID_REL (llvm::ELF::DT_LOOS + 2)
1438#define DT_ANDROID_RELA (llvm::ELF::DT_LOOS + 4)
1439
1440template<typename ELFT>
1441void validate_compatibility_of_native_library(const std::string& soname,
1442                                              const std::string& path, ELFT* elf) {
1443  bool has_elf_hash = false;
1444  bool has_android_rel = false;
1445  bool has_rel = false;
1446  // Find dynamic section and check that DT_HASH and there is no DT_ANDROID_REL
1447  for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
1448    const llvm::object::ELFSectionRef& section_ref = *it;
1449    if (section_ref.getType() == llvm::ELF::SHT_DYNAMIC) {
1450      llvm::StringRef data;
1451      ASSERT_TRUE(!it->getContents(data)) << "unable to get SHT_DYNAMIC section data";
1452      for (auto d = to_dynamic_table(data.data()); d->d_tag != llvm::ELF::DT_NULL; ++d) {
1453        if (d->d_tag == llvm::ELF::DT_HASH) {
1454          has_elf_hash = true;
1455        } else if (d->d_tag == DT_ANDROID_REL || d->d_tag == DT_ANDROID_RELA) {
1456          has_android_rel = true;
1457        } else if (d->d_tag == llvm::ELF::DT_REL || d->d_tag == llvm::ELF::DT_RELA) {
1458          has_rel = true;
1459        }
1460      }
1461
1462      break;
1463    }
1464  }
1465
1466  ASSERT_TRUE(has_elf_hash) << path.c_str() << ": missing elf hash (DT_HASH)";
1467  ASSERT_TRUE(!has_android_rel) << path.c_str() << ": has packed relocations";
1468  // libdl.so is simple enough that it might not have any relocations, so
1469  // exempt it from the DT_REL/DT_RELA check.
1470  if (soname != "libdl.so") {
1471    ASSERT_TRUE(has_rel) << path.c_str() << ": missing DT_REL/DT_RELA";
1472  }
1473}
1474
1475void validate_compatibility_of_native_library(const std::string& soname) {
1476  // On the systems with emulation system libraries would be of different
1477  // architecture.  Try to use alternate paths first.
1478  std::string path = std::string(ALTERNATE_PATH_TO_SYSTEM_LIB) + soname;
1479  auto binary_or_error = llvm::object::createBinary(path);
1480  if (!binary_or_error) {
1481    path = std::string(PATH_TO_SYSTEM_LIB) + soname;
1482    binary_or_error = llvm::object::createBinary(path);
1483  }
1484  ASSERT_FALSE(!binary_or_error);
1485
1486  llvm::object::Binary* binary = binary_or_error.get().getBinary();
1487
1488  auto obj = llvm::dyn_cast<llvm::object::ObjectFile>(binary);
1489  ASSERT_TRUE(obj != nullptr);
1490
1491  auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj);
1492
1493  ASSERT_TRUE(elf != nullptr);
1494
1495  validate_compatibility_of_native_library(soname, path, elf);
1496}
1497
1498// This is a test for app compatibility workaround for arm apps
1499// affected by http://b/24465209
1500TEST(dlext, compat_elf_hash_and_relocation_tables) {
1501  validate_compatibility_of_native_library("libc.so");
1502  validate_compatibility_of_native_library("liblog.so");
1503  validate_compatibility_of_native_library("libstdc++.so");
1504  validate_compatibility_of_native_library("libdl.so");
1505  validate_compatibility_of_native_library("libm.so");
1506  validate_compatibility_of_native_library("libz.so");
1507  validate_compatibility_of_native_library("libjnigraphics.so");
1508}
1509
1510#endif //  defined(__arm__)
1511
1512TEST(dlfcn, dlopen_invalid_rw_load_segment) {
1513  const std::string libpath = get_testlib_root() +
1514                              "/" + kPrebuiltElfDir +
1515                              "/libtest_invalid-rw_load_segment.so";
1516  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1517  ASSERT_TRUE(handle == nullptr);
1518  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\": W+E load segments are not allowed";
1519  ASSERT_STREQ(expected_dlerror.c_str(), dlerror());
1520}
1521
1522TEST(dlfcn, dlopen_invalid_unaligned_shdr_offset) {
1523  const std::string libpath = get_testlib_root() +
1524                              "/" + kPrebuiltElfDir +
1525                              "/libtest_invalid-unaligned_shdr_offset.so";
1526
1527  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1528  ASSERT_TRUE(handle == nullptr);
1529  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has invalid shdr offset/size: ";
1530  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1531}
1532
1533TEST(dlfcn, dlopen_invalid_zero_shentsize) {
1534  const std::string libpath = get_testlib_root() +
1535                              "/" + kPrebuiltElfDir +
1536                              "/libtest_invalid-zero_shentsize.so";
1537
1538  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1539  ASSERT_TRUE(handle == nullptr);
1540  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has unsupported e_shentsize: 0x0 (expected 0x";
1541  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1542}
1543
1544TEST(dlfcn, dlopen_invalid_zero_shstrndx) {
1545  const std::string libpath = get_testlib_root() +
1546                              "/" + kPrebuiltElfDir +
1547                              "/libtest_invalid-zero_shstrndx.so";
1548
1549  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1550  ASSERT_TRUE(handle == nullptr);
1551  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has invalid e_shstrndx";
1552  ASSERT_STREQ(expected_dlerror.c_str(), dlerror());
1553}
1554
1555TEST(dlfcn, dlopen_invalid_empty_shdr_table) {
1556  const std::string libpath = get_testlib_root() +
1557                              "/" + kPrebuiltElfDir +
1558                              "/libtest_invalid-empty_shdr_table.so";
1559
1560  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1561  ASSERT_TRUE(handle == nullptr);
1562  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has no section headers";
1563  ASSERT_STREQ(expected_dlerror.c_str(), dlerror());
1564}
1565
1566TEST(dlfcn, dlopen_invalid_zero_shdr_table_offset) {
1567  const std::string libpath = get_testlib_root() +
1568                              "/" + kPrebuiltElfDir +
1569                              "/libtest_invalid-zero_shdr_table_offset.so";
1570
1571  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1572  ASSERT_TRUE(handle == nullptr);
1573  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has invalid shdr offset/size: 0/";
1574  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1575}
1576
1577TEST(dlfcn, dlopen_invalid_zero_shdr_table_content) {
1578  const std::string libpath = get_testlib_root() +
1579                              "/" + kPrebuiltElfDir +
1580                              "/libtest_invalid-zero_shdr_table_content.so";
1581
1582  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1583  ASSERT_TRUE(handle == nullptr);
1584  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" .dynamic section header was not found";
1585  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1586}
1587
1588TEST(dlfcn, dlopen_invalid_textrels) {
1589  const std::string libpath = get_testlib_root() +
1590                              "/" + kPrebuiltElfDir +
1591                              "/libtest_invalid-textrels.so";
1592
1593  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1594  ASSERT_TRUE(handle == nullptr);
1595  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has text relocations";
1596  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1597}
1598
1599TEST(dlfcn, dlopen_invalid_textrels2) {
1600  const std::string libpath = get_testlib_root() +
1601                              "/" + kPrebuiltElfDir +
1602                              "/libtest_invalid-textrels2.so";
1603
1604  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1605  ASSERT_TRUE(handle == nullptr);
1606  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has text relocations";
1607  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1608}
1609
1610TEST(dlfcn, dlopen_df_1_global) {
1611  void* handle = dlopen("libtest_dlopen_df_1_global.so", RTLD_NOW);
1612  ASSERT_TRUE(handle != nullptr) << dlerror();
1613}
1614
1615#endif
1616