dlfcn_test.cpp revision b3356773c6b5fbbbb26d22b3d6c6e0e598840e44
1acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao/*
2acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * Copyright (C) 2012 The Android Open Source Project
3acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao *
4acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * Licensed under the Apache License, Version 2.0 (the "License");
5acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * you may not use this file except in compliance with the License.
6acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * You may obtain a copy of the License at
7acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao *
8acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao *      http://www.apache.org/licenses/LICENSE-2.0
9acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao *
10acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * Unless required by applicable law or agreed to in writing, software
11acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * distributed under the License is distributed on an "AS IS" BASIS,
12acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * See the License for the specific language governing permissions and
14acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao * limitations under the License.
15acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao */
16acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
17acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao#include <gtest/gtest.h>
18acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
19acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao#include <dlfcn.h>
208e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <libgen.h>
218e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <limits.h>
228e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <stdio.h>
238e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <stdint.h>
248e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
25b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov#include "private/ScopeGuard.h"
26b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
278e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <string>
28acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
293b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#define ASSERT_SUBSTR(needle, haystack) \
303b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
313b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
321728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic bool g_called = false;
33acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhaoextern "C" void DlSymTestFunction() {
341728b2396591853345507a063ed6075dfd251706Elliott Hughes  g_called = true;
35acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao}
36acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
37f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovstatic int g_ctor_function_called = 0;
38f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
39f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovextern "C" void ctor_function() __attribute__ ((constructor));
40f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
41f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovextern "C" void ctor_function() {
42f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov  g_ctor_function_called = 17;
43f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov}
44f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
45f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy IvanovTEST(dlfcn, ctor_function_call) {
46f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov  ASSERT_EQ(17, g_ctor_function_called);
47f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov}
48f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
49e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlsym_in_self) {
503b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
51acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void* self = dlopen(NULL, RTLD_NOW);
52acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  ASSERT_TRUE(self != NULL);
533b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
54acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
55acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void* sym = dlsym(self, "DlSymTestFunction");
56acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  ASSERT_TRUE(sym != NULL);
57acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
58acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void (*function)() = reinterpret_cast<void(*)()>(sym);
59acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
601728b2396591853345507a063ed6075dfd251706Elliott Hughes  g_called = false;
61acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  function();
621728b2396591853345507a063ed6075dfd251706Elliott Hughes  ASSERT_TRUE(g_called);
631a6961650c82168864afe040dbdc05977db701dfElliott Hughes
641a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
65acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao}
668e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
67aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy IvanovTEST(dlfcn, dlsym_with_dependencies) {
68aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
69aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  ASSERT_TRUE(handle != NULL);
70aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  dlerror();
71aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  // This symbol is in DT_NEEDED library.
72aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
73aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  ASSERT_TRUE(sym != NULL);
74aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  int (*fn)(void);
75aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
76aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  EXPECT_EQ(4, fn());
77aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  dlclose(handle);
78aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov}
79aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
80b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy IvanovTEST(dlfcn, dlopen_noload) {
81b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
82b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle == NULL);
83b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  handle = dlopen("libtest_simple.so", RTLD_NOW);
84b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
85b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle != NULL);
86b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle2 != NULL);
87b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle == handle2);
88b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
89b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle2));
90b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov}
91b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
929aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov// ifuncs are only supported on intel and arm64 for now
939aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#if defined (__aarch64__) || defined(__i386__) || defined(__x86_64__)
94c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid SmithTEST(dlfcn, ifunc) {
959598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  typedef const char* (*fn_ptr)();
96c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
97c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // ifunc's choice depends on whether IFUNC_CHOICE has a value
98c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // first check the set case
99c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  setenv("IFUNC_CHOICE", "set", 1);
100c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
101c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(handle != NULL);
1029598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
1039598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
104c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(foo_ptr != NULL);
105c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(foo_library_ptr != NULL);
1069598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
1079598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
108c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  dlclose(handle);
109c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
110c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // then check the unset case
111c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  unsetenv("IFUNC_CHOICE");
112c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  handle = dlopen("libtest_ifunc.so", RTLD_NOW);
113c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(handle != NULL);
1149598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
1159598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
116c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(foo_ptr != NULL);
117c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(foo_library_ptr != NULL);
1189598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
1199598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
1209598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  dlclose(handle);
1219598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov}
1229598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov
1239598b8c415e2fa9f240508185fe8c964b83f538dDmitriy IvanovTEST(dlfcn, ifunc_ctor_call) {
1249598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  typedef const char* (*fn_ptr)();
1259598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov
1269598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
1279aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
1289aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  fn_ptr is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
1299aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
1309aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_STREQ("false", is_ctor_called());
1319aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov
1329aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
1339aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
1349598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_STREQ("true", is_ctor_called());
135c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  dlclose(handle);
136c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith}
137c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith#endif
138c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
139b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy IvanovTEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
140b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // This is the structure of the test library and
141b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // its dt_needed libraries
142b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // libtest_relo_check_dt_needed_order.so
143b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // |
144b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // +-> libtest_relo_check_dt_needed_order_1.so
145b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // |
146b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // +-> libtest_relo_check_dt_needed_order_2.so
147b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  //
148b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // The root library references relo_test_get_answer_lib - which is defined
149b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // in both dt_needed libraries, the correct relocation should
150b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // use the function defined in libtest_relo_check_dt_needed_order_1.so
151b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  void* handle = nullptr;
152d9ff7226613014056c9edd79a68dc5af939107a0Dmitriy Ivanov  auto guard = make_scope_guard([&]() {
153b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov    dlclose(handle);
154b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  });
155b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
156b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
157b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
158b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
159b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  typedef int (*fn_t) (void);
160b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
161b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
162b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_EQ(1, fn());
163b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov}
164b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
165cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_dlsym) {
16614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Here is how the test library and its dt_needed
16714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // libraries are arranged
16814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
169cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  libtest_check_order_children.so
17014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
171cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  +-> ..._1_left.so
17214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
173cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |   +-> ..._a.so
17414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
175cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |   +-> ...r_b.so
17614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
177cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  +-> ..._2_right.so
17814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
179cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |   +-> ..._d.so
18014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |       |
181cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |       +-> ..._b.so
18214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
183cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  +-> ..._3_c.so
18414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
18514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  load order should be (1, 2, 3, a, b, d)
18614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
18714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // get_answer() is defined in (2, 3, a, b, c)
18814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // get_answer2() is defined in (b, d)
189cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer");
19014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
191cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL);
192cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
19314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  typedef int (*fn_t) (void);
19414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  fn_t fn, fn2;
195cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"));
196eb27bbae8f0edc6b62ca2db73256c7fb53b9e9bfDmitriy Ivanov  ASSERT_TRUE(fn != NULL) << dlerror();
197cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2"));
198eb27bbae8f0edc6b62ca2db73256c7fb53b9e9bfDmitriy Ivanov  ASSERT_TRUE(fn2 != NULL) << dlerror();
19914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
20014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_EQ(42, fn());
20114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_EQ(43, fn2());
20214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  dlclose(handle);
20314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
20414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
205cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_siblings) {
206cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This is how this one works:
207cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // we lookup and call get_answer which is defined in '_2.so'
208cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so'
209cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // the correct _impl() is implemented by '_a.so';
210cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
211cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?)
212cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
213cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Here is the picture:
214cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
215cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_siblings.so
216cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
217cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._1.so <- empty
218cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
219cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._a.so <- exports correct answer_impl()
220cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
221cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._b.so <- every other letter exporting incorrect one.
222cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
223cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._2.so <- empty
224cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
225cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._c.so
226cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
227cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._d.so
228cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
229cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._3.so <- empty
230cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
231cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._e.so
232cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
233cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._f.so <- exports get_answer() that calls get_anser_impl();
234cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //                     implements incorrect get_answer_impl()
235cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
236cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
237cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
238cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#ifdef __BIONIC__
239cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
240cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
241cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#endif
242cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
243cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
244cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
245cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
246cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
247cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
248cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
249cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
250cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
251cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
252cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
253cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
254cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) {
255cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This test uses the same library as dlopen_check_order_reloc_siblings.
256cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Unlike dlopen_check_order_reloc_siblings it preloads
257cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_siblings_1.so (first dependency) prior to
258cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // dlopen(libtest_check_order_reloc_siblings.so)
259cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
260cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
261cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
262cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD);
263cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
264cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
265cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL);
266cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle_for_1 != nullptr) << dlerror();
267cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
268cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
269cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
270cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
271cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle_for_1));
272cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
273cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
274cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
275cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
276cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
277cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
278cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
279cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
280cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
281cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_nephew) {
282cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This is how this one works:
283cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // we lookup and call nephew_get_answer which is defined in '_2.so'
284cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // and in turn calls external get_answer_impl() defined in '_[a-f].so'
285cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // the correct _impl() is implemented by '_a.so';
286cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
287cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Here is the picture:
288cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
289cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_siblings.so
290cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
291cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._1.so <- empty
292cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
293cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._a.so <- exports correct answer_impl()
294cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
295cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._b.so <- every other letter exporting incorrect one.
296cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
297cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._2.so <- empty
298cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
299cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._c.so
300cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
301cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._d.so
302cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
303cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl();
304cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
305cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._e.so
306cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
307cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._f.so
308cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
309cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
310cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
311cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#ifdef __BIONIC__
312cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
313cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
314cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#endif
315cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
316cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
317cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
318cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
319cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
320cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_nephew_get_answer"));
321cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
322cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
323cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
324cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
325cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
326cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
327cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanovextern "C" int check_order_reloc_root_get_answer_impl() {
328cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  return 42;
329cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
330cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
331cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_main_executable) {
332cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This is how this one works:
333cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // we lookup and call get_answer3 which is defined in 'root.so'
334cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // and in turn calls external root_get_answer_impl() defined in _2.so and
335cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // above the correct _impl() is one in the executable.
336cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
337cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_root.so
338cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
339cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._1.so <- empty
340cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
341cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._2.so <- gives incorrect answer for answer_main_impl()
342cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
343cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
344cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD);
345cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
346cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#ifdef __BIONIC__
347cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
348cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
349cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#endif
350cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
351cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL);
352cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
353cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
354cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
355cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_root_get_answer"));
356cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
357cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
358cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
359cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
360cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
361cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
362e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy IvanovTEST(dlfcn, dlopen_check_rtld_local) {
363e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
364e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
365e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
366e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  // implicit RTLD_LOCAL
367e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW);
368e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
369e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
370e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
371e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(handle, "dlopen_testlib_simple_func");
372e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr);
373e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
374e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  dlclose(handle);
375e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
376e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  // explicit RTLD_LOCAL
377e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL);
378e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
379e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
380e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
381e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(handle, "dlopen_testlib_simple_func");
382e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr);
383e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
384e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  dlclose(handle);
385e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov}
386e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
387e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy IvanovTEST(dlfcn, dlopen_check_rtld_global) {
388e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
389e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
390e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
391e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL);
3921b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
393e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
394e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
395e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
396e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  dlclose(handle);
3971b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
3981b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  // RTLD_GLOBAL implies RTLD_NODELETE, let's check that
3991b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
4001b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(sym, sym_after_dlclose);
401e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov}
402e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
40314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
40414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so ->
40514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop_a.so
40614669a939d113214a4a20b9318fca0992d5453f0Dmitriy IvanovTEST(dlfcn, dlopen_check_loop) {
40714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW);
408eb27bbae8f0edc6b62ca2db73256c7fb53b9e9bfDmitriy Ivanov#if defined(__BIONIC__)
409a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
41014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_STREQ("dlopen failed: recursive link to \"libtest_with_dependency_loop_a.so\"", dlerror());
411a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov  // This symbol should never be exposed
412a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov  void* f = dlsym(RTLD_DEFAULT, "dlopen_test_invalid_function");
413a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov  ASSERT_TRUE(f == nullptr);
414a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: dlopen_test_invalid_function", dlerror());
415a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov
416a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov  // dlopen second time to make sure that the library wasn't loaded even though dlopen returned null.
417a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov  // This may happen if during cleanup the root library or one of the depended libs were not removed
418a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov  // from soinfo list.
419a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov  handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
420a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
421a6ac54a215d6b64f5cc5a59b66c1dbfbb41ea9f5Dmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
422eb27bbae8f0edc6b62ca2db73256c7fb53b9e9bfDmitriy Ivanov#else // glibc allows recursive links
423eb27bbae8f0edc6b62ca2db73256c7fb53b9e9bfDmitriy Ivanov  ASSERT_TRUE(handle != nullptr);
424eb27bbae8f0edc6b62ca2db73256c7fb53b9e9bfDmitriy Ivanov  dlclose(handle);
425eb27bbae8f0edc6b62ca2db73256c7fb53b9e9bfDmitriy Ivanov#endif
42614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
42714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
4281b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy IvanovTEST(dlfcn, dlopen_nodelete) {
4291b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  static bool is_unloaded = false;
4301b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4311b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE);
4321b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
4331b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void (*set_unload_flag_ptr)(bool*);
4341b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr"));
4351b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
4361b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr(&is_unloaded);
4371b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4381b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
4391b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
4401b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(1729U, *taxicab_number);
4411b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  *taxicab_number = 2;
4421b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4431b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
4441b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(!is_unloaded);
4451b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4461b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number_after_dlclose = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
4471b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number);
4481b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(2U, *taxicab_number_after_dlclose);
4491b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4501b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4511b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  handle = dlopen("libtest_nodelete_1.so", RTLD_NOW);
4521b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number2 = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
4531b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(taxicab_number2, taxicab_number);
4541b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4551b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(2U, *taxicab_number2);
4561b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4571b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
4581b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(!is_unloaded);
4591b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
4601b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4611b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy IvanovTEST(dlfcn, dlopen_nodelete_on_second_dlopen) {
4621b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  static bool is_unloaded = false;
4631b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4641b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW);
4651b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
4661b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void (*set_unload_flag_ptr)(bool*);
4671b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr"));
4681b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
4691b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr(&is_unloaded);
4701b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4711b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_2_taxicab_number"));
4721b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
4731b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4741b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(1729U, *taxicab_number);
4751b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  *taxicab_number = 2;
4761b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4771b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  // This RTLD_NODELETE should be ignored
4781b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE);
4791b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle1 != nullptr) << dlerror();
4801b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(handle, handle1);
4811b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4821b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle1);
4831b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
4841b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4851b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(is_unloaded);
4861b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
4871b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4881b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy IvanovTEST(dlfcn, dlopen_nodelete_dt_flags_1) {
4891b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  static bool is_unloaded = false;
4901b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4911b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW);
4921b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
4931b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void (*set_unload_flag_ptr)(bool*);
4941b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr"));
4951b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
4961b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr(&is_unloaded);
4971b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4981b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
4991b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(!is_unloaded);
5001b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
5011b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
502d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy IvanovTEST(dlfcn, dlsym_df_1_global) {
5034e446b19d8710cd2004785db4a00f18f249fe73fDmitriy Ivanov#if !defined(__arm__) && !defined(__aarch64__)
504d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW);
505d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
506d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  int (*get_answer)();
507d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  get_answer = reinterpret_cast<int (*)()>(dlsym(handle, "dl_df_1_global_get_answer"));
508d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_TRUE(get_answer != nullptr) << dlerror();
509d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_EQ(42, get_answer());
510d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
511d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov#else
5124e446b19d8710cd2004785db4a00f18f249fe73fDmitriy Ivanov  GTEST_LOG_(INFO) << "This test does nothing on arm/arm64 (to be reenabled once b/18137520 or b/18130452 are fixed).\n";
513d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov#endif
514d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov}
515d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
516e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_failure) {
5173b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* self = dlopen("/does/not/exist", RTLD_NOW);
5183b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(self == NULL);
519063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__BIONIC__)
5203b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
5213b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#else
5223b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
5233b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
5243b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
5253b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
526ad88a0863110798cef5169dcf917e18b967a7cf6Elliott Hughesstatic void* ConcurrentDlErrorFn(void*) {
5275419b9474753d25dff947c7740532f86d130c0beElliott Hughes  dlopen("/child/thread", RTLD_NOW);
5285419b9474753d25dff947c7740532f86d130c0beElliott Hughes  return reinterpret_cast<void*>(strdup(dlerror()));
5295419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
5305419b9474753d25dff947c7740532f86d130c0beElliott Hughes
531e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlerror_concurrent) {
5325419b9474753d25dff947c7740532f86d130c0beElliott Hughes  dlopen("/main/thread", RTLD_NOW);
5335419b9474753d25dff947c7740532f86d130c0beElliott Hughes  const char* main_thread_error = dlerror();
5345419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/main/thread", main_thread_error);
5355419b9474753d25dff947c7740532f86d130c0beElliott Hughes
5365419b9474753d25dff947c7740532f86d130c0beElliott Hughes  pthread_t t;
5375419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentDlErrorFn, NULL));
5385419b9474753d25dff947c7740532f86d130c0beElliott Hughes  void* result;
5395419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_EQ(0, pthread_join(t, &result));
5405419b9474753d25dff947c7740532f86d130c0beElliott Hughes  char* child_thread_error = static_cast<char*>(result);
5415419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/child/thread", child_thread_error);
5425419b9474753d25dff947c7740532f86d130c0beElliott Hughes  free(child_thread_error);
5435419b9474753d25dff947c7740532f86d130c0beElliott Hughes
5445419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/main/thread", main_thread_error);
5455419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
5465419b9474753d25dff947c7740532f86d130c0beElliott Hughes
547e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlsym_failures) {
5483b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
5493b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* self = dlopen(NULL, RTLD_NOW);
5503b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(self != NULL);
5513b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
5523b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
5533b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* sym;
5543b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
55544adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov#if defined(__BIONIC__) && !defined(__LP64__)
55644adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov  // RTLD_DEFAULT in lp32 bionic is not (void*)0
55744adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov  // so it can be distinguished from the NULL handle.
5583b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(NULL, "test");
5593b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
5603b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("dlsym library handle is null", dlerror());
5613b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
5623b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
5633b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // NULL symbol name.
564063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__BIONIC__)
5653b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // glibc marks this parameter non-null and SEGVs if you cheat.
5663b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(self, NULL);
5673b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
5683b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("", dlerror());
5693b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
5703b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
5713b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // Symbol that doesn't exist.
5723b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(self, "ThisSymbolDoesNotExist");
5733b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
5743b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
5751a6961650c82168864afe040dbdc05977db701dfElliott Hughes
5761a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
5773b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
5783b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
579e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dladdr) {
5803b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
5818e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* self = dlopen(NULL, RTLD_NOW);
5828e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(self != NULL);
5833b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
5848e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
5858e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* sym = dlsym(self, "DlSymTestFunction");
5868e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(sym != NULL);
5878e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
5888e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
5898e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
5908e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
5918e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  Dl_info info;
5928e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  int rc = dladdr(addr, &info);
5938e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
5948e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
5958e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Get the name of this executable.
5968e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  char executable_path[PATH_MAX];
5978e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  rc = readlink("/proc/self/exe", executable_path, sizeof(executable_path));
5988e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_NE(rc, -1);
5998e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  executable_path[rc] = '\0';
6008e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  std::string executable_name(basename(executable_path));
6018e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
6028e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The filename should be that of this executable.
6038e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Note that we don't know whether or not we have the full path, so we want an "ends_with" test.
6048e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  std::string dli_fname(info.dli_fname);
6058e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  dli_fname = basename(&dli_fname[0]);
6068e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dli_fname, executable_name);
6078e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
6088e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The symbol name should be the symbol we looked up.
6098e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_STREQ(info.dli_sname, "DlSymTestFunction");
6108e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
6118e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The address should be the exact address of the symbol.
6128e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(info.dli_saddr, sym);
6138e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
6148e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Look in /proc/pid/maps to find out what address we were loaded at.
6158e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // TODO: factor /proc/pid/maps parsing out into a class and reuse all over bionic.
6168e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* base_address = NULL;
6178e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  char line[BUFSIZ];
61857b7a6110e7e8b446fc23cce4765ff625ee0a105Elliott Hughes  FILE* fp = fopen("/proc/self/maps", "r");
6198e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(fp != NULL);
6208e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  while (fgets(line, sizeof(line), fp) != NULL) {
6218e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    uintptr_t start = strtoul(line, 0, 16);
6228e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    line[strlen(line) - 1] = '\0'; // Chomp the '\n'.
6238e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    char* path = strchr(line, '/');
624156da966214957c5616a0b83cc84686eedfc4e31Elliott Hughes    if (path != NULL && strcmp(executable_path, path) == 0) {
6258e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes      base_address = reinterpret_cast<void*>(start);
6268e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes      break;
6278e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    }
6288e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  }
6298e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  fclose(fp);
6308e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
6318e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The base address should be the address we were loaded at.
6328e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(info.dli_fbase, base_address);
6331a6961650c82168864afe040dbdc05977db701dfElliott Hughes
6341a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
6358e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes}
6368e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
637e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dladdr_invalid) {
6388e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  Dl_info info;
6398e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
6403b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
6413b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
6428e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // No symbol corresponding to NULL.
6438e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success.
6443b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
6458e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
6468e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // No symbol corresponding to a stack address.
6478e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
6483b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
6498e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes}
650124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes
651a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes// GNU-style ELF hash tables are incompatible with the MIPS ABI.
652a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes// MIPS requires .dynsym to be sorted to match the GOT but GNU-style requires sorting by hash code.
653e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_library_with_only_gnu_hash) {
654ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov#if !defined(__mips__)
655124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  dlerror(); // Clear any pending errors.
656ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  void* handle = dlopen("libgnu-hash-table-library.so", RTLD_NOW);
657ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
658ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  auto guard = make_scope_guard([&]() {
659ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    dlclose(handle);
660ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  });
661ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
662ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
663ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  int (*fn)(void);
664ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
665ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  EXPECT_EQ(4, fn());
666ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
667ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  Dl_info dlinfo;
668ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
669ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
670ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(fn == dlinfo.dli_saddr);
671ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
672b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_SUBSTR("libgnu-hash-table-library.so", dlinfo.dli_fname);
673ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov#else
674ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  GTEST_LOG_(INFO) << "This test does nothing for mips/mips64; mips toolchain does not support '--hash-style=gnu'\n";
675a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes#endif
676ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
677e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
678b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy IvanovTEST(dlfcn, dlopen_library_with_only_sysv_hash) {
679b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  void* handle = dlopen("libsysv-hash-table-library.so", RTLD_NOW);
680b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
681b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  auto guard = make_scope_guard([&]() {
682b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov    dlclose(handle);
683b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  });
684b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
685b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
686b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  int (*fn)(void);
687b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
688b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  EXPECT_EQ(4, fn());
689b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov
690b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  Dl_info dlinfo;
691b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
692b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov
693b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(fn == dlinfo.dli_saddr);
694b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
695b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_SUBSTR("libsysv-hash-table-library.so", dlinfo.dli_fname);
696b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov}
697b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov
698e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_bad_flags) {
699e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  dlerror(); // Clear any pending errors.
700e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  void* handle;
701e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
702063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__GLIBC__)
703e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
704e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  handle = dlopen(NULL, 0);
705e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_TRUE(handle == NULL);
706e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR("invalid", dlerror());
707e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes#endif
708e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
709e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  handle = dlopen(NULL, 0xffffffff);
710e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_TRUE(handle == NULL);
711e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR("invalid", dlerror());
712e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
713e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
714e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  handle = dlopen(NULL, RTLD_NOW|RTLD_LAZY);
715e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_TRUE(handle != NULL);
716e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR(NULL, dlerror());
717e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes}
718ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
719ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey MelnikovTEST(dlfcn, rtld_default_unknown_symbol) {
7202ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
721ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov  ASSERT_TRUE(addr == NULL);
722ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov}
723ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
724ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey MelnikovTEST(dlfcn, rtld_default_known_symbol) {
7252ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_DEFAULT, "fopen");
7262ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  ASSERT_TRUE(addr != NULL);
7272ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes}
7282ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes
7292ed710976cb0ace31aab565c95a42d4e75623894Elliott HughesTEST(dlfcn, rtld_next_unknown_symbol) {
7302ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
7312ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  ASSERT_TRUE(addr == NULL);
7322ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes}
7332ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes
7342ed710976cb0ace31aab565c95a42d4e75623894Elliott HughesTEST(dlfcn, rtld_next_known_symbol) {
7352ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_NEXT, "fopen");
736ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov  ASSERT_TRUE(addr != NULL);
737ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov}
7387db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov
739ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy IvanovTEST(dlfcn, dlsym_weak_func) {
740ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  dlerror();
741ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_weak_func.so",RTLD_NOW);
742ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  ASSERT_TRUE(handle != NULL);
743ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov
744ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  int (*weak_func)();
745ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
746ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  ASSERT_TRUE(weak_func != NULL) << "dlerror: " << dlerror();
747ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  EXPECT_EQ(42, weak_func());
748ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  dlclose(handle);
749ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov}
750ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov
7517db180919c335287b201e859faa8ee0dbe281cdeDmitriy IvanovTEST(dlfcn, dlopen_symlink) {
7527db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
7537db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  void* handle2 = dlopen("libdlext_test_v2.so", RTLD_NOW);
7547db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_TRUE(handle1 != NULL);
7557db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_TRUE(handle2 != NULL);
7567db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_EQ(handle1, handle2);
757319356e39cc91b4eb94b1974756f1cfc0a137351Dmitriy Ivanov  dlclose(handle1);
758319356e39cc91b4eb94b1974756f1cfc0a137351Dmitriy Ivanov  dlclose(handle2);
7597db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov}
760