blob: 1061e84f23da142a2a9d80e8963e6442b04cd406 [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
Elliott Hughese66190d2012-12-18 15:57:55 -080049TEST(dlfcn, dlsym_in_self) {
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 Ivanovaa0f2bd2014-07-28 17:32:20 -070067TEST(dlfcn, dlsym_with_dependencies) {
68 void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
69 ASSERT_TRUE(handle != NULL);
70 dlerror();
71 // This symbol is in DT_NEEDED library.
72 void* sym = dlsym(handle, "getRandomNumber");
73 ASSERT_TRUE(sym != NULL);
74 int (*fn)(void);
75 fn = reinterpret_cast<int (*)(void)>(sym);
76 EXPECT_EQ(4, fn());
77 dlclose(handle);
78}
79
Dmitriy Ivanovb648a8a2014-05-19 15:06:58 -070080TEST(dlfcn, dlopen_noload) {
81 void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
82 ASSERT_TRUE(handle == NULL);
83 handle = dlopen("libtest_simple.so", RTLD_NOW);
84 void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
85 ASSERT_TRUE(handle != NULL);
86 ASSERT_TRUE(handle2 != NULL);
87 ASSERT_TRUE(handle == handle2);
88 ASSERT_EQ(0, dlclose(handle));
89 ASSERT_EQ(0, dlclose(handle2));
90}
91
Dmitriy Ivanov618f1a32015-03-17 20:06:36 -070092TEST(dlfcn, dlopen_by_soname) {
93 static const char* soname = "libdlext_test_soname.so";
94 static const char* filename = "libdlext_test_different_soname.so";
95 // 1. Make sure there is no library with soname in default search path
96 void* handle = dlopen(soname, RTLD_NOW);
97 ASSERT_TRUE(handle == nullptr);
98
99 // 2. Load a library using filename
100 handle = dlopen(filename, RTLD_NOW);
101 ASSERT_TRUE(handle != nullptr) << dlerror();
102
103 // 3. Find library by soname
104 void* handle_soname = dlopen(soname, RTLD_NOW | RTLD_NOLOAD);
105 ASSERT_TRUE(handle_soname != nullptr) << dlerror();
106 ASSERT_EQ(handle, handle_soname);
107
108 // 4. RTLD_NOLOAD should still work with filename
109 void* handle_filename = dlopen(filename, RTLD_NOW | RTLD_NOLOAD);
110 ASSERT_TRUE(handle_filename != nullptr) << dlerror();
111 ASSERT_EQ(handle, handle_filename);
112
113 dlclose(handle_filename);
114 dlclose(handle_soname);
115 dlclose(handle);
116}
117
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -0700118// ifuncs are only supported on intel and arm64 for now
119#if defined (__aarch64__) || defined(__i386__) || defined(__x86_64__)
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700120TEST(dlfcn, ifunc) {
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700121 typedef const char* (*fn_ptr)();
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700122
123 // ifunc's choice depends on whether IFUNC_CHOICE has a value
124 // first check the set case
125 setenv("IFUNC_CHOICE", "set", 1);
126 void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
127 ASSERT_TRUE(handle != NULL);
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700128 fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
129 fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700130 ASSERT_TRUE(foo_ptr != NULL);
131 ASSERT_TRUE(foo_library_ptr != NULL);
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700132 ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
133 ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700134 dlclose(handle);
135
136 // then check the unset case
137 unsetenv("IFUNC_CHOICE");
138 handle = dlopen("libtest_ifunc.so", RTLD_NOW);
139 ASSERT_TRUE(handle != NULL);
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700140 foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
141 foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700142 ASSERT_TRUE(foo_ptr != NULL);
143 ASSERT_TRUE(foo_library_ptr != NULL);
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700144 ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
145 ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
146 dlclose(handle);
147}
148
149TEST(dlfcn, ifunc_ctor_call) {
150 typedef const char* (*fn_ptr)();
151
152 void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
Dmitriy Ivanov9aea1642014-09-11 15:16:03 -0700153 ASSERT_TRUE(handle != nullptr) << dlerror();
154 fn_ptr is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
155 ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
156 ASSERT_STREQ("false", is_ctor_called());
157
158 is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
159 ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
Dmitriy Ivanov9598b8c2014-08-21 13:54:03 -0700160 ASSERT_STREQ("true", is_ctor_called());
Brigid Smithc5a13ef2014-07-23 11:22:25 -0700161 dlclose(handle);
162}
163#endif
164
Dmitriy Ivanovb2a30ee2014-09-04 18:23:00 -0700165TEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
166 // This is the structure of the test library and
167 // its dt_needed libraries
168 // libtest_relo_check_dt_needed_order.so
169 // |
170 // +-> libtest_relo_check_dt_needed_order_1.so
171 // |
172 // +-> libtest_relo_check_dt_needed_order_2.so
173 //
174 // The root library references relo_test_get_answer_lib - which is defined
175 // in both dt_needed libraries, the correct relocation should
176 // use the function defined in libtest_relo_check_dt_needed_order_1.so
177 void* handle = nullptr;
Dmitriy Ivanovd9ff7222014-09-08 16:22:22 -0700178 auto guard = make_scope_guard([&]() {
Dmitriy Ivanovb2a30ee2014-09-04 18:23:00 -0700179 dlclose(handle);
180 });
181
182 handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
183 ASSERT_TRUE(handle != nullptr) << dlerror();
184
185 typedef int (*fn_t) (void);
186 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
187 ASSERT_TRUE(fn != nullptr) << dlerror();
188 ASSERT_EQ(1, fn());
189}
190
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700191TEST(dlfcn, dlopen_check_order_dlsym) {
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700192 // Here is how the test library and its dt_needed
193 // libraries are arranged
194 //
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700195 // libtest_check_order_children.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700196 // |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700197 // +-> ..._1_left.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700198 // | |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700199 // | +-> ..._a.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700200 // | |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700201 // | +-> ...r_b.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700202 // |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700203 // +-> ..._2_right.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700204 // | |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700205 // | +-> ..._d.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700206 // | |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700207 // | +-> ..._b.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700208 // |
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700209 // +-> ..._3_c.so
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700210 //
211 // load order should be (1, 2, 3, a, b, d)
212 //
213 // get_answer() is defined in (2, 3, a, b, c)
214 // get_answer2() is defined in (b, d)
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700215 void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer");
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700216 ASSERT_TRUE(sym == nullptr);
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700217 void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL);
218 ASSERT_TRUE(handle != nullptr) << dlerror();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700219 typedef int (*fn_t) (void);
220 fn_t fn, fn2;
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700221 fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"));
Dmitriy Ivanoveb27bba2014-09-15 14:13:24 -0700222 ASSERT_TRUE(fn != NULL) << dlerror();
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700223 fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2"));
Dmitriy Ivanoveb27bba2014-09-15 14:13:24 -0700224 ASSERT_TRUE(fn2 != NULL) << dlerror();
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700225
226 ASSERT_EQ(42, fn());
227 ASSERT_EQ(43, fn2());
228 dlclose(handle);
229}
230
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700231TEST(dlfcn, dlopen_check_order_reloc_siblings) {
232 // This is how this one works:
233 // we lookup and call get_answer which is defined in '_2.so'
234 // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so'
235 // the correct _impl() is implemented by '_a.so';
236 //
237 // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?)
238 //
239 // Here is the picture:
240 //
241 // libtest_check_order_reloc_siblings.so
242 // |
243 // +-> ..._1.so <- empty
244 // | |
245 // | +-> ..._a.so <- exports correct answer_impl()
246 // | |
247 // | +-> ..._b.so <- every other letter exporting incorrect one.
248 // |
249 // +-> ..._2.so <- empty
250 // | |
251 // | +-> ..._c.so
252 // | |
253 // | +-> ..._d.so
254 // |
255 // +-> ..._3.so <- empty
256 // |
257 // +-> ..._e.so
258 // |
259 // +-> ..._f.so <- exports get_answer() that calls get_anser_impl();
260 // implements incorrect get_answer_impl()
261
262 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
263 ASSERT_TRUE(handle == nullptr);
264#ifdef __BIONIC__
265 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
266 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
267#endif
268
269 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
270 ASSERT_TRUE(handle != nullptr) << dlerror();
271
272 typedef int (*fn_t) (void);
273 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
274 ASSERT_TRUE(fn != nullptr) << dlerror();
275 ASSERT_EQ(42, fn());
276
277 ASSERT_EQ(0, dlclose(handle));
278}
279
280TEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) {
281 // This test uses the same library as dlopen_check_order_reloc_siblings.
282 // Unlike dlopen_check_order_reloc_siblings it preloads
283 // libtest_check_order_reloc_siblings_1.so (first dependency) prior to
284 // dlopen(libtest_check_order_reloc_siblings.so)
285
286 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
287 ASSERT_TRUE(handle == nullptr);
288 handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD);
289 ASSERT_TRUE(handle == nullptr);
290
291 void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL);
292 ASSERT_TRUE(handle_for_1 != nullptr) << dlerror();
293
294 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
295 ASSERT_TRUE(handle != nullptr) << dlerror();
296
297 ASSERT_EQ(0, dlclose(handle_for_1));
298
299 typedef int (*fn_t) (void);
300 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
301 ASSERT_TRUE(fn != nullptr) << dlerror();
302 ASSERT_EQ(42, fn());
303
304 ASSERT_EQ(0, dlclose(handle));
305}
306
Dmitriy Ivanov7699d132014-11-18 17:26:31 -0800307TEST(dlfcn, dlopen_check_order_reloc_grandchild) {
308 // This is how this one works:
309 // we lookup and call grandchild_get_answer which is defined in '_2.so'
310 // and in turn calls external get_answer_impl() defined in '_c_1.so and _c_2.so'
311 // the correct _impl() is implemented by '_c_1.so';
312 //
313 // Here is the picture of subtree:
314 //
315 // libtest_check_order_reloc_siblings.so
316 // |
317 // +-> ..._2.so <- grandchild_get_answer()
318 // |
319 // +-> ..._c.so <- empty
320 // | |
321 // | +-> _c_1.so <- exports correct answer_impl()
322 // | |
323 // | +-> _c_2.so <- exports incorrect answer_impl()
324 // |
325 // +-> ..._d.so <- empty
326
327 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
328 ASSERT_TRUE(handle == nullptr);
329#ifdef __BIONIC__
330 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
331 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
332#endif
333
334 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
335 ASSERT_TRUE(handle != nullptr) << dlerror();
336
337 typedef int (*fn_t) (void);
338 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_grandchild_get_answer"));
339 ASSERT_TRUE(fn != nullptr) << dlerror();
340 ASSERT_EQ(42, fn());
341
342 ASSERT_EQ(0, dlclose(handle));
343}
344
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700345TEST(dlfcn, dlopen_check_order_reloc_nephew) {
346 // This is how this one works:
347 // we lookup and call nephew_get_answer which is defined in '_2.so'
348 // and in turn calls external get_answer_impl() defined in '_[a-f].so'
349 // the correct _impl() is implemented by '_a.so';
350 //
351 // Here is the picture:
352 //
353 // libtest_check_order_reloc_siblings.so
354 // |
355 // +-> ..._1.so <- empty
356 // | |
357 // | +-> ..._a.so <- exports correct answer_impl()
358 // | |
359 // | +-> ..._b.so <- every other letter exporting incorrect one.
360 // |
361 // +-> ..._2.so <- empty
362 // | |
363 // | +-> ..._c.so
364 // | |
365 // | +-> ..._d.so
366 // |
367 // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl();
368 // |
369 // +-> ..._e.so
370 // |
371 // +-> ..._f.so
372
373 void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
374 ASSERT_TRUE(handle == nullptr);
375#ifdef __BIONIC__
376 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
377 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
378#endif
379
380 handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
381 ASSERT_TRUE(handle != nullptr) << dlerror();
382
383 typedef int (*fn_t) (void);
384 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_nephew_get_answer"));
385 ASSERT_TRUE(fn != nullptr) << dlerror();
386 ASSERT_EQ(42, fn());
387
388 ASSERT_EQ(0, dlclose(handle));
389}
390
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800391TEST(dlfcn, check_unload_after_reloc) {
392 // This is how this one works:
393 // libtest_two_parents_parent1 <- answer_impl() used by libtest_two_parents_child
394 // |
395 // +-> libtest_two_parents_child
396 //
397 // libtest_two_parents_parent2 <- answer_impl() not used by libtest_two_parents_child
398 // |
399 // +-> libtest_two_parents_child
400 //
401 // Test dlopens parent1 which loads and relocates libtest_two_parents_child.so
402 // as a second step it dlopens parent2 and dlcloses parent1...
403
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700404 void* handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL);
405 ASSERT_TRUE(handle != nullptr) << dlerror();
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800406
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700407 void* handle2 = dlopen("libtest_two_parents_parent2.so", RTLD_NOW | RTLD_LOCAL);
408 ASSERT_TRUE(handle2 != nullptr) << dlerror();
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800409
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700410 typedef int (*fn_t) (void);
411 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
412 ASSERT_TRUE(fn != nullptr) << dlerror();
413 ASSERT_EQ(42, fn());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800414
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700415 ASSERT_EQ(0, dlclose(handle));
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800416
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700417 handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
418 ASSERT_TRUE(handle != nullptr);
419 ASSERT_EQ(0, dlclose(handle));
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800420
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700421 fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
422 ASSERT_TRUE(fn != nullptr) << dlerror();
423 ASSERT_EQ(42, fn());
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800424
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700425 ASSERT_EQ(0, dlclose(handle2));
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800426
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700427 handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
428 ASSERT_TRUE(handle == nullptr);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800429}
430
Dmitriy Ivanovcfa97f12014-10-21 09:23:18 -0700431extern "C" int check_order_reloc_root_get_answer_impl() {
432 return 42;
433}
434
435TEST(dlfcn, dlopen_check_order_reloc_main_executable) {
436 // This is how this one works:
437 // we lookup and call get_answer3 which is defined in 'root.so'
438 // and in turn calls external root_get_answer_impl() defined in _2.so and
439 // above the correct _impl() is one in the executable.
440 //
441 // libtest_check_order_reloc_root.so
442 // |
443 // +-> ..._1.so <- empty
444 // |
445 // +-> ..._2.so <- gives incorrect answer for answer_main_impl()
446 //
447
448 void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD);
449 ASSERT_TRUE(handle == nullptr);
450#ifdef __BIONIC__
451 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
452 ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
453#endif
454
455 handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL);
456 ASSERT_TRUE(handle != nullptr) << dlerror();
457
458 typedef int (*fn_t) (void);
459 fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_root_get_answer"));
460 ASSERT_TRUE(fn != nullptr) << dlerror();
461 ASSERT_EQ(42, fn());
462
463 ASSERT_EQ(0, dlclose(handle));
464}
465
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700466TEST(dlfcn, dlopen_check_rtld_local) {
467 void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
468 ASSERT_TRUE(sym == nullptr);
469
470 // implicit RTLD_LOCAL
471 void* handle = dlopen("libtest_simple.so", RTLD_NOW);
472 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
473 ASSERT_TRUE(sym == nullptr);
474 ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
475 sym = dlsym(handle, "dlopen_testlib_simple_func");
476 ASSERT_TRUE(sym != nullptr);
477 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
478 dlclose(handle);
479
480 // explicit RTLD_LOCAL
481 handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL);
482 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
483 ASSERT_TRUE(sym == nullptr);
484 ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
485 sym = dlsym(handle, "dlopen_testlib_simple_func");
486 ASSERT_TRUE(sym != nullptr);
487 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
488 dlclose(handle);
489}
490
491TEST(dlfcn, dlopen_check_rtld_global) {
492 void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
493 ASSERT_TRUE(sym == nullptr);
494
495 void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -0700496 ASSERT_TRUE(handle != nullptr) << dlerror();
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700497 sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
498 ASSERT_TRUE(sym != nullptr) << dlerror();
499 ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
500 dlclose(handle);
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -0700501
502 // RTLD_GLOBAL implies RTLD_NODELETE, let's check that
503 void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
504 ASSERT_EQ(sym, sym_after_dlclose);
Dmitriy Ivanove8ba50f2014-09-15 17:00:10 -0700505}
506
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700507// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
508// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so ->
509// libtest_with_dependency_loop_a.so
510TEST(dlfcn, dlopen_check_loop) {
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700511 void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW);
512 ASSERT_TRUE(handle != nullptr) << dlerror();
513 void* f = dlsym(handle, "dlopen_test_loopy_function");
514 ASSERT_TRUE(f != nullptr) << dlerror();
515 EXPECT_TRUE(reinterpret_cast<bool (*)(void)>(f)());
516 ASSERT_EQ(0, dlclose(handle));
Dmitriy Ivanova6ac54a2014-09-09 10:21:42 -0700517
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700518 // dlopen second time to make sure that the library was unloaded correctly
519 handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
520 ASSERT_TRUE(handle == nullptr);
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800521#ifdef __BIONIC__
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700522 // TODO: glibc returns nullptr on dlerror() here. Is it bug?
523 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 -0700524#endif
Dmitriy Ivanovab972b92014-11-29 13:57:41 -0800525
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700526 handle = dlopen("libtest_with_dependency_a.so", RTLD_NOW | RTLD_NOLOAD);
527 ASSERT_TRUE(handle == nullptr);
Dmitriy Ivanov14669a92014-09-05 16:42:53 -0700528}
529
Dmitriy Ivanov1b20daf2014-05-19 15:06:58 -0700530TEST(dlfcn, dlopen_nodelete) {
531 static bool is_unloaded = false;
532
533 void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE);
534 ASSERT_TRUE(handle != nullptr) << dlerror();
535 void (*set_unload_flag_ptr)(bool*);
536 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr"));
537 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
538 set_unload_flag_ptr(&is_unloaded);
539
540 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
541 ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
542 ASSERT_EQ(1729U, *taxicab_number);
543 *taxicab_number = 2;
544
545 dlclose(handle);
546 ASSERT_TRUE(!is_unloaded);
547
548 uint32_t* taxicab_number_after_dlclose = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
549 ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number);
550 ASSERT_EQ(2U, *taxicab_number_after_dlclose);
551
552
553 handle = dlopen("libtest_nodelete_1.so", RTLD_NOW);
554 uint32_t* taxicab_number2 = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
555 ASSERT_EQ(taxicab_number2, taxicab_number);
556
557 ASSERT_EQ(2U, *taxicab_number2);
558
559 dlclose(handle);
560 ASSERT_TRUE(!is_unloaded);
561}
562
563TEST(dlfcn, dlopen_nodelete_on_second_dlopen) {
564 static bool is_unloaded = false;
565
566 void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW);
567 ASSERT_TRUE(handle != nullptr) << dlerror();
568 void (*set_unload_flag_ptr)(bool*);
569 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr"));
570 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
571 set_unload_flag_ptr(&is_unloaded);
572
573 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_2_taxicab_number"));
574 ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
575
576 ASSERT_EQ(1729U, *taxicab_number);
577 *taxicab_number = 2;
578
579 // This RTLD_NODELETE should be ignored
580 void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE);
581 ASSERT_TRUE(handle1 != nullptr) << dlerror();
582 ASSERT_EQ(handle, handle1);
583
584 dlclose(handle1);
585 dlclose(handle);
586
587 ASSERT_TRUE(is_unloaded);
588}
589
590TEST(dlfcn, dlopen_nodelete_dt_flags_1) {
591 static bool is_unloaded = false;
592
593 void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW);
594 ASSERT_TRUE(handle != nullptr) << dlerror();
595 void (*set_unload_flag_ptr)(bool*);
596 set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr"));
597 ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
598 set_unload_flag_ptr(&is_unloaded);
599
600 dlclose(handle);
601 ASSERT_TRUE(!is_unloaded);
602}
603
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700604TEST(dlfcn, dlsym_df_1_global) {
Dmitriy Ivanov4e446b12014-10-31 17:27:02 -0700605#if !defined(__arm__) && !defined(__aarch64__)
Dmitriy Ivanovd225a5e2014-08-28 14:12:12 -0700606 void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW);
607 ASSERT_TRUE(handle != nullptr) << dlerror();
608 int (*get_answer)();
609 get_answer = reinterpret_cast<int (*)()>(dlsym(handle, "dl_df_1_global_get_answer"));
610 ASSERT_TRUE(get_answer != nullptr) << dlerror();
611 ASSERT_EQ(42, get_answer());
612 ASSERT_EQ(0, dlclose(handle));
613#else
Dmitriy Ivanov4e446b12014-10-31 17:27:02 -0700614 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 -0700615#endif
616}
617
Elliott Hughese66190d2012-12-18 15:57:55 -0800618TEST(dlfcn, dlopen_failure) {
Elliott Hughes3b297c42012-10-11 16:08:51 -0700619 void* self = dlopen("/does/not/exist", RTLD_NOW);
620 ASSERT_TRUE(self == NULL);
Elliott Hughes063525c2014-05-13 11:19:57 -0700621#if defined(__BIONIC__)
Elliott Hughes3b297c42012-10-11 16:08:51 -0700622 ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
623#else
624 ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
625#endif
626}
627
Elliott Hughesad88a082012-10-24 18:37:21 -0700628static void* ConcurrentDlErrorFn(void*) {
Elliott Hughes5419b942012-10-16 15:54:46 -0700629 dlopen("/child/thread", RTLD_NOW);
630 return reinterpret_cast<void*>(strdup(dlerror()));
631}
632
Elliott Hughese66190d2012-12-18 15:57:55 -0800633TEST(dlfcn, dlerror_concurrent) {
Elliott Hughes5419b942012-10-16 15:54:46 -0700634 dlopen("/main/thread", RTLD_NOW);
635 const char* main_thread_error = dlerror();
636 ASSERT_SUBSTR("/main/thread", main_thread_error);
637
638 pthread_t t;
639 ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentDlErrorFn, NULL));
640 void* result;
641 ASSERT_EQ(0, pthread_join(t, &result));
642 char* child_thread_error = static_cast<char*>(result);
643 ASSERT_SUBSTR("/child/thread", child_thread_error);
644 free(child_thread_error);
645
646 ASSERT_SUBSTR("/main/thread", main_thread_error);
647}
648
Elliott Hughese66190d2012-12-18 15:57:55 -0800649TEST(dlfcn, dlsym_failures) {
Elliott Hughes3b297c42012-10-11 16:08:51 -0700650 dlerror(); // Clear any pending errors.
Elliott Hughes8e15b082012-09-26 11:44:01 -0700651 void* self = dlopen(NULL, RTLD_NOW);
652 ASSERT_TRUE(self != NULL);
Elliott Hughes3b297c42012-10-11 16:08:51 -0700653 ASSERT_TRUE(dlerror() == NULL);
654
655 void* sym;
656
Dmitriy Ivanov44adf932014-05-22 09:49:24 -0700657#if defined(__BIONIC__) && !defined(__LP64__)
658 // RTLD_DEFAULT in lp32 bionic is not (void*)0
659 // so it can be distinguished from the NULL handle.
Elliott Hughes3b297c42012-10-11 16:08:51 -0700660 sym = dlsym(NULL, "test");
661 ASSERT_TRUE(sym == NULL);
Elliott Hughes3b297c42012-10-11 16:08:51 -0700662 ASSERT_SUBSTR("dlsym library handle is null", dlerror());
Elliott Hughes3b297c42012-10-11 16:08:51 -0700663#endif
664
665 // NULL symbol name.
Elliott Hughes063525c2014-05-13 11:19:57 -0700666#if defined(__BIONIC__)
Elliott Hughes3b297c42012-10-11 16:08:51 -0700667 // glibc marks this parameter non-null and SEGVs if you cheat.
668 sym = dlsym(self, NULL);
669 ASSERT_TRUE(sym == NULL);
670 ASSERT_SUBSTR("", dlerror());
671#endif
672
673 // Symbol that doesn't exist.
674 sym = dlsym(self, "ThisSymbolDoesNotExist");
675 ASSERT_TRUE(sym == NULL);
676 ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
Elliott Hughes1a696162012-11-01 13:49:32 -0700677
678 ASSERT_EQ(0, dlclose(self));
Elliott Hughes3b297c42012-10-11 16:08:51 -0700679}
680
Elliott Hughese66190d2012-12-18 15:57:55 -0800681TEST(dlfcn, dladdr) {
Elliott Hughes3b297c42012-10-11 16:08:51 -0700682 dlerror(); // Clear any pending errors.
683 void* self = dlopen(NULL, RTLD_NOW);
684 ASSERT_TRUE(self != NULL);
685 ASSERT_TRUE(dlerror() == NULL);
Elliott Hughes8e15b082012-09-26 11:44:01 -0700686
687 void* sym = dlsym(self, "DlSymTestFunction");
688 ASSERT_TRUE(sym != NULL);
689
690 // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
691 void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
692
693 Dl_info info;
694 int rc = dladdr(addr, &info);
695 ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
696
697 // Get the name of this executable.
698 char executable_path[PATH_MAX];
699 rc = readlink("/proc/self/exe", executable_path, sizeof(executable_path));
700 ASSERT_NE(rc, -1);
701 executable_path[rc] = '\0';
702 std::string executable_name(basename(executable_path));
703
704 // The filename should be that of this executable.
705 // Note that we don't know whether or not we have the full path, so we want an "ends_with" test.
706 std::string dli_fname(info.dli_fname);
707 dli_fname = basename(&dli_fname[0]);
708 ASSERT_EQ(dli_fname, executable_name);
709
710 // The symbol name should be the symbol we looked up.
711 ASSERT_STREQ(info.dli_sname, "DlSymTestFunction");
712
713 // The address should be the exact address of the symbol.
714 ASSERT_EQ(info.dli_saddr, sym);
715
716 // Look in /proc/pid/maps to find out what address we were loaded at.
717 // TODO: factor /proc/pid/maps parsing out into a class and reuse all over bionic.
718 void* base_address = NULL;
Elliott Hughes8e15b082012-09-26 11:44:01 -0700719 char line[BUFSIZ];
Elliott Hughes57b7a612014-08-25 17:26:50 -0700720 FILE* fp = fopen("/proc/self/maps", "r");
Elliott Hughes8e15b082012-09-26 11:44:01 -0700721 ASSERT_TRUE(fp != NULL);
722 while (fgets(line, sizeof(line), fp) != NULL) {
723 uintptr_t start = strtoul(line, 0, 16);
724 line[strlen(line) - 1] = '\0'; // Chomp the '\n'.
725 char* path = strchr(line, '/');
Elliott Hughes156da962012-10-09 17:14:56 -0700726 if (path != NULL && strcmp(executable_path, path) == 0) {
Elliott Hughes8e15b082012-09-26 11:44:01 -0700727 base_address = reinterpret_cast<void*>(start);
728 break;
729 }
730 }
731 fclose(fp);
732
733 // The base address should be the address we were loaded at.
734 ASSERT_EQ(info.dli_fbase, base_address);
Elliott Hughes1a696162012-11-01 13:49:32 -0700735
736 ASSERT_EQ(0, dlclose(self));
Elliott Hughes8e15b082012-09-26 11:44:01 -0700737}
738
Elliott Hughese66190d2012-12-18 15:57:55 -0800739TEST(dlfcn, dladdr_invalid) {
Elliott Hughes8e15b082012-09-26 11:44:01 -0700740 Dl_info info;
741
Elliott Hughes3b297c42012-10-11 16:08:51 -0700742 dlerror(); // Clear any pending errors.
743
Elliott Hughes8e15b082012-09-26 11:44:01 -0700744 // No symbol corresponding to NULL.
745 ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success.
Elliott Hughes3b297c42012-10-11 16:08:51 -0700746 ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
Elliott Hughes8e15b082012-09-26 11:44:01 -0700747
748 // No symbol corresponding to a stack address.
749 ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
Elliott Hughes3b297c42012-10-11 16:08:51 -0700750 ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
Elliott Hughes8e15b082012-09-26 11:44:01 -0700751}
Elliott Hughes124fae92012-10-31 14:20:03 -0700752
Elliott Hughesa43e9062013-01-07 14:18:22 -0800753// GNU-style ELF hash tables are incompatible with the MIPS ABI.
754// 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 -0800755TEST(dlfcn, dlopen_library_with_only_gnu_hash) {
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800756#if !defined(__mips__)
Elliott Hughes124fae92012-10-31 14:20:03 -0700757 dlerror(); // Clear any pending errors.
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800758 void* handle = dlopen("libgnu-hash-table-library.so", RTLD_NOW);
759 ASSERT_TRUE(handle != nullptr) << dlerror();
760 auto guard = make_scope_guard([&]() {
761 dlclose(handle);
762 });
763 void* sym = dlsym(handle, "getRandomNumber");
764 ASSERT_TRUE(sym != nullptr) << dlerror();
765 int (*fn)(void);
766 fn = reinterpret_cast<int (*)(void)>(sym);
767 EXPECT_EQ(4, fn());
768
769 Dl_info dlinfo;
770 ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
771
772 ASSERT_TRUE(fn == dlinfo.dli_saddr);
773 ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
Dmitriy Ivanovb3356772014-11-14 11:19:22 -0800774 ASSERT_SUBSTR("libgnu-hash-table-library.so", dlinfo.dli_fname);
Dmitriy Ivanovec18ce02014-11-09 19:27:20 -0800775#else
776 GTEST_LOG_(INFO) << "This test does nothing for mips/mips64; mips toolchain does not support '--hash-style=gnu'\n";
777#endif
Elliott Hughes124fae92012-10-31 14:20:03 -0700778}
Elliott Hughese66190d2012-12-18 15:57:55 -0800779
Dmitriy Ivanovb3356772014-11-14 11:19:22 -0800780TEST(dlfcn, dlopen_library_with_only_sysv_hash) {
781 void* handle = dlopen("libsysv-hash-table-library.so", RTLD_NOW);
782 ASSERT_TRUE(handle != nullptr) << dlerror();
783 auto guard = make_scope_guard([&]() {
784 dlclose(handle);
785 });
786 void* sym = dlsym(handle, "getRandomNumber");
787 ASSERT_TRUE(sym != nullptr) << dlerror();
788 int (*fn)(void);
789 fn = reinterpret_cast<int (*)(void)>(sym);
790 EXPECT_EQ(4, fn());
791
792 Dl_info dlinfo;
793 ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
794
795 ASSERT_TRUE(fn == dlinfo.dli_saddr);
796 ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
797 ASSERT_SUBSTR("libsysv-hash-table-library.so", dlinfo.dli_fname);
798}
799
Elliott Hughese66190d2012-12-18 15:57:55 -0800800TEST(dlfcn, dlopen_bad_flags) {
801 dlerror(); // Clear any pending errors.
802 void* handle;
803
Elliott Hughes063525c2014-05-13 11:19:57 -0700804#if defined(__GLIBC__)
Elliott Hughese66190d2012-12-18 15:57:55 -0800805 // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
806 handle = dlopen(NULL, 0);
807 ASSERT_TRUE(handle == NULL);
808 ASSERT_SUBSTR("invalid", dlerror());
809#endif
810
811 handle = dlopen(NULL, 0xffffffff);
812 ASSERT_TRUE(handle == NULL);
813 ASSERT_SUBSTR("invalid", dlerror());
814
815 // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
816 handle = dlopen(NULL, RTLD_NOW|RTLD_LAZY);
817 ASSERT_TRUE(handle != NULL);
818 ASSERT_SUBSTR(NULL, dlerror());
819}
Sergey Melnikovebd506c2013-10-31 18:02:12 +0400820
821TEST(dlfcn, rtld_default_unknown_symbol) {
Elliott Hughes2ed71092013-11-11 15:48:06 -0800822 void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
Sergey Melnikovebd506c2013-10-31 18:02:12 +0400823 ASSERT_TRUE(addr == NULL);
824}
825
826TEST(dlfcn, rtld_default_known_symbol) {
Elliott Hughes2ed71092013-11-11 15:48:06 -0800827 void* addr = dlsym(RTLD_DEFAULT, "fopen");
828 ASSERT_TRUE(addr != NULL);
829}
830
831TEST(dlfcn, rtld_next_unknown_symbol) {
832 void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
833 ASSERT_TRUE(addr == NULL);
834}
835
836TEST(dlfcn, rtld_next_known_symbol) {
837 void* addr = dlsym(RTLD_NEXT, "fopen");
Sergey Melnikovebd506c2013-10-31 18:02:12 +0400838 ASSERT_TRUE(addr != NULL);
839}
Dmitriy Ivanov7db18092014-05-08 12:27:25 -0700840
Dmitriy Ivanovce441662014-06-17 15:56:38 -0700841TEST(dlfcn, dlsym_weak_func) {
842 dlerror();
Dmitriy Ivanovbfa88bc2014-12-16 11:40:46 -0800843 void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW);
Dmitriy Ivanovce441662014-06-17 15:56:38 -0700844 ASSERT_TRUE(handle != NULL);
845
846 int (*weak_func)();
847 weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
848 ASSERT_TRUE(weak_func != NULL) << "dlerror: " << dlerror();
849 EXPECT_EQ(42, weak_func());
850 dlclose(handle);
851}
852
Dmitriy Ivanovbfa88bc2014-12-16 11:40:46 -0800853TEST(dlfcn, dlopen_undefined_weak_func) {
Dmitriy Ivanovcb0443c2015-03-16 14:15:46 -0700854 void* handle = dlopen("libtest_dlopen_weak_undefined_func.so", RTLD_NOW);
855 ASSERT_TRUE(handle != nullptr) << dlerror();
856 int (*weak_func)();
857 weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "use_weak_undefined_func"));
858 ASSERT_TRUE(weak_func != nullptr) << dlerror();
859 EXPECT_EQ(6551, weak_func());
860 dlclose(handle);
Dmitriy Ivanovbfa88bc2014-12-16 11:40:46 -0800861}
862
Dmitriy Ivanov7db18092014-05-08 12:27:25 -0700863TEST(dlfcn, dlopen_symlink) {
864 void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
865 void* handle2 = dlopen("libdlext_test_v2.so", RTLD_NOW);
866 ASSERT_TRUE(handle1 != NULL);
867 ASSERT_TRUE(handle2 != NULL);
868 ASSERT_EQ(handle1, handle2);
Dmitriy Ivanov319356e2014-09-02 17:31:44 -0700869 dlclose(handle1);
870 dlclose(handle2);
Dmitriy Ivanov7db18092014-05-08 12:27:25 -0700871}
Dmitriy Ivanov279a22f2015-01-23 12:03:53 -0800872
873// libtest_dlopen_from_ctor_main.so depends on
874// libtest_dlopen_from_ctor.so which has a constructor
875// that calls dlopen(libc...). This is to test the situation
876// described in b/7941716.
877TEST(dlfcn, dlopen_dlopen_from_ctor) {
878#if defined(__BIONIC__)
879 void* handle = dlopen("libtest_dlopen_from_ctor_main.so", RTLD_NOW);
880 ASSERT_TRUE(handle != nullptr) << dlerror();
881 dlclose(handle);
882#else
883 GTEST_LOG_(INFO) << "This test is disabled for glibc (glibc segfaults if you try to call dlopen from a constructor).\n";
884#endif
885}