blob: a63c070cf9bedbc8e5e948e16d4f35684c8069c6 [file] [log] [blame]
jeffhaoacf5aa72012-09-12 17:25:30 -07001/*
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>
Elliott Hughes8e15b082012-09-26 11:44:01 -070020#include <libgen.h>
21#include <limits.h>
22#include <stdio.h>
23#include <stdint.h>
24
Dmitriy Ivanovb2a30ee2014-09-04 18:23:00 -070025#include "private/ScopeGuard.h"
26
Elliott Hughes8e15b082012-09-26 11:44:01 -070027#include <string>
jeffhaoacf5aa72012-09-12 17:25:30 -070028
Elliott Hughes3b297c42012-10-11 16:08:51 -070029#define ASSERT_SUBSTR(needle, haystack) \
30 ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
31
Elliott Hughes1728b232014-05-14 10:02:03 -070032static bool g_called = false;
jeffhaoacf5aa72012-09-12 17:25:30 -070033extern "C" void DlSymTestFunction() {
Elliott Hughes1728b232014-05-14 10:02:03 -070034 g_called = true;
jeffhaoacf5aa72012-09-12 17:25:30 -070035}
36
Dmitriy Ivanovf8846a42014-07-08 21:21:34 -070037static int g_ctor_function_called = 0;
38
39extern "C" void ctor_function() __attribute__ ((constructor));
40
41extern "C" void ctor_function() {
42 g_ctor_function_called = 17;
43}
44
45TEST(dlfcn, ctor_function_call) {
46 ASSERT_EQ(17, g_ctor_function_called);
47}
48
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -070049TEST(dlfcn, dlsym_in_executable) {
Elliott Hughes3b297c42012-10-11 16:08:51 -070050 dlerror(); // Clear any pending errors.
jeffhaoacf5aa72012-09-12 17:25:30 -070051 void* self = dlopen(NULL, RTLD_NOW);
52 ASSERT_TRUE(self != NULL);
Elliott Hughes3b297c42012-10-11 16:08:51 -070053 ASSERT_TRUE(dlerror() == NULL);
jeffhaoacf5aa72012-09-12 17:25:30 -070054
55 void* sym = dlsym(self, "DlSymTestFunction");
56 ASSERT_TRUE(sym != NULL);
57
58 void (*function)() = reinterpret_cast<void(*)()>(sym);
59
Elliott Hughes1728b232014-05-14 10:02:03 -070060 g_called = false;
jeffhaoacf5aa72012-09-12 17:25:30 -070061 function();
Elliott Hughes1728b232014-05-14 10:02:03 -070062 ASSERT_TRUE(g_called);
Elliott Hughes1a696162012-11-01 13:49:32 -070063
64 ASSERT_EQ(0, dlclose(self));
jeffhaoacf5aa72012-09-12 17:25:30 -070065}
Elliott Hughes8e15b082012-09-26 11:44:01 -070066
Dmitriy Ivanov76ac1ac2015-04-01 14:45:10 -070067TEST(dlfcn, dlsym_from_sofile) {
68 void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_LAZY | RTLD_LOCAL);
69 ASSERT_TRUE(handle != nullptr) << dlerror();
70
71 // check that we cant find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
72 void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
73 ASSERT_TRUE(symbol == nullptr);
74 ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
75
76 typedef int* (*fn_t)();
77 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
78
79 ASSERT_TRUE(fn != nullptr) << dlerror();
80
81 int* ptr = fn();
82 ASSERT_TRUE(ptr != nullptr) << dlerror();
83 ASSERT_EQ(42, *ptr);
84
85 dlclose(handle);
86}
87
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -070088TEST(dlfcn, dlsym_with_dependencies) {
89 void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
90 ASSERT_TRUE(handle != NULL);
91 dlerror();
92 // This symbol is in DT_NEEDED library.
93 void* sym = dlsym(handle, "getRandomNumber");
94 ASSERT_TRUE(sym != NULL);
95 int (*fn)(void);
96 fn = reinterpret_cast<int (*)(void)>(sym);
97 EXPECT_EQ(4, fn());
98 dlclose(handle);
99}
100
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -0700101TEST(dlfcn, dlopen_noload) {
102 void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
103 ASSERT_TRUE(handle == NULL);
104 handle = dlopen("libtest_simple.so", RTLD_NOW);
105 void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
106 ASSERT_TRUE(handle != NULL);
107 ASSERT_TRUE(handle2 != NULL);
108 ASSERT_TRUE(handle == handle2);
109 ASSERT_EQ(0, dlclose(handle));
110 ASSERT_EQ(0, dlclose(handle2));
111}
112
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -0700113TEST(dlfcn, dlopen_by_soname) {
114 static const char* soname = "libdlext_test_soname.so";
115 static const char* filename = "libdlext_test_different_soname.so";
116 // 1. Make sure there is no library with soname in default search path
117 void* handle = dlopen(soname, RTLD_NOW);
118 ASSERT_TRUE(handle == nullptr);
119
120 // 2. Load a library using filename
121 handle = dlopen(filename, RTLD_NOW);
122 ASSERT_TRUE(handle != nullptr) << dlerror();
123
124 // 3. Find library by soname
125 void* handle_soname = dlopen(soname, RTLD_NOW | RTLD_NOLOAD);
126 ASSERT_TRUE(handle_soname != nullptr) << dlerror();
127 ASSERT_EQ(handle, handle_soname);
128
129 // 4. RTLD_NOLOAD should still work with filename
130 void* handle_filename = dlopen(filename, RTLD_NOW | RTLD_NOLOAD);
131 ASSERT_TRUE(handle_filename != nullptr) << dlerror();
132 ASSERT_EQ(handle, handle_filename);
133
134 dlclose(handle_filename);
135 dlclose(handle_soname);
136 dlclose(handle);
137}
138
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -0700139// ifuncs are only supported on intel and arm64 for now
140#if defined (__aarch64__) || defined(__i386__) || defined(__x86_64__)
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700141TEST(dlfcn, ifunc) {
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700142 typedef const char* (*fn_ptr)();
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700143
144 // ifunc's choice depends on whether IFUNC_CHOICE has a value
145 // first check the set case
146 setenv("IFUNC_CHOICE", "set", 1);
147 void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
148 ASSERT_TRUE(handle != NULL);
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700149 fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
150 fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700151 ASSERT_TRUE(foo_ptr != NULL);
152 ASSERT_TRUE(foo_library_ptr != NULL);
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700153 ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
154 ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700155 dlclose(handle);
156
157 // then check the unset case
158 unsetenv("IFUNC_CHOICE");
159 handle = dlopen("libtest_ifunc.so", RTLD_NOW);
160 ASSERT_TRUE(handle != NULL);
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700161 foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
162 foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700163 ASSERT_TRUE(foo_ptr != NULL);
164 ASSERT_TRUE(foo_library_ptr != NULL);
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700165 ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
166 ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
167 dlclose(handle);
168}
169
170TEST(dlfcn, ifunc_ctor_call) {
171 typedef const char* (*fn_ptr)();
172
173 void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -0700174 ASSERT_TRUE(handle != nullptr) << dlerror();
175 fn_ptr is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
176 ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
177 ASSERT_STREQ("false", is_ctor_called());
178
179 is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
180 ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700181 ASSERT_STREQ("true", is_ctor_called());
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700182 dlclose(handle);
183}
184#endif
185
Dmitriy Ivanovb2a30ee2014-09-04 18:23:00 -0700186TEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
187 // This is the structure of the test library and
188 // its dt_needed libraries
189 // libtest_relo_check_dt_needed_order.so
190 // |
191 // +-> libtest_relo_check_dt_needed_order_1.so
192 // |
193 // +-> libtest_relo_check_dt_needed_order_2.so
194 //
195 // The root library references relo_test_get_answer_lib - which is defined
196 // in both dt_needed libraries, the correct relocation should
197 // use the function defined in libtest_relo_check_dt_needed_order_1.so
198 void* handle = nullptr;
Dmitriy Ivanovd9ff7222014-09-08 16:22:22 -0700199 auto guard = make_scope_guard([&]() {
Dmitriy Ivanovb2a30ee2014-09-04 18:23:00 -0700200 dlclose(handle);
201 });
202
203 handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
204 ASSERT_TRUE(handle != nullptr) << dlerror();
205
206 typedef int (*fn_t) (void);
207 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
208 ASSERT_TRUE(fn != nullptr) << dlerror();
209 ASSERT_EQ(1, fn());
210}
211
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700212TEST(dlfcn, dlopen_check_order_dlsym) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700213 // Here is how the test library and its dt_needed
214 // libraries are arranged
215 //
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700216 // libtest_check_order_children.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700217 // |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700218 // +-> ..._1_left.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700219 // | |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700220 // | +-> ..._a.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700221 // | |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700222 // | +-> ...r_b.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700223 // |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700224 // +-> ..._2_right.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700225 // | |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700226 // | +-> ..._d.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700227 // | |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700228 // | +-> ..._b.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700229 // |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700230 // +-> ..._3_c.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700231 //
232 // load order should be (1, 2, 3, a, b, d)
233 //
234 // get_answer() is defined in (2, 3, a, b, c)
235 // get_answer2() is defined in (b, d)
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700236 void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer");
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700237 ASSERT_TRUE(sym == nullptr);
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700238 void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL);
239 ASSERT_TRUE(handle != nullptr) << dlerror();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700240 typedef int (*fn_t) (void);
241 fn_t fn, fn2;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700242 fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"));
Dmitriy Ivanoveb27bba2014-09-15 14:13:24 -0700243 ASSERT_TRUE(fn != NULL) << dlerror();
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700244 fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2"));
Dmitriy Ivanoveb27bba2014-09-15 14:13:24 -0700245 ASSERT_TRUE(fn2 != NULL) << dlerror();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700246
247 ASSERT_EQ(42, fn());
248 ASSERT_EQ(43, fn2());
249 dlclose(handle);
250}
251
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700252TEST(dlfcn, dlopen_check_order_reloc_siblings) {
253 // This is how this one works:
254 // we lookup and call get_answer which is defined in '_2.so'
255 // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so'
256 // the correct _impl() is implemented by '_a.so';
257 //
258 // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?)
259 //
260 // Here is the picture:
261 //
262 // libtest_check_order_reloc_siblings.so
263 // |
264 // +-> ..._1.so <- empty
265 // | |
266 // | +-> ..._a.so <- exports correct answer_impl()
267 // | |
268 // | +-> ..._b.so <- every other letter exporting incorrect one.
269 // |
270 // +-> ..._2.so <- empty
271 // | |
272 // | +-> ..._c.so
273 // | |
274 // | +-> ..._d.so
275 // |
276 // +-> ..._3.so <- empty
277 // |
278 // +-> ..._e.so
279 // |
280 // +-> ..._f.so <- exports get_answer() that calls get_anser_impl();
281 // implements incorrect get_answer_impl()
282
283 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
284 ASSERT_TRUE(handle == nullptr);
285#ifdef __BIONIC__
286 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
287 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
288#endif
289
290 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
291 ASSERT_TRUE(handle != nullptr) << dlerror();
292
293 typedef int (*fn_t) (void);
294 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
295 ASSERT_TRUE(fn != nullptr) << dlerror();
296 ASSERT_EQ(42, fn());
297
298 ASSERT_EQ(0, dlclose(handle));
299}
300
301TEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) {
302 // This test uses the same library as dlopen_check_order_reloc_siblings.
303 // Unlike dlopen_check_order_reloc_siblings it preloads
304 // libtest_check_order_reloc_siblings_1.so (first dependency) prior to
305 // dlopen(libtest_check_order_reloc_siblings.so)
306
307 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
308 ASSERT_TRUE(handle == nullptr);
309 handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD);
310 ASSERT_TRUE(handle == nullptr);
311
312 void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL);
313 ASSERT_TRUE(handle_for_1 != nullptr) << dlerror();
314
315 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
316 ASSERT_TRUE(handle != nullptr) << dlerror();
317
318 ASSERT_EQ(0, dlclose(handle_for_1));
319
320 typedef int (*fn_t) (void);
321 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
322 ASSERT_TRUE(fn != nullptr) << dlerror();
323 ASSERT_EQ(42, fn());
324
325 ASSERT_EQ(0, dlclose(handle));
326}
327
Dmitriy Ivanov7699d132014-11-18 17:26:31 -0800328TEST(dlfcn, dlopen_check_order_reloc_grandchild) {
329 // This is how this one works:
330 // we lookup and call grandchild_get_answer which is defined in '_2.so'
331 // and in turn calls external get_answer_impl() defined in '_c_1.so and _c_2.so'
332 // the correct _impl() is implemented by '_c_1.so';
333 //
334 // Here is the picture of subtree:
335 //
336 // libtest_check_order_reloc_siblings.so
337 // |
338 // +-> ..._2.so <- grandchild_get_answer()
339 // |
340 // +-> ..._c.so <- empty
341 // | |
342 // | +-> _c_1.so <- exports correct answer_impl()
343 // | |
344 // | +-> _c_2.so <- exports incorrect answer_impl()
345 // |
346 // +-> ..._d.so <- empty
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_grandchild_get_answer"));
360 ASSERT_TRUE(fn != nullptr) << dlerror();
361 ASSERT_EQ(42, fn());
362
363 ASSERT_EQ(0, dlclose(handle));
364}
365
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700366TEST(dlfcn, dlopen_check_order_reloc_nephew) {
367 // This is how this one works:
368 // we lookup and call nephew_get_answer which is defined in '_2.so'
369 // and in turn calls external get_answer_impl() defined in '_[a-f].so'
370 // the correct _impl() is implemented by '_a.so';
371 //
372 // Here is the picture:
373 //
374 // libtest_check_order_reloc_siblings.so
375 // |
376 // +-> ..._1.so <- empty
377 // | |
378 // | +-> ..._a.so <- exports correct answer_impl()
379 // | |
380 // | +-> ..._b.so <- every other letter exporting incorrect one.
381 // |
382 // +-> ..._2.so <- empty
383 // | |
384 // | +-> ..._c.so
385 // | |
386 // | +-> ..._d.so
387 // |
388 // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl();
389 // |
390 // +-> ..._e.so
391 // |
392 // +-> ..._f.so
393
394 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
395 ASSERT_TRUE(handle == nullptr);
396#ifdef __BIONIC__
397 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
398 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
399#endif
400
401 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
402 ASSERT_TRUE(handle != nullptr) << dlerror();
403
404 typedef int (*fn_t) (void);
405 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_nephew_get_answer"));
406 ASSERT_TRUE(fn != nullptr) << dlerror();
407 ASSERT_EQ(42, fn());
408
409 ASSERT_EQ(0, dlclose(handle));
410}
411
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800412TEST(dlfcn, check_unload_after_reloc) {
413 // This is how this one works:
414 // libtest_two_parents_parent1 <- answer_impl() used by libtest_two_parents_child
415 // |
416 // +-> libtest_two_parents_child
417 //
418 // libtest_two_parents_parent2 <- answer_impl() not used by libtest_two_parents_child
419 // |
420 // +-> libtest_two_parents_child
421 //
422 // Test dlopens parent1 which loads and relocates libtest_two_parents_child.so
423 // as a second step it dlopens parent2 and dlcloses parent1...
424
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700425 void* handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL);
426 ASSERT_TRUE(handle != nullptr) << dlerror();
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800427
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700428 void* handle2 = dlopen("libtest_two_parents_parent2.so", RTLD_NOW | RTLD_LOCAL);
429 ASSERT_TRUE(handle2 != nullptr) << dlerror();
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800430
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700431 typedef int (*fn_t) (void);
432 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
433 ASSERT_TRUE(fn != nullptr) << dlerror();
434 ASSERT_EQ(42, fn());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800435
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700436 ASSERT_EQ(0, dlclose(handle));
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800437
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700438 handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
439 ASSERT_TRUE(handle != nullptr);
440 ASSERT_EQ(0, dlclose(handle));
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800441
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700442 fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
443 ASSERT_TRUE(fn != nullptr) << dlerror();
444 ASSERT_EQ(42, fn());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800445
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700446 ASSERT_EQ(0, dlclose(handle2));
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800447
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700448 handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
449 ASSERT_TRUE(handle == nullptr);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800450}
451
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700452extern "C" int check_order_reloc_root_get_answer_impl() {
453 return 42;
454}
455
456TEST(dlfcn, dlopen_check_order_reloc_main_executable) {
457 // This is how this one works:
458 // we lookup and call get_answer3 which is defined in 'root.so'
459 // and in turn calls external root_get_answer_impl() defined in _2.so and
460 // above the correct _impl() is one in the executable.
461 //
462 // libtest_check_order_reloc_root.so
463 // |
464 // +-> ..._1.so <- empty
465 // |
466 // +-> ..._2.so <- gives incorrect answer for answer_main_impl()
467 //
468
469 void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD);
470 ASSERT_TRUE(handle == nullptr);
471#ifdef __BIONIC__
472 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
473 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
474#endif
475
476 handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL);
477 ASSERT_TRUE(handle != nullptr) << dlerror();
478
479 typedef int (*fn_t) (void);
480 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_root_get_answer"));
481 ASSERT_TRUE(fn != nullptr) << dlerror();
482 ASSERT_EQ(42, fn());
483
484 ASSERT_EQ(0, dlclose(handle));
485}
486
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700487TEST(dlfcn, dlopen_check_rtld_local) {
488 void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
489 ASSERT_TRUE(sym == nullptr);
490
491 // implicit RTLD_LOCAL
492 void* handle = dlopen("libtest_simple.so", RTLD_NOW);
493 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
494 ASSERT_TRUE(sym == nullptr);
495 ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
496 sym = dlsym(handle, "dlopen_testlib_simple_func");
497 ASSERT_TRUE(sym != nullptr);
498 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
499 dlclose(handle);
500
501 // explicit RTLD_LOCAL
502 handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL);
503 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
504 ASSERT_TRUE(sym == nullptr);
505 ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
506 sym = dlsym(handle, "dlopen_testlib_simple_func");
507 ASSERT_TRUE(sym != nullptr);
508 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
509 dlclose(handle);
510}
511
512TEST(dlfcn, dlopen_check_rtld_global) {
513 void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
514 ASSERT_TRUE(sym == nullptr);
515
516 void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -0700517 ASSERT_TRUE(handle != nullptr) << dlerror();
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700518 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
519 ASSERT_TRUE(sym != nullptr) << dlerror();
520 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
521 dlclose(handle);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -0700522
523 // RTLD_GLOBAL implies RTLD_NODELETE, let's check that
524 void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
525 ASSERT_EQ(sym, sym_after_dlclose);
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700526}
527
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700528// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
529// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so ->
530// libtest_with_dependency_loop_a.so
531TEST(dlfcn, dlopen_check_loop) {
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700532 void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW);
533 ASSERT_TRUE(handle != nullptr) << dlerror();
534 void* f = dlsym(handle, "dlopen_test_loopy_function");
535 ASSERT_TRUE(f != nullptr) << dlerror();
536 EXPECT_TRUE(reinterpret_cast<bool (*)(void)>(f)());
537 ASSERT_EQ(0, dlclose(handle));
Dmitriy Ivanova6ac54a2014-09-09 10:21:42 -0700538
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700539 // dlopen second time to make sure that the library was unloaded correctly
540 handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
541 ASSERT_TRUE(handle == nullptr);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800542#ifdef __BIONIC__
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700543 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
544 ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
Dmitriy Ivanoveb27bba2014-09-15 14:13:24 -0700545#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800546
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700547 handle = dlopen("libtest_with_dependency_a.so", RTLD_NOW | RTLD_NOLOAD);
548 ASSERT_TRUE(handle == nullptr);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700549}
550
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -0700551TEST(dlfcn, dlopen_nodelete) {
552 static bool is_unloaded = false;
553
554 void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE);
555 ASSERT_TRUE(handle != nullptr) << dlerror();
556 void (*set_unload_flag_ptr)(bool*);
557 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr"));
558 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
559 set_unload_flag_ptr(&is_unloaded);
560
561 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
562 ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
563 ASSERT_EQ(1729U, *taxicab_number);
564 *taxicab_number = 2;
565
566 dlclose(handle);
567 ASSERT_TRUE(!is_unloaded);
568
569 uint32_t* taxicab_number_after_dlclose = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
570 ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number);
571 ASSERT_EQ(2U, *taxicab_number_after_dlclose);
572
573
574 handle = dlopen("libtest_nodelete_1.so", RTLD_NOW);
575 uint32_t* taxicab_number2 = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
576 ASSERT_EQ(taxicab_number2, taxicab_number);
577
578 ASSERT_EQ(2U, *taxicab_number2);
579
580 dlclose(handle);
581 ASSERT_TRUE(!is_unloaded);
582}
583
584TEST(dlfcn, dlopen_nodelete_on_second_dlopen) {
585 static bool is_unloaded = false;
586
587 void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW);
588 ASSERT_TRUE(handle != nullptr) << dlerror();
589 void (*set_unload_flag_ptr)(bool*);
590 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr"));
591 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
592 set_unload_flag_ptr(&is_unloaded);
593
594 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_2_taxicab_number"));
595 ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
596
597 ASSERT_EQ(1729U, *taxicab_number);
598 *taxicab_number = 2;
599
600 // This RTLD_NODELETE should be ignored
601 void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE);
602 ASSERT_TRUE(handle1 != nullptr) << dlerror();
603 ASSERT_EQ(handle, handle1);
604
605 dlclose(handle1);
606 dlclose(handle);
607
608 ASSERT_TRUE(is_unloaded);
609}
610
611TEST(dlfcn, dlopen_nodelete_dt_flags_1) {
612 static bool is_unloaded = false;
613
614 void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW);
615 ASSERT_TRUE(handle != nullptr) << dlerror();
616 void (*set_unload_flag_ptr)(bool*);
617 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr"));
618 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
619 set_unload_flag_ptr(&is_unloaded);
620
621 dlclose(handle);
622 ASSERT_TRUE(!is_unloaded);
623}
624
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700625TEST(dlfcn, dlsym_df_1_global) {
Dmitriy Ivanov4e446b12014-10-31 17:27:02 -0700626#if !defined(__arm__) && !defined(__aarch64__)
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700627 void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW);
628 ASSERT_TRUE(handle != nullptr) << dlerror();
629 int (*get_answer)();
630 get_answer = reinterpret_cast<int (*)()>(dlsym(handle, "dl_df_1_global_get_answer"));
631 ASSERT_TRUE(get_answer != nullptr) << dlerror();
632 ASSERT_EQ(42, get_answer());
633 ASSERT_EQ(0, dlclose(handle));
634#else
Dmitriy Ivanov4e446b12014-10-31 17:27:02 -0700635 GTEST_LOG_(INFO) << "This test does nothing on arm/arm64 (to be reenabled once b/18137520 or b/18130452 are fixed).\n";
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700636#endif
637}
638
Elliott Hughese66190d2012-12-18 15:57:55 -0800639TEST(dlfcn, dlopen_failure) {
Elliott Hughes3b297c42012-10-11 16:08:51 -0700640 void* self = dlopen("/does/not/exist", RTLD_NOW);
641 ASSERT_TRUE(self == NULL);
Elliott Hughes063525c2014-05-13 11:19:57 -0700642#if defined(__BIONIC__)
Elliott Hughes3b297c42012-10-11 16:08:51 -0700643 ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
644#else
645 ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
646#endif
647}
648
Elliott Hughesad88a082012-10-24 18:37:21 -0700649static void* ConcurrentDlErrorFn(void*) {
Elliott Hughes5419b942012-10-16 15:54:46 -0700650 dlopen("/child/thread", RTLD_NOW);
651 return reinterpret_cast<void*>(strdup(dlerror()));
652}
653
Elliott Hughese66190d2012-12-18 15:57:55 -0800654TEST(dlfcn, dlerror_concurrent) {
Elliott Hughes5419b942012-10-16 15:54:46 -0700655 dlopen("/main/thread", RTLD_NOW);
656 const char* main_thread_error = dlerror();
657 ASSERT_SUBSTR("/main/thread", main_thread_error);
658
659 pthread_t t;
660 ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentDlErrorFn, NULL));
661 void* result;
662 ASSERT_EQ(0, pthread_join(t, &result));
663 char* child_thread_error = static_cast<char*>(result);
664 ASSERT_SUBSTR("/child/thread", child_thread_error);
665 free(child_thread_error);
666
667 ASSERT_SUBSTR("/main/thread", main_thread_error);
668}
669
Elliott Hughese66190d2012-12-18 15:57:55 -0800670TEST(dlfcn, dlsym_failures) {
Elliott Hughes3b297c42012-10-11 16:08:51 -0700671 dlerror(); // Clear any pending errors.
Elliott Hughes8e15b082012-09-26 11:44:01 -0700672 void* self = dlopen(NULL, RTLD_NOW);
673 ASSERT_TRUE(self != NULL);
Elliott Hughes3b297c42012-10-11 16:08:51 -0700674 ASSERT_TRUE(dlerror() == NULL);
675
676 void* sym;
677
Dmitriy Ivanov44adf932014-05-22 09:49:24 -0700678#if defined(__BIONIC__) && !defined(__LP64__)
679 // RTLD_DEFAULT in lp32 bionic is not (void*)0
680 // so it can be distinguished from the NULL handle.
Elliott Hughes3b297c42012-10-11 16:08:51 -0700681 sym = dlsym(NULL, "test");
682 ASSERT_TRUE(sym == NULL);
Elliott Hughes3b297c42012-10-11 16:08:51 -0700683 ASSERT_SUBSTR("dlsym library handle is null", dlerror());
Elliott Hughes3b297c42012-10-11 16:08:51 -0700684#endif
685
686 // NULL symbol name.
Elliott Hughes063525c2014-05-13 11:19:57 -0700687#if defined(__BIONIC__)
Elliott Hughes3b297c42012-10-11 16:08:51 -0700688 // glibc marks this parameter non-null and SEGVs if you cheat.
689 sym = dlsym(self, NULL);
690 ASSERT_TRUE(sym == NULL);
691 ASSERT_SUBSTR("", dlerror());
692#endif
693
694 // Symbol that doesn't exist.
695 sym = dlsym(self, "ThisSymbolDoesNotExist");
696 ASSERT_TRUE(sym == NULL);
697 ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
Elliott Hughes1a696162012-11-01 13:49:32 -0700698
699 ASSERT_EQ(0, dlclose(self));
Elliott Hughes3b297c42012-10-11 16:08:51 -0700700}
701
Elliott Hughese66190d2012-12-18 15:57:55 -0800702TEST(dlfcn, dladdr) {
Elliott Hughes3b297c42012-10-11 16:08:51 -0700703 dlerror(); // Clear any pending errors.
704 void* self = dlopen(NULL, RTLD_NOW);
705 ASSERT_TRUE(self != NULL);
706 ASSERT_TRUE(dlerror() == NULL);
Elliott Hughes8e15b082012-09-26 11:44:01 -0700707
708 void* sym = dlsym(self, "DlSymTestFunction");
709 ASSERT_TRUE(sym != NULL);
710
711 // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
712 void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
713
714 Dl_info info;
715 int rc = dladdr(addr, &info);
716 ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
717
718 // Get the name of this executable.
719 char executable_path[PATH_MAX];
720 rc = readlink("/proc/self/exe", executable_path, sizeof(executable_path));
721 ASSERT_NE(rc, -1);
722 executable_path[rc] = '\0';
723 std::string executable_name(basename(executable_path));
724
725 // The filename should be that of this executable.
726 // Note that we don't know whether or not we have the full path, so we want an "ends_with" test.
727 std::string dli_fname(info.dli_fname);
728 dli_fname = basename(&dli_fname[0]);
729 ASSERT_EQ(dli_fname, executable_name);
730
731 // The symbol name should be the symbol we looked up.
732 ASSERT_STREQ(info.dli_sname, "DlSymTestFunction");
733
734 // The address should be the exact address of the symbol.
735 ASSERT_EQ(info.dli_saddr, sym);
736
737 // Look in /proc/pid/maps to find out what address we were loaded at.
738 // TODO: factor /proc/pid/maps parsing out into a class and reuse all over bionic.
739 void* base_address = NULL;
Elliott Hughes8e15b082012-09-26 11:44:01 -0700740 char line[BUFSIZ];
Elliott Hughes57b7a612014-08-25 17:26:50 -0700741 FILE* fp = fopen("/proc/self/maps", "r");
Elliott Hughes8e15b082012-09-26 11:44:01 -0700742 ASSERT_TRUE(fp != NULL);
743 while (fgets(line, sizeof(line), fp) != NULL) {
744 uintptr_t start = strtoul(line, 0, 16);
745 line[strlen(line) - 1] = '\0'; // Chomp the '\n'.
746 char* path = strchr(line, '/');
Elliott Hughes156da962012-10-09 17:14:56 -0700747 if (path != NULL && strcmp(executable_path, path) == 0) {
Elliott Hughes8e15b082012-09-26 11:44:01 -0700748 base_address = reinterpret_cast<void*>(start);
749 break;
750 }
751 }
752 fclose(fp);
753
754 // The base address should be the address we were loaded at.
755 ASSERT_EQ(info.dli_fbase, base_address);
Elliott Hughes1a696162012-11-01 13:49:32 -0700756
757 ASSERT_EQ(0, dlclose(self));
Elliott Hughes8e15b082012-09-26 11:44:01 -0700758}
759
Elliott Hughese66190d2012-12-18 15:57:55 -0800760TEST(dlfcn, dladdr_invalid) {
Elliott Hughes8e15b082012-09-26 11:44:01 -0700761 Dl_info info;
762
Elliott Hughes3b297c42012-10-11 16:08:51 -0700763 dlerror(); // Clear any pending errors.
764
Elliott Hughes8e15b082012-09-26 11:44:01 -0700765 // No symbol corresponding to NULL.
766 ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success.
Elliott Hughes3b297c42012-10-11 16:08:51 -0700767 ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
Elliott Hughes8e15b082012-09-26 11:44:01 -0700768
769 // No symbol corresponding to a stack address.
770 ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
Elliott Hughes3b297c42012-10-11 16:08:51 -0700771 ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
Elliott Hughes8e15b082012-09-26 11:44:01 -0700772}
Elliott Hughes124fae92012-10-31 14:20:03 -0700773
Elliott Hughesa43e9062013-01-07 14:18:22 -0800774// GNU-style ELF hash tables are incompatible with the MIPS ABI.
775// MIPS requires .dynsym to be sorted to match the GOT but GNU-style requires sorting by hash code.
Elliott Hughese66190d2012-12-18 15:57:55 -0800776TEST(dlfcn, dlopen_library_with_only_gnu_hash) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800777#if !defined(__mips__)
Elliott Hughes124fae92012-10-31 14:20:03 -0700778 dlerror(); // Clear any pending errors.
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800779 void* handle = dlopen("libgnu-hash-table-library.so", RTLD_NOW);
780 ASSERT_TRUE(handle != nullptr) << dlerror();
781 auto guard = make_scope_guard([&]() {
782 dlclose(handle);
783 });
784 void* sym = dlsym(handle, "getRandomNumber");
785 ASSERT_TRUE(sym != nullptr) << dlerror();
786 int (*fn)(void);
787 fn = reinterpret_cast<int (*)(void)>(sym);
788 EXPECT_EQ(4, fn());
789
790 Dl_info dlinfo;
791 ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
792
793 ASSERT_TRUE(fn == dlinfo.dli_saddr);
794 ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
Dmitriy Ivanovb3356772014-11-14 11:19:22 -0800795 ASSERT_SUBSTR("libgnu-hash-table-library.so", dlinfo.dli_fname);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800796#else
797 GTEST_LOG_(INFO) << "This test does nothing for mips/mips64; mips toolchain does not support '--hash-style=gnu'\n";
798#endif
Elliott Hughes124fae92012-10-31 14:20:03 -0700799}
Elliott Hughese66190d2012-12-18 15:57:55 -0800800
Dmitriy Ivanovb3356772014-11-14 11:19:22 -0800801TEST(dlfcn, dlopen_library_with_only_sysv_hash) {
802 void* handle = dlopen("libsysv-hash-table-library.so", RTLD_NOW);
803 ASSERT_TRUE(handle != nullptr) << dlerror();
804 auto guard = make_scope_guard([&]() {
805 dlclose(handle);
806 });
807 void* sym = dlsym(handle, "getRandomNumber");
808 ASSERT_TRUE(sym != nullptr) << dlerror();
809 int (*fn)(void);
810 fn = reinterpret_cast<int (*)(void)>(sym);
811 EXPECT_EQ(4, fn());
812
813 Dl_info dlinfo;
814 ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
815
816 ASSERT_TRUE(fn == dlinfo.dli_saddr);
817 ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
818 ASSERT_SUBSTR("libsysv-hash-table-library.so", dlinfo.dli_fname);
819}
820
Elliott Hughese66190d2012-12-18 15:57:55 -0800821TEST(dlfcn, dlopen_bad_flags) {
822 dlerror(); // Clear any pending errors.
823 void* handle;
824
Elliott Hughes063525c2014-05-13 11:19:57 -0700825#if defined(__GLIBC__)
Elliott Hughese66190d2012-12-18 15:57:55 -0800826 // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
827 handle = dlopen(NULL, 0);
828 ASSERT_TRUE(handle == NULL);
829 ASSERT_SUBSTR("invalid", dlerror());
830#endif
831
832 handle = dlopen(NULL, 0xffffffff);
833 ASSERT_TRUE(handle == NULL);
834 ASSERT_SUBSTR("invalid", dlerror());
835
836 // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
837 handle = dlopen(NULL, RTLD_NOW|RTLD_LAZY);
838 ASSERT_TRUE(handle != NULL);
839 ASSERT_SUBSTR(NULL, dlerror());
840}
Sergey Melnikovebd506c2013-10-31 18:02:12 +0400841
842TEST(dlfcn, rtld_default_unknown_symbol) {
Elliott Hughes2ed71092013-11-11 15:48:06 -0800843 void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
Sergey Melnikovebd506c2013-10-31 18:02:12 +0400844 ASSERT_TRUE(addr == NULL);
845}
846
847TEST(dlfcn, rtld_default_known_symbol) {
Elliott Hughes2ed71092013-11-11 15:48:06 -0800848 void* addr = dlsym(RTLD_DEFAULT, "fopen");
849 ASSERT_TRUE(addr != NULL);
850}
851
852TEST(dlfcn, rtld_next_unknown_symbol) {
853 void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
854 ASSERT_TRUE(addr == NULL);
855}
856
857TEST(dlfcn, rtld_next_known_symbol) {
858 void* addr = dlsym(RTLD_NEXT, "fopen");
Sergey Melnikovebd506c2013-10-31 18:02:12 +0400859 ASSERT_TRUE(addr != NULL);
860}
Dmitriy Ivanov7db18092014-05-08 12:27:25 -0700861
Dmitriy Ivanovce441662014-06-17 15:56:38 -0700862TEST(dlfcn, dlsym_weak_func) {
863 dlerror();
Dmitriy Ivanovbfa88bc2014-12-16 11:40:46 -0800864 void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW);
Dmitriy Ivanovce441662014-06-17 15:56:38 -0700865 ASSERT_TRUE(handle != NULL);
866
867 int (*weak_func)();
868 weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
869 ASSERT_TRUE(weak_func != NULL) << "dlerror: " << dlerror();
870 EXPECT_EQ(42, weak_func());
871 dlclose(handle);
872}
873
Dmitriy Ivanovbfa88bc2014-12-16 11:40:46 -0800874TEST(dlfcn, dlopen_undefined_weak_func) {
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700875 void* handle = dlopen("libtest_dlopen_weak_undefined_func.so", RTLD_NOW);
876 ASSERT_TRUE(handle != nullptr) << dlerror();
877 int (*weak_func)();
878 weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "use_weak_undefined_func"));
879 ASSERT_TRUE(weak_func != nullptr) << dlerror();
880 EXPECT_EQ(6551, weak_func());
881 dlclose(handle);
Dmitriy Ivanovbfa88bc2014-12-16 11:40:46 -0800882}
883
Dmitriy Ivanov7db18092014-05-08 12:27:25 -0700884TEST(dlfcn, dlopen_symlink) {
885 void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
886 void* handle2 = dlopen("libdlext_test_v2.so", RTLD_NOW);
887 ASSERT_TRUE(handle1 != NULL);
888 ASSERT_TRUE(handle2 != NULL);
889 ASSERT_EQ(handle1, handle2);
Dmitriy Ivanov319356e2014-09-02 17:31:44 -0700890 dlclose(handle1);
891 dlclose(handle2);
Dmitriy Ivanov7db18092014-05-08 12:27:25 -0700892}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800893
894// libtest_dlopen_from_ctor_main.so depends on
895// libtest_dlopen_from_ctor.so which has a constructor
896// that calls dlopen(libc...). This is to test the situation
897// described in b/7941716.
898TEST(dlfcn, dlopen_dlopen_from_ctor) {
899#if defined(__BIONIC__)
900 void* handle = dlopen("libtest_dlopen_from_ctor_main.so", RTLD_NOW);
901 ASSERT_TRUE(handle != nullptr) << dlerror();
902 dlclose(handle);
903#else
904 GTEST_LOG_(INFO) << "This test is disabled for glibc (glibc segfaults if you try to call dlopen from a constructor).\n";
905#endif
906}