blob: ef4ff20f080667dbac9977ebd6f0855ecfc4a615 [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
Simon Baldwinaef71952015-01-16 13:22:54 +000032#if defined(__LP64__)
33#define LIBPATH_PREFIX "/nativetest64/libdlext_test_fd/"
34#else
35#define LIBPATH_PREFIX "/nativetest/libdlext_test_fd/"
36#endif
37
38#define LIBZIPPATH LIBPATH_PREFIX "libdlext_test_fd_zipaligned.zip"
39
Elliott Hughes1728b232014-05-14 10:02:03 -070040static bool g_called = false;
jeffhaoacf5aa72012-09-12 17:25:30 -070041extern "C" void DlSymTestFunction() {
Elliott Hughes1728b232014-05-14 10:02:03 -070042 g_called = true;
jeffhaoacf5aa72012-09-12 17:25:30 -070043}
44
Dmitriy Ivanovf8846a42014-07-08 21:21:34 -070045static int g_ctor_function_called = 0;
46
47extern "C" void ctor_function() __attribute__ ((constructor));
48
49extern "C" void ctor_function() {
50 g_ctor_function_called = 17;
51}
52
53TEST(dlfcn, ctor_function_call) {
54 ASSERT_EQ(17, g_ctor_function_called);
55}
56
Elliott Hughese66190d2012-12-18 15:57:55 -080057TEST(dlfcn, dlsym_in_self) {
Elliott Hughes3b297c42012-10-11 16:08:51 -070058 dlerror(); // Clear any pending errors.
jeffhaoacf5aa72012-09-12 17:25:30 -070059 void* self = dlopen(NULL, RTLD_NOW);
60 ASSERT_TRUE(self != NULL);
Elliott Hughes3b297c42012-10-11 16:08:51 -070061 ASSERT_TRUE(dlerror() == NULL);
jeffhaoacf5aa72012-09-12 17:25:30 -070062
63 void* sym = dlsym(self, "DlSymTestFunction");
64 ASSERT_TRUE(sym != NULL);
65
66 void (*function)() = reinterpret_cast<void(*)()>(sym);
67
Elliott Hughes1728b232014-05-14 10:02:03 -070068 g_called = false;
jeffhaoacf5aa72012-09-12 17:25:30 -070069 function();
Elliott Hughes1728b232014-05-14 10:02:03 -070070 ASSERT_TRUE(g_called);
Elliott Hughes1a696162012-11-01 13:49:32 -070071
72 ASSERT_EQ(0, dlclose(self));
jeffhaoacf5aa72012-09-12 17:25:30 -070073}
Elliott Hughes8e15b082012-09-26 11:44:01 -070074
Dmitriy Ivanovaa0f2bd2014-07-28 17:32:20 -070075TEST(dlfcn, dlsym_with_dependencies) {
76 void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
77 ASSERT_TRUE(handle != NULL);
78 dlerror();
79 // This symbol is in DT_NEEDED library.
80 void* sym = dlsym(handle, "getRandomNumber");
81 ASSERT_TRUE(sym != NULL);
82 int (*fn)(void);
83 fn = reinterpret_cast<int (*)(void)>(sym);
84 EXPECT_EQ(4, fn());
85 dlclose(handle);
86}
87
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -070088TEST(dlfcn, dlopen_noload) {
89 void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
90 ASSERT_TRUE(handle == NULL);
91 handle = dlopen("libtest_simple.so", RTLD_NOW);
92 void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
93 ASSERT_TRUE(handle != NULL);
94 ASSERT_TRUE(handle2 != NULL);
95 ASSERT_TRUE(handle == handle2);
96 ASSERT_EQ(0, dlclose(handle));
97 ASSERT_EQ(0, dlclose(handle2));
98}
99
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -0700100// ifuncs are only supported on intel and arm64 for now
101#if defined (__aarch64__) || defined(__i386__) || defined(__x86_64__)
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700102TEST(dlfcn, ifunc) {
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700103 typedef const char* (*fn_ptr)();
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700104
105 // ifunc's choice depends on whether IFUNC_CHOICE has a value
106 // first check the set case
107 setenv("IFUNC_CHOICE", "set", 1);
108 void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
109 ASSERT_TRUE(handle != NULL);
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700110 fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
111 fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700112 ASSERT_TRUE(foo_ptr != NULL);
113 ASSERT_TRUE(foo_library_ptr != NULL);
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700114 ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
115 ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700116 dlclose(handle);
117
118 // then check the unset case
119 unsetenv("IFUNC_CHOICE");
120 handle = dlopen("libtest_ifunc.so", RTLD_NOW);
121 ASSERT_TRUE(handle != NULL);
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700122 foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
123 foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700124 ASSERT_TRUE(foo_ptr != NULL);
125 ASSERT_TRUE(foo_library_ptr != NULL);
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700126 ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
127 ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
128 dlclose(handle);
129}
130
131TEST(dlfcn, ifunc_ctor_call) {
132 typedef const char* (*fn_ptr)();
133
134 void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -0700135 ASSERT_TRUE(handle != nullptr) << dlerror();
136 fn_ptr is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
137 ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
138 ASSERT_STREQ("false", is_ctor_called());
139
140 is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
141 ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700142 ASSERT_STREQ("true", is_ctor_called());
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700143 dlclose(handle);
144}
145#endif
146
Dmitriy Ivanovb2a30ee2014-09-04 18:23:00 -0700147TEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
148 // This is the structure of the test library and
149 // its dt_needed libraries
150 // libtest_relo_check_dt_needed_order.so
151 // |
152 // +-> libtest_relo_check_dt_needed_order_1.so
153 // |
154 // +-> libtest_relo_check_dt_needed_order_2.so
155 //
156 // The root library references relo_test_get_answer_lib - which is defined
157 // in both dt_needed libraries, the correct relocation should
158 // use the function defined in libtest_relo_check_dt_needed_order_1.so
159 void* handle = nullptr;
Dmitriy Ivanovd9ff7222014-09-08 16:22:22 -0700160 auto guard = make_scope_guard([&]() {
Dmitriy Ivanovb2a30ee2014-09-04 18:23:00 -0700161 dlclose(handle);
162 });
163
164 handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
165 ASSERT_TRUE(handle != nullptr) << dlerror();
166
167 typedef int (*fn_t) (void);
168 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
169 ASSERT_TRUE(fn != nullptr) << dlerror();
170 ASSERT_EQ(1, fn());
171}
172
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700173TEST(dlfcn, dlopen_check_order_dlsym) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700174 // Here is how the test library and its dt_needed
175 // libraries are arranged
176 //
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700177 // libtest_check_order_children.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700178 // |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700179 // +-> ..._1_left.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700180 // | |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700181 // | +-> ..._a.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700182 // | |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700183 // | +-> ...r_b.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700184 // |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700185 // +-> ..._2_right.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700186 // | |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700187 // | +-> ..._d.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700188 // | |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700189 // | +-> ..._b.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700190 // |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700191 // +-> ..._3_c.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700192 //
193 // load order should be (1, 2, 3, a, b, d)
194 //
195 // get_answer() is defined in (2, 3, a, b, c)
196 // get_answer2() is defined in (b, d)
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700197 void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer");
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700198 ASSERT_TRUE(sym == nullptr);
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700199 void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL);
200 ASSERT_TRUE(handle != nullptr) << dlerror();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700201 typedef int (*fn_t) (void);
202 fn_t fn, fn2;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700203 fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"));
Dmitriy Ivanoveb27bba2014-09-15 14:13:24 -0700204 ASSERT_TRUE(fn != NULL) << dlerror();
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700205 fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2"));
Dmitriy Ivanoveb27bba2014-09-15 14:13:24 -0700206 ASSERT_TRUE(fn2 != NULL) << dlerror();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700207
208 ASSERT_EQ(42, fn());
209 ASSERT_EQ(43, fn2());
210 dlclose(handle);
211}
212
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700213TEST(dlfcn, dlopen_check_order_reloc_siblings) {
214 // This is how this one works:
215 // we lookup and call get_answer which is defined in '_2.so'
216 // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so'
217 // the correct _impl() is implemented by '_a.so';
218 //
219 // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?)
220 //
221 // Here is the picture:
222 //
223 // libtest_check_order_reloc_siblings.so
224 // |
225 // +-> ..._1.so <- empty
226 // | |
227 // | +-> ..._a.so <- exports correct answer_impl()
228 // | |
229 // | +-> ..._b.so <- every other letter exporting incorrect one.
230 // |
231 // +-> ..._2.so <- empty
232 // | |
233 // | +-> ..._c.so
234 // | |
235 // | +-> ..._d.so
236 // |
237 // +-> ..._3.so <- empty
238 // |
239 // +-> ..._e.so
240 // |
241 // +-> ..._f.so <- exports get_answer() that calls get_anser_impl();
242 // implements incorrect get_answer_impl()
243
244 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
245 ASSERT_TRUE(handle == nullptr);
246#ifdef __BIONIC__
247 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
248 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
249#endif
250
251 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
252 ASSERT_TRUE(handle != nullptr) << dlerror();
253
254 typedef int (*fn_t) (void);
255 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
256 ASSERT_TRUE(fn != nullptr) << dlerror();
257 ASSERT_EQ(42, fn());
258
259 ASSERT_EQ(0, dlclose(handle));
260}
261
262TEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) {
263 // This test uses the same library as dlopen_check_order_reloc_siblings.
264 // Unlike dlopen_check_order_reloc_siblings it preloads
265 // libtest_check_order_reloc_siblings_1.so (first dependency) prior to
266 // dlopen(libtest_check_order_reloc_siblings.so)
267
268 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
269 ASSERT_TRUE(handle == nullptr);
270 handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD);
271 ASSERT_TRUE(handle == nullptr);
272
273 void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL);
274 ASSERT_TRUE(handle_for_1 != nullptr) << dlerror();
275
276 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
277 ASSERT_TRUE(handle != nullptr) << dlerror();
278
279 ASSERT_EQ(0, dlclose(handle_for_1));
280
281 typedef int (*fn_t) (void);
282 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
283 ASSERT_TRUE(fn != nullptr) << dlerror();
284 ASSERT_EQ(42, fn());
285
286 ASSERT_EQ(0, dlclose(handle));
287}
288
Dmitriy Ivanov7699d132014-11-18 17:26:31 -0800289TEST(dlfcn, dlopen_check_order_reloc_grandchild) {
290 // This is how this one works:
291 // we lookup and call grandchild_get_answer which is defined in '_2.so'
292 // and in turn calls external get_answer_impl() defined in '_c_1.so and _c_2.so'
293 // the correct _impl() is implemented by '_c_1.so';
294 //
295 // Here is the picture of subtree:
296 //
297 // libtest_check_order_reloc_siblings.so
298 // |
299 // +-> ..._2.so <- grandchild_get_answer()
300 // |
301 // +-> ..._c.so <- empty
302 // | |
303 // | +-> _c_1.so <- exports correct answer_impl()
304 // | |
305 // | +-> _c_2.so <- exports incorrect answer_impl()
306 // |
307 // +-> ..._d.so <- empty
308
309 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
310 ASSERT_TRUE(handle == nullptr);
311#ifdef __BIONIC__
312 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
313 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
314#endif
315
316 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
317 ASSERT_TRUE(handle != nullptr) << dlerror();
318
319 typedef int (*fn_t) (void);
320 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_grandchild_get_answer"));
321 ASSERT_TRUE(fn != nullptr) << dlerror();
322 ASSERT_EQ(42, fn());
323
324 ASSERT_EQ(0, dlclose(handle));
325}
326
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700327TEST(dlfcn, dlopen_check_order_reloc_nephew) {
328 // This is how this one works:
329 // we lookup and call nephew_get_answer which is defined in '_2.so'
330 // and in turn calls external get_answer_impl() defined in '_[a-f].so'
331 // the correct _impl() is implemented by '_a.so';
332 //
333 // Here is the picture:
334 //
335 // libtest_check_order_reloc_siblings.so
336 // |
337 // +-> ..._1.so <- empty
338 // | |
339 // | +-> ..._a.so <- exports correct answer_impl()
340 // | |
341 // | +-> ..._b.so <- every other letter exporting incorrect one.
342 // |
343 // +-> ..._2.so <- empty
344 // | |
345 // | +-> ..._c.so
346 // | |
347 // | +-> ..._d.so
348 // |
349 // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl();
350 // |
351 // +-> ..._e.so
352 // |
353 // +-> ..._f.so
354
355 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
356 ASSERT_TRUE(handle == nullptr);
357#ifdef __BIONIC__
358 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
359 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
360#endif
361
362 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
363 ASSERT_TRUE(handle != nullptr) << dlerror();
364
365 typedef int (*fn_t) (void);
366 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_nephew_get_answer"));
367 ASSERT_TRUE(fn != nullptr) << dlerror();
368 ASSERT_EQ(42, fn());
369
370 ASSERT_EQ(0, dlclose(handle));
371}
372
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800373TEST(dlfcn, check_unload_after_reloc) {
374 // This is how this one works:
375 // libtest_two_parents_parent1 <- answer_impl() used by libtest_two_parents_child
376 // |
377 // +-> libtest_two_parents_child
378 //
379 // libtest_two_parents_parent2 <- answer_impl() not used by libtest_two_parents_child
380 // |
381 // +-> libtest_two_parents_child
382 //
383 // Test dlopens parent1 which loads and relocates libtest_two_parents_child.so
384 // as a second step it dlopens parent2 and dlcloses parent1...
385
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700386 void* handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL);
387 ASSERT_TRUE(handle != nullptr) << dlerror();
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800388
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700389 void* handle2 = dlopen("libtest_two_parents_parent2.so", RTLD_NOW | RTLD_LOCAL);
390 ASSERT_TRUE(handle2 != nullptr) << dlerror();
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800391
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700392 typedef int (*fn_t) (void);
393 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
394 ASSERT_TRUE(fn != nullptr) << dlerror();
395 ASSERT_EQ(42, fn());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800396
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700397 ASSERT_EQ(0, dlclose(handle));
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800398
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700399 handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
400 ASSERT_TRUE(handle != nullptr);
401 ASSERT_EQ(0, dlclose(handle));
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800402
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700403 fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
404 ASSERT_TRUE(fn != nullptr) << dlerror();
405 ASSERT_EQ(42, fn());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800406
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700407 ASSERT_EQ(0, dlclose(handle2));
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800408
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700409 handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
410 ASSERT_TRUE(handle == nullptr);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800411}
412
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700413extern "C" int check_order_reloc_root_get_answer_impl() {
414 return 42;
415}
416
417TEST(dlfcn, dlopen_check_order_reloc_main_executable) {
418 // This is how this one works:
419 // we lookup and call get_answer3 which is defined in 'root.so'
420 // and in turn calls external root_get_answer_impl() defined in _2.so and
421 // above the correct _impl() is one in the executable.
422 //
423 // libtest_check_order_reloc_root.so
424 // |
425 // +-> ..._1.so <- empty
426 // |
427 // +-> ..._2.so <- gives incorrect answer for answer_main_impl()
428 //
429
430 void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD);
431 ASSERT_TRUE(handle == nullptr);
432#ifdef __BIONIC__
433 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
434 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
435#endif
436
437 handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL);
438 ASSERT_TRUE(handle != nullptr) << dlerror();
439
440 typedef int (*fn_t) (void);
441 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_root_get_answer"));
442 ASSERT_TRUE(fn != nullptr) << dlerror();
443 ASSERT_EQ(42, fn());
444
445 ASSERT_EQ(0, dlclose(handle));
446}
447
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700448TEST(dlfcn, dlopen_check_rtld_local) {
449 void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
450 ASSERT_TRUE(sym == nullptr);
451
452 // implicit RTLD_LOCAL
453 void* handle = dlopen("libtest_simple.so", RTLD_NOW);
454 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
455 ASSERT_TRUE(sym == nullptr);
456 ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
457 sym = dlsym(handle, "dlopen_testlib_simple_func");
458 ASSERT_TRUE(sym != nullptr);
459 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
460 dlclose(handle);
461
462 // explicit RTLD_LOCAL
463 handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL);
464 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
465 ASSERT_TRUE(sym == nullptr);
466 ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
467 sym = dlsym(handle, "dlopen_testlib_simple_func");
468 ASSERT_TRUE(sym != nullptr);
469 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
470 dlclose(handle);
471}
472
473TEST(dlfcn, dlopen_check_rtld_global) {
474 void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
475 ASSERT_TRUE(sym == nullptr);
476
477 void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -0700478 ASSERT_TRUE(handle != nullptr) << dlerror();
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700479 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
480 ASSERT_TRUE(sym != nullptr) << dlerror();
481 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
482 dlclose(handle);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -0700483
484 // RTLD_GLOBAL implies RTLD_NODELETE, let's check that
485 void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
486 ASSERT_EQ(sym, sym_after_dlclose);
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700487}
488
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700489// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
490// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so ->
491// libtest_with_dependency_loop_a.so
492TEST(dlfcn, dlopen_check_loop) {
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700493 void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW);
494 ASSERT_TRUE(handle != nullptr) << dlerror();
495 void* f = dlsym(handle, "dlopen_test_loopy_function");
496 ASSERT_TRUE(f != nullptr) << dlerror();
497 EXPECT_TRUE(reinterpret_cast<bool (*)(void)>(f)());
498 ASSERT_EQ(0, dlclose(handle));
Dmitriy Ivanova6ac54a2014-09-09 10:21:42 -0700499
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700500 // dlopen second time to make sure that the library was unloaded correctly
501 handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
502 ASSERT_TRUE(handle == nullptr);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800503#ifdef __BIONIC__
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700504 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
505 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 -0700506#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800507
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700508 handle = dlopen("libtest_with_dependency_a.so", RTLD_NOW | RTLD_NOLOAD);
509 ASSERT_TRUE(handle == nullptr);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700510}
511
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -0700512TEST(dlfcn, dlopen_nodelete) {
513 static bool is_unloaded = false;
514
515 void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE);
516 ASSERT_TRUE(handle != nullptr) << dlerror();
517 void (*set_unload_flag_ptr)(bool*);
518 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr"));
519 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
520 set_unload_flag_ptr(&is_unloaded);
521
522 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
523 ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
524 ASSERT_EQ(1729U, *taxicab_number);
525 *taxicab_number = 2;
526
527 dlclose(handle);
528 ASSERT_TRUE(!is_unloaded);
529
530 uint32_t* taxicab_number_after_dlclose = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
531 ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number);
532 ASSERT_EQ(2U, *taxicab_number_after_dlclose);
533
534
535 handle = dlopen("libtest_nodelete_1.so", RTLD_NOW);
536 uint32_t* taxicab_number2 = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
537 ASSERT_EQ(taxicab_number2, taxicab_number);
538
539 ASSERT_EQ(2U, *taxicab_number2);
540
541 dlclose(handle);
542 ASSERT_TRUE(!is_unloaded);
543}
544
545TEST(dlfcn, dlopen_nodelete_on_second_dlopen) {
546 static bool is_unloaded = false;
547
548 void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW);
549 ASSERT_TRUE(handle != nullptr) << dlerror();
550 void (*set_unload_flag_ptr)(bool*);
551 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr"));
552 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
553 set_unload_flag_ptr(&is_unloaded);
554
555 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_2_taxicab_number"));
556 ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
557
558 ASSERT_EQ(1729U, *taxicab_number);
559 *taxicab_number = 2;
560
561 // This RTLD_NODELETE should be ignored
562 void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE);
563 ASSERT_TRUE(handle1 != nullptr) << dlerror();
564 ASSERT_EQ(handle, handle1);
565
566 dlclose(handle1);
567 dlclose(handle);
568
569 ASSERT_TRUE(is_unloaded);
570}
571
572TEST(dlfcn, dlopen_nodelete_dt_flags_1) {
573 static bool is_unloaded = false;
574
575 void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW);
576 ASSERT_TRUE(handle != nullptr) << dlerror();
577 void (*set_unload_flag_ptr)(bool*);
578 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr"));
579 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
580 set_unload_flag_ptr(&is_unloaded);
581
582 dlclose(handle);
583 ASSERT_TRUE(!is_unloaded);
584}
585
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700586TEST(dlfcn, dlsym_df_1_global) {
Dmitriy Ivanov4e446b12014-10-31 17:27:02 -0700587#if !defined(__arm__) && !defined(__aarch64__)
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700588 void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW);
589 ASSERT_TRUE(handle != nullptr) << dlerror();
590 int (*get_answer)();
591 get_answer = reinterpret_cast<int (*)()>(dlsym(handle, "dl_df_1_global_get_answer"));
592 ASSERT_TRUE(get_answer != nullptr) << dlerror();
593 ASSERT_EQ(42, get_answer());
594 ASSERT_EQ(0, dlclose(handle));
595#else
Dmitriy Ivanov4e446b12014-10-31 17:27:02 -0700596 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 -0700597#endif
598}
599
Elliott Hughese66190d2012-12-18 15:57:55 -0800600TEST(dlfcn, dlopen_failure) {
Elliott Hughes3b297c42012-10-11 16:08:51 -0700601 void* self = dlopen("/does/not/exist", RTLD_NOW);
602 ASSERT_TRUE(self == NULL);
Elliott Hughes063525c2014-05-13 11:19:57 -0700603#if defined(__BIONIC__)
Elliott Hughes3b297c42012-10-11 16:08:51 -0700604 ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
605#else
606 ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
607#endif
608}
609
Elliott Hughesad88a082012-10-24 18:37:21 -0700610static void* ConcurrentDlErrorFn(void*) {
Elliott Hughes5419b942012-10-16 15:54:46 -0700611 dlopen("/child/thread", RTLD_NOW);
612 return reinterpret_cast<void*>(strdup(dlerror()));
613}
614
Elliott Hughese66190d2012-12-18 15:57:55 -0800615TEST(dlfcn, dlerror_concurrent) {
Elliott Hughes5419b942012-10-16 15:54:46 -0700616 dlopen("/main/thread", RTLD_NOW);
617 const char* main_thread_error = dlerror();
618 ASSERT_SUBSTR("/main/thread", main_thread_error);
619
620 pthread_t t;
621 ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentDlErrorFn, NULL));
622 void* result;
623 ASSERT_EQ(0, pthread_join(t, &result));
624 char* child_thread_error = static_cast<char*>(result);
625 ASSERT_SUBSTR("/child/thread", child_thread_error);
626 free(child_thread_error);
627
628 ASSERT_SUBSTR("/main/thread", main_thread_error);
629}
630
Elliott Hughese66190d2012-12-18 15:57:55 -0800631TEST(dlfcn, dlsym_failures) {
Elliott Hughes3b297c42012-10-11 16:08:51 -0700632 dlerror(); // Clear any pending errors.
Elliott Hughes8e15b082012-09-26 11:44:01 -0700633 void* self = dlopen(NULL, RTLD_NOW);
634 ASSERT_TRUE(self != NULL);
Elliott Hughes3b297c42012-10-11 16:08:51 -0700635 ASSERT_TRUE(dlerror() == NULL);
636
637 void* sym;
638
Dmitriy Ivanov44adf932014-05-22 09:49:24 -0700639#if defined(__BIONIC__) && !defined(__LP64__)
640 // RTLD_DEFAULT in lp32 bionic is not (void*)0
641 // so it can be distinguished from the NULL handle.
Elliott Hughes3b297c42012-10-11 16:08:51 -0700642 sym = dlsym(NULL, "test");
643 ASSERT_TRUE(sym == NULL);
Elliott Hughes3b297c42012-10-11 16:08:51 -0700644 ASSERT_SUBSTR("dlsym library handle is null", dlerror());
Elliott Hughes3b297c42012-10-11 16:08:51 -0700645#endif
646
647 // NULL symbol name.
Elliott Hughes063525c2014-05-13 11:19:57 -0700648#if defined(__BIONIC__)
Elliott Hughes3b297c42012-10-11 16:08:51 -0700649 // glibc marks this parameter non-null and SEGVs if you cheat.
650 sym = dlsym(self, NULL);
651 ASSERT_TRUE(sym == NULL);
652 ASSERT_SUBSTR("", dlerror());
653#endif
654
655 // Symbol that doesn't exist.
656 sym = dlsym(self, "ThisSymbolDoesNotExist");
657 ASSERT_TRUE(sym == NULL);
658 ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
Elliott Hughes1a696162012-11-01 13:49:32 -0700659
660 ASSERT_EQ(0, dlclose(self));
Elliott Hughes3b297c42012-10-11 16:08:51 -0700661}
662
Elliott Hughese66190d2012-12-18 15:57:55 -0800663TEST(dlfcn, dladdr) {
Elliott Hughes3b297c42012-10-11 16:08:51 -0700664 dlerror(); // Clear any pending errors.
665 void* self = dlopen(NULL, RTLD_NOW);
666 ASSERT_TRUE(self != NULL);
667 ASSERT_TRUE(dlerror() == NULL);
Elliott Hughes8e15b082012-09-26 11:44:01 -0700668
669 void* sym = dlsym(self, "DlSymTestFunction");
670 ASSERT_TRUE(sym != NULL);
671
672 // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
673 void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
674
675 Dl_info info;
676 int rc = dladdr(addr, &info);
677 ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
678
679 // Get the name of this executable.
680 char executable_path[PATH_MAX];
681 rc = readlink("/proc/self/exe", executable_path, sizeof(executable_path));
682 ASSERT_NE(rc, -1);
683 executable_path[rc] = '\0';
684 std::string executable_name(basename(executable_path));
685
686 // The filename should be that of this executable.
687 // Note that we don't know whether or not we have the full path, so we want an "ends_with" test.
688 std::string dli_fname(info.dli_fname);
689 dli_fname = basename(&dli_fname[0]);
690 ASSERT_EQ(dli_fname, executable_name);
691
692 // The symbol name should be the symbol we looked up.
693 ASSERT_STREQ(info.dli_sname, "DlSymTestFunction");
694
695 // The address should be the exact address of the symbol.
696 ASSERT_EQ(info.dli_saddr, sym);
697
698 // Look in /proc/pid/maps to find out what address we were loaded at.
699 // TODO: factor /proc/pid/maps parsing out into a class and reuse all over bionic.
700 void* base_address = NULL;
Elliott Hughes8e15b082012-09-26 11:44:01 -0700701 char line[BUFSIZ];
Elliott Hughes57b7a612014-08-25 17:26:50 -0700702 FILE* fp = fopen("/proc/self/maps", "r");
Elliott Hughes8e15b082012-09-26 11:44:01 -0700703 ASSERT_TRUE(fp != NULL);
704 while (fgets(line, sizeof(line), fp) != NULL) {
705 uintptr_t start = strtoul(line, 0, 16);
706 line[strlen(line) - 1] = '\0'; // Chomp the '\n'.
707 char* path = strchr(line, '/');
Elliott Hughes156da962012-10-09 17:14:56 -0700708 if (path != NULL && strcmp(executable_path, path) == 0) {
Elliott Hughes8e15b082012-09-26 11:44:01 -0700709 base_address = reinterpret_cast<void*>(start);
710 break;
711 }
712 }
713 fclose(fp);
714
715 // The base address should be the address we were loaded at.
716 ASSERT_EQ(info.dli_fbase, base_address);
Elliott Hughes1a696162012-11-01 13:49:32 -0700717
718 ASSERT_EQ(0, dlclose(self));
Elliott Hughes8e15b082012-09-26 11:44:01 -0700719}
720
Elliott Hughese66190d2012-12-18 15:57:55 -0800721TEST(dlfcn, dladdr_invalid) {
Elliott Hughes8e15b082012-09-26 11:44:01 -0700722 Dl_info info;
723
Elliott Hughes3b297c42012-10-11 16:08:51 -0700724 dlerror(); // Clear any pending errors.
725
Elliott Hughes8e15b082012-09-26 11:44:01 -0700726 // No symbol corresponding to NULL.
727 ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success.
Elliott Hughes3b297c42012-10-11 16:08:51 -0700728 ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
Elliott Hughes8e15b082012-09-26 11:44:01 -0700729
730 // No symbol corresponding to a stack address.
731 ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
Elliott Hughes3b297c42012-10-11 16:08:51 -0700732 ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
Elliott Hughes8e15b082012-09-26 11:44:01 -0700733}
Elliott Hughes124fae92012-10-31 14:20:03 -0700734
Elliott Hughesa43e9062013-01-07 14:18:22 -0800735// GNU-style ELF hash tables are incompatible with the MIPS ABI.
736// 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 -0800737TEST(dlfcn, dlopen_library_with_only_gnu_hash) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800738#if !defined(__mips__)
Elliott Hughes124fae92012-10-31 14:20:03 -0700739 dlerror(); // Clear any pending errors.
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800740 void* handle = dlopen("libgnu-hash-table-library.so", RTLD_NOW);
741 ASSERT_TRUE(handle != nullptr) << dlerror();
742 auto guard = make_scope_guard([&]() {
743 dlclose(handle);
744 });
745 void* sym = dlsym(handle, "getRandomNumber");
746 ASSERT_TRUE(sym != nullptr) << dlerror();
747 int (*fn)(void);
748 fn = reinterpret_cast<int (*)(void)>(sym);
749 EXPECT_EQ(4, fn());
750
751 Dl_info dlinfo;
752 ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
753
754 ASSERT_TRUE(fn == dlinfo.dli_saddr);
755 ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
Dmitriy Ivanovb3356772014-11-14 11:19:22 -0800756 ASSERT_SUBSTR("libgnu-hash-table-library.so", dlinfo.dli_fname);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800757#else
758 GTEST_LOG_(INFO) << "This test does nothing for mips/mips64; mips toolchain does not support '--hash-style=gnu'\n";
759#endif
Elliott Hughes124fae92012-10-31 14:20:03 -0700760}
Elliott Hughese66190d2012-12-18 15:57:55 -0800761
Dmitriy Ivanovb3356772014-11-14 11:19:22 -0800762TEST(dlfcn, dlopen_library_with_only_sysv_hash) {
763 void* handle = dlopen("libsysv-hash-table-library.so", RTLD_NOW);
764 ASSERT_TRUE(handle != nullptr) << dlerror();
765 auto guard = make_scope_guard([&]() {
766 dlclose(handle);
767 });
768 void* sym = dlsym(handle, "getRandomNumber");
769 ASSERT_TRUE(sym != nullptr) << dlerror();
770 int (*fn)(void);
771 fn = reinterpret_cast<int (*)(void)>(sym);
772 EXPECT_EQ(4, fn());
773
774 Dl_info dlinfo;
775 ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
776
777 ASSERT_TRUE(fn == dlinfo.dli_saddr);
778 ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
779 ASSERT_SUBSTR("libsysv-hash-table-library.so", dlinfo.dli_fname);
780}
781
Elliott Hughese66190d2012-12-18 15:57:55 -0800782TEST(dlfcn, dlopen_bad_flags) {
783 dlerror(); // Clear any pending errors.
784 void* handle;
785
Elliott Hughes063525c2014-05-13 11:19:57 -0700786#if defined(__GLIBC__)
Elliott Hughese66190d2012-12-18 15:57:55 -0800787 // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
788 handle = dlopen(NULL, 0);
789 ASSERT_TRUE(handle == NULL);
790 ASSERT_SUBSTR("invalid", dlerror());
791#endif
792
793 handle = dlopen(NULL, 0xffffffff);
794 ASSERT_TRUE(handle == NULL);
795 ASSERT_SUBSTR("invalid", dlerror());
796
797 // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
798 handle = dlopen(NULL, RTLD_NOW|RTLD_LAZY);
799 ASSERT_TRUE(handle != NULL);
800 ASSERT_SUBSTR(NULL, dlerror());
801}
Sergey Melnikovebd506c2013-10-31 18:02:12 +0400802
803TEST(dlfcn, rtld_default_unknown_symbol) {
Elliott Hughes2ed71092013-11-11 15:48:06 -0800804 void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
Sergey Melnikovebd506c2013-10-31 18:02:12 +0400805 ASSERT_TRUE(addr == NULL);
806}
807
808TEST(dlfcn, rtld_default_known_symbol) {
Elliott Hughes2ed71092013-11-11 15:48:06 -0800809 void* addr = dlsym(RTLD_DEFAULT, "fopen");
810 ASSERT_TRUE(addr != NULL);
811}
812
813TEST(dlfcn, rtld_next_unknown_symbol) {
814 void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
815 ASSERT_TRUE(addr == NULL);
816}
817
818TEST(dlfcn, rtld_next_known_symbol) {
819 void* addr = dlsym(RTLD_NEXT, "fopen");
Sergey Melnikovebd506c2013-10-31 18:02:12 +0400820 ASSERT_TRUE(addr != NULL);
821}
Dmitriy Ivanov7db18092014-05-08 12:27:25 -0700822
Dmitriy Ivanovce441662014-06-17 15:56:38 -0700823TEST(dlfcn, dlsym_weak_func) {
824 dlerror();
Dmitriy Ivanovbfa88bc2014-12-16 11:40:46 -0800825 void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW);
Dmitriy Ivanovce441662014-06-17 15:56:38 -0700826 ASSERT_TRUE(handle != NULL);
827
828 int (*weak_func)();
829 weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
830 ASSERT_TRUE(weak_func != NULL) << "dlerror: " << dlerror();
831 EXPECT_EQ(42, weak_func());
832 dlclose(handle);
833}
834
Dmitriy Ivanovbfa88bc2014-12-16 11:40:46 -0800835TEST(dlfcn, dlopen_undefined_weak_func) {
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700836 void* handle = dlopen("libtest_dlopen_weak_undefined_func.so", RTLD_NOW);
837 ASSERT_TRUE(handle != nullptr) << dlerror();
838 int (*weak_func)();
839 weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "use_weak_undefined_func"));
840 ASSERT_TRUE(weak_func != nullptr) << dlerror();
841 EXPECT_EQ(6551, weak_func());
842 dlclose(handle);
Dmitriy Ivanovbfa88bc2014-12-16 11:40:46 -0800843}
844
Dmitriy Ivanov7db18092014-05-08 12:27:25 -0700845TEST(dlfcn, dlopen_symlink) {
846 void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
847 void* handle2 = dlopen("libdlext_test_v2.so", RTLD_NOW);
848 ASSERT_TRUE(handle1 != NULL);
849 ASSERT_TRUE(handle2 != NULL);
850 ASSERT_EQ(handle1, handle2);
Dmitriy Ivanov319356e2014-09-02 17:31:44 -0700851 dlclose(handle1);
852 dlclose(handle2);
Dmitriy Ivanov7db18092014-05-08 12:27:25 -0700853}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800854
Simon Baldwinaef71952015-01-16 13:22:54 +0000855TEST(dlfcn, dlopen_from_zip_absolute_path) {
856 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;
857
858 void* handle = dlopen((lib_path + "!libdir/libdlext_test_fd.so").c_str(), RTLD_NOW);
859 ASSERT_TRUE(handle != nullptr) << dlerror();
860
861 int (*fn)(void);
862 fn = reinterpret_cast<int (*)(void)>(dlsym(handle, "getRandomNumber"));
863 ASSERT_TRUE(fn != nullptr);
864 EXPECT_EQ(4, fn());
865
866 dlclose(handle);
867}
868
869TEST(dlfcn, dlopen_from_zip_ld_library_path) {
870 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH + "!libdir";
871
872 typedef void (*fn_t)(const char*);
873 fn_t android_update_LD_LIBRARY_PATH =
874 reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "android_update_LD_LIBRARY_PATH"));
875
876 ASSERT_TRUE(android_update_LD_LIBRARY_PATH != nullptr) << dlerror();
877
878 void* handle = dlopen("libdlext_test_fd.so", RTLD_NOW);
879 ASSERT_TRUE(handle == nullptr);
880
881 android_update_LD_LIBRARY_PATH(lib_path.c_str());
882
883 handle = dlopen("libdlext_test_fd.so", RTLD_NOW);
884 ASSERT_TRUE(handle != nullptr) << dlerror();
885
886 int (*fn)(void);
887 fn = reinterpret_cast<int (*)(void)>(dlsym(handle, "getRandomNumber"));
888 ASSERT_TRUE(fn != nullptr);
889 EXPECT_EQ(4, fn());
890
891 dlclose(handle);
892}
893
894
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800895// libtest_dlopen_from_ctor_main.so depends on
896// libtest_dlopen_from_ctor.so which has a constructor
897// that calls dlopen(libc...). This is to test the situation
898// described in b/7941716.
899TEST(dlfcn, dlopen_dlopen_from_ctor) {
900#if defined(__BIONIC__)
901 void* handle = dlopen("libtest_dlopen_from_ctor_main.so", RTLD_NOW);
902 ASSERT_TRUE(handle != nullptr) << dlerror();
903 dlclose(handle);
904#else
905 GTEST_LOG_(INFO) << "This test is disabled for glibc (glibc segfaults if you try to call dlopen from a constructor).\n";
906#endif
907}