dlfcn_test.cpp revision 279a22f96e639e76c801bdb39aee5576f2280fe0
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
25ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov#include "gtest_ex.h"
26b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov#include "private/ScopeGuard.h"
27b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
288e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <string>
29acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
303b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#define ASSERT_SUBSTR(needle, haystack) \
313b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
323b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
331728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic bool g_called = false;
34acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhaoextern "C" void DlSymTestFunction() {
351728b2396591853345507a063ed6075dfd251706Elliott Hughes  g_called = true;
36acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao}
37acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
38f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovstatic int g_ctor_function_called = 0;
39f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
40f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovextern "C" void ctor_function() __attribute__ ((constructor));
41f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
42f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovextern "C" void ctor_function() {
43f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov  g_ctor_function_called = 17;
44f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov}
45f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
46f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy IvanovTEST(dlfcn, ctor_function_call) {
47f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov  ASSERT_EQ(17, g_ctor_function_called);
48f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov}
49f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
50e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlsym_in_self) {
513b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
52acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void* self = dlopen(NULL, RTLD_NOW);
53acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  ASSERT_TRUE(self != NULL);
543b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
55acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
56acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void* sym = dlsym(self, "DlSymTestFunction");
57acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  ASSERT_TRUE(sym != NULL);
58acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
59acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void (*function)() = reinterpret_cast<void(*)()>(sym);
60acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
611728b2396591853345507a063ed6075dfd251706Elliott Hughes  g_called = false;
62acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  function();
631728b2396591853345507a063ed6075dfd251706Elliott Hughes  ASSERT_TRUE(g_called);
641a6961650c82168864afe040dbdc05977db701dfElliott Hughes
651a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
66acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao}
678e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
68aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy IvanovTEST(dlfcn, dlsym_with_dependencies) {
69aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
70aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  ASSERT_TRUE(handle != NULL);
71aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  dlerror();
72aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  // This symbol is in DT_NEEDED library.
73aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
74aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  ASSERT_TRUE(sym != NULL);
75aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  int (*fn)(void);
76aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
77aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  EXPECT_EQ(4, fn());
78aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  dlclose(handle);
79aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov}
80aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
81b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy IvanovTEST(dlfcn, dlopen_noload) {
82b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
83b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle == NULL);
84b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  handle = dlopen("libtest_simple.so", RTLD_NOW);
85b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
86b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle != NULL);
87b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle2 != NULL);
88b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle == handle2);
89b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
90b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle2));
91b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov}
92b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
939aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov// ifuncs are only supported on intel and arm64 for now
949aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#if defined (__aarch64__) || defined(__i386__) || defined(__x86_64__)
95c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid SmithTEST(dlfcn, ifunc) {
969598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  typedef const char* (*fn_ptr)();
97c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
98c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // ifunc's choice depends on whether IFUNC_CHOICE has a value
99c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // first check the set case
100c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  setenv("IFUNC_CHOICE", "set", 1);
101c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
102c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(handle != NULL);
1039598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
1049598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
105c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(foo_ptr != NULL);
106c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(foo_library_ptr != NULL);
1079598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
1089598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
109c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  dlclose(handle);
110c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
111c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // then check the unset case
112c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  unsetenv("IFUNC_CHOICE");
113c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  handle = dlopen("libtest_ifunc.so", RTLD_NOW);
114c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(handle != NULL);
1159598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
1169598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
117c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(foo_ptr != NULL);
118c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(foo_library_ptr != NULL);
1199598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
1209598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
1219598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  dlclose(handle);
1229598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov}
1239598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov
1249598b8c415e2fa9f240508185fe8c964b83f538dDmitriy IvanovTEST(dlfcn, ifunc_ctor_call) {
1259598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  typedef const char* (*fn_ptr)();
1269598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov
1279598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
1289aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
1299aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  fn_ptr is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
1309aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
1319aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_STREQ("false", is_ctor_called());
1329aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov
1339aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
1349aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
1359598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_STREQ("true", is_ctor_called());
136c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  dlclose(handle);
137c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith}
138c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith#endif
139c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
140b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy IvanovTEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
141b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // This is the structure of the test library and
142b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // its dt_needed libraries
143b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // libtest_relo_check_dt_needed_order.so
144b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // |
145b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // +-> libtest_relo_check_dt_needed_order_1.so
146b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // |
147b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // +-> libtest_relo_check_dt_needed_order_2.so
148b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  //
149b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // The root library references relo_test_get_answer_lib - which is defined
150b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // in both dt_needed libraries, the correct relocation should
151b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // use the function defined in libtest_relo_check_dt_needed_order_1.so
152b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  void* handle = nullptr;
153d9ff7226613014056c9edd79a68dc5af939107a0Dmitriy Ivanov  auto guard = make_scope_guard([&]() {
154b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov    dlclose(handle);
155b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  });
156b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
157b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
158b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
159b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
160b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  typedef int (*fn_t) (void);
161b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
162b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
163b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_EQ(1, fn());
164b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov}
165b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
166cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_dlsym) {
16714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Here is how the test library and its dt_needed
16814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // libraries are arranged
16914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
170cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  libtest_check_order_children.so
17114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
172cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  +-> ..._1_left.so
17314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
174cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |   +-> ..._a.so
17514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
176cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |   +-> ...r_b.so
17714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
178cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  +-> ..._2_right.so
17914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
180cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |   +-> ..._d.so
18114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |       |
182cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |       +-> ..._b.so
18314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
184cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  +-> ..._3_c.so
18514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
18614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  load order should be (1, 2, 3, a, b, d)
18714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
18814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // get_answer() is defined in (2, 3, a, b, c)
18914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // get_answer2() is defined in (b, d)
190cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer");
19114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
192cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL);
193cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
19414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  typedef int (*fn_t) (void);
19514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  fn_t fn, fn2;
196cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"));
197eb27bbae8f0edc6b62ca2db73256c7fb53b9e9bfDmitriy Ivanov  ASSERT_TRUE(fn != NULL) << dlerror();
198cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2"));
199eb27bbae8f0edc6b62ca2db73256c7fb53b9e9bfDmitriy Ivanov  ASSERT_TRUE(fn2 != NULL) << dlerror();
20014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
20114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_EQ(42, fn());
20214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_EQ(43, fn2());
20314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  dlclose(handle);
20414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
20514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
206cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_siblings) {
207cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This is how this one works:
208cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // we lookup and call get_answer which is defined in '_2.so'
209cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so'
210cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // the correct _impl() is implemented by '_a.so';
211cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
212cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?)
213cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
214cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Here is the picture:
215cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
216cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_siblings.so
217cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
218cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._1.so <- empty
219cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
220cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._a.so <- exports correct answer_impl()
221cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
222cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._b.so <- every other letter exporting incorrect one.
223cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
224cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._2.so <- empty
225cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
226cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._c.so
227cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
228cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._d.so
229cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
230cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._3.so <- empty
231cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
232cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._e.so
233cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
234cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._f.so <- exports get_answer() that calls get_anser_impl();
235cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //                     implements incorrect get_answer_impl()
236cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
237cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
238cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
239cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#ifdef __BIONIC__
240cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
241cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
242cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#endif
243cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
244cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
245cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
246cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
247cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
248cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
249cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
250cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
251cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
252cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
253cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
254cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
255cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) {
256cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This test uses the same library as dlopen_check_order_reloc_siblings.
257cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Unlike dlopen_check_order_reloc_siblings it preloads
258cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_siblings_1.so (first dependency) prior to
259cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // dlopen(libtest_check_order_reloc_siblings.so)
260cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
261cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
262cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
263cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD);
264cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
265cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
266cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL);
267cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle_for_1 != nullptr) << dlerror();
268cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
269cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
270cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
271cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
272cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle_for_1));
273cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
274cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
275cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
276cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
277cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
278cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
279cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
280cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
281cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
2827699d13a74769fe8063fcca95588c87c571226c0Dmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_grandchild) {
2837699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // This is how this one works:
2847699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // we lookup and call grandchild_get_answer which is defined in '_2.so'
2857699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // and in turn calls external get_answer_impl() defined in '_c_1.so and _c_2.so'
2867699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // the correct _impl() is implemented by '_c_1.so';
2877699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //
2887699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // Here is the picture of subtree:
2897699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //
2907699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // libtest_check_order_reloc_siblings.so
2917699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // |
2927699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // +-> ..._2.so <- grandchild_get_answer()
2937699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |
2947699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     +-> ..._c.so <- empty
2957699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |   |
2967699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |   +-> _c_1.so <- exports correct answer_impl()
2977699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |   |
2987699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |   +-> _c_2.so <- exports incorrect answer_impl()
2997699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |
3007699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     +-> ..._d.so <- empty
3017699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
3027699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
3037699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
3047699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov#ifdef __BIONIC__
3057699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
3067699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
3077699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov#endif
3087699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
3097699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
3107699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
3117699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
3127699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  typedef int (*fn_t) (void);
3137699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_grandchild_get_answer"));
3147699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
3157699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_EQ(42, fn());
3167699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
3177699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
3187699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov}
3197699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
320cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_nephew) {
321cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This is how this one works:
322cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // we lookup and call nephew_get_answer which is defined in '_2.so'
323cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // and in turn calls external get_answer_impl() defined in '_[a-f].so'
324cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // the correct _impl() is implemented by '_a.so';
325cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
326cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Here is the picture:
327cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
328cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_siblings.so
329cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
330cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._1.so <- empty
331cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
332cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._a.so <- exports correct answer_impl()
333cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
334cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._b.so <- every other letter exporting incorrect one.
335cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
336cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._2.so <- empty
337cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
338cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._c.so
339cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
340cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._d.so
341cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
342cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl();
343cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
344cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._e.so
345cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
346cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._f.so
347cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
348cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
349cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
350cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#ifdef __BIONIC__
351cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
352cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
353cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#endif
354cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
355cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
356cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
357cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
358cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
359cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_nephew_get_answer"));
360cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
361cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
362cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
363cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
364cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
365cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
366ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy IvanovTEST(dlfcn, check_unload_after_reloc) {
367ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // This is how this one works:
368ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // libtest_two_parents_parent1 <- answer_impl() used by libtest_two_parents_child
369ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // |
370ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // +-> libtest_two_parents_child
371ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  //
372ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // libtest_two_parents_parent2 <- answer_impl() not used by libtest_two_parents_child
373ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // |
374ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // +-> libtest_two_parents_child
375ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  //
376ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // Test dlopens parent1 which loads and relocates libtest_two_parents_child.so
377ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // as a second step it dlopens parent2 and dlcloses parent1...
378ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
379ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  test_isolated([] {
380ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    void* handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL);
381ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_TRUE(handle != nullptr) << dlerror();
382ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
383ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    void* handle2 = dlopen("libtest_two_parents_parent2.so", RTLD_NOW | RTLD_LOCAL);
384ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_TRUE(handle2 != nullptr) << dlerror();
385ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
386ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    typedef int (*fn_t) (void);
387ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    fn_t fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
388ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_TRUE(fn != nullptr) << dlerror();
389ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_EQ(42, fn());
390ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
391ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_EQ(0, dlclose(handle));
392ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
393ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
394ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_TRUE(handle != nullptr);
395ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_EQ(0, dlclose(handle));
396ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
397ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
398ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_TRUE(fn != nullptr) << dlerror();
399ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_EQ(42, fn());
400ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
401ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_EQ(0, dlclose(handle2));
402ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
403ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
404ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_TRUE(handle == nullptr);
405ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  });
406ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
407ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
408cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanovextern "C" int check_order_reloc_root_get_answer_impl() {
409cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  return 42;
410cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
411cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
412cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_main_executable) {
413cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This is how this one works:
414cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // we lookup and call get_answer3 which is defined in 'root.so'
415cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // and in turn calls external root_get_answer_impl() defined in _2.so and
416cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // above the correct _impl() is one in the executable.
417cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
418cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_root.so
419cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
420cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._1.so <- empty
421cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
422cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._2.so <- gives incorrect answer for answer_main_impl()
423cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
424cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
425cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD);
426cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
427cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#ifdef __BIONIC__
428cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
429cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
430cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#endif
431cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
432cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL);
433cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
434cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
435cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
436cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_root_get_answer"));
437cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
438cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
439cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
440cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
441cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
442cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
443e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy IvanovTEST(dlfcn, dlopen_check_rtld_local) {
444e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
445e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
446e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
447e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  // implicit RTLD_LOCAL
448e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW);
449e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
450e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
451e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
452e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(handle, "dlopen_testlib_simple_func");
453e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr);
454e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
455e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  dlclose(handle);
456e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
457e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  // explicit RTLD_LOCAL
458e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL);
459e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
460e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
461e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
462e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(handle, "dlopen_testlib_simple_func");
463e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr);
464e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
465e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  dlclose(handle);
466e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov}
467e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
468e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy IvanovTEST(dlfcn, dlopen_check_rtld_global) {
469e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
470e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
471e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
472e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL);
4731b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
474e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
475e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
476e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
477e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  dlclose(handle);
4781b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
4791b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  // RTLD_GLOBAL implies RTLD_NODELETE, let's check that
4801b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
4811b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(sym, sym_after_dlclose);
482e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov}
483e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
48414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
48514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so ->
48614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop_a.so
48714669a939d113214a4a20b9318fca0992d5453f0Dmitriy IvanovTEST(dlfcn, dlopen_check_loop) {
488ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  test_isolated([] {
489ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW);
490ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_TRUE(handle != nullptr) << dlerror();
491ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    void* f = dlsym(handle, "dlopen_test_loopy_function");
492ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_TRUE(f != nullptr) << dlerror();
493ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    EXPECT_TRUE(reinterpret_cast<bool (*)(void)>(f)());
494ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_EQ(0, dlclose(handle));
495ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
496ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    // dlopen second time to make sure that the library was unloaded correctly
497ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
498ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_TRUE(handle == nullptr);
499ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov#ifdef __BIONIC__
500ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    // TODO: glibc returns nullptr on dlerror() here. Is it bug?
501ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
502eb27bbae8f0edc6b62ca2db73256c7fb53b9e9bfDmitriy Ivanov#endif
503ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
504ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    handle = dlopen("libtest_with_dependency_a.so", RTLD_NOW | RTLD_NOLOAD);
505ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov    ASSERT_TRUE(handle == nullptr);
506ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  });
50714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
50814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
5091b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy IvanovTEST(dlfcn, dlopen_nodelete) {
5101b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  static bool is_unloaded = false;
5111b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5121b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE);
5131b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
5141b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void (*set_unload_flag_ptr)(bool*);
5151b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr"));
5161b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
5171b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr(&is_unloaded);
5181b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5191b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
5201b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
5211b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(1729U, *taxicab_number);
5221b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  *taxicab_number = 2;
5231b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5241b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
5251b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(!is_unloaded);
5261b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5271b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number_after_dlclose = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
5281b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number);
5291b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(2U, *taxicab_number_after_dlclose);
5301b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5311b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5321b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  handle = dlopen("libtest_nodelete_1.so", RTLD_NOW);
5331b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number2 = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
5341b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(taxicab_number2, taxicab_number);
5351b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5361b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(2U, *taxicab_number2);
5371b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5381b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
5391b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(!is_unloaded);
5401b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
5411b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5421b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy IvanovTEST(dlfcn, dlopen_nodelete_on_second_dlopen) {
5431b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  static bool is_unloaded = false;
5441b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5451b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW);
5461b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
5471b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void (*set_unload_flag_ptr)(bool*);
5481b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr"));
5491b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
5501b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr(&is_unloaded);
5511b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5521b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_2_taxicab_number"));
5531b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
5541b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5551b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(1729U, *taxicab_number);
5561b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  *taxicab_number = 2;
5571b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5581b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  // This RTLD_NODELETE should be ignored
5591b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE);
5601b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle1 != nullptr) << dlerror();
5611b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(handle, handle1);
5621b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5631b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle1);
5641b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
5651b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5661b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(is_unloaded);
5671b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
5681b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5691b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy IvanovTEST(dlfcn, dlopen_nodelete_dt_flags_1) {
5701b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  static bool is_unloaded = false;
5711b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5721b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW);
5731b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
5741b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void (*set_unload_flag_ptr)(bool*);
5751b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr"));
5761b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
5771b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr(&is_unloaded);
5781b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5791b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
5801b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(!is_unloaded);
5811b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
5821b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
583d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy IvanovTEST(dlfcn, dlsym_df_1_global) {
5844e446b19d8710cd2004785db4a00f18f249fe73fDmitriy Ivanov#if !defined(__arm__) && !defined(__aarch64__)
585d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW);
586d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
587d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  int (*get_answer)();
588d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  get_answer = reinterpret_cast<int (*)()>(dlsym(handle, "dl_df_1_global_get_answer"));
589d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_TRUE(get_answer != nullptr) << dlerror();
590d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_EQ(42, get_answer());
591d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
592d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov#else
5934e446b19d8710cd2004785db4a00f18f249fe73fDmitriy Ivanov  GTEST_LOG_(INFO) << "This test does nothing on arm/arm64 (to be reenabled once b/18137520 or b/18130452 are fixed).\n";
594d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov#endif
595d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov}
596d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
597e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_failure) {
5983b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* self = dlopen("/does/not/exist", RTLD_NOW);
5993b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(self == NULL);
600063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__BIONIC__)
6013b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
6023b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#else
6033b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
6043b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
6053b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
6063b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
607ad88a0863110798cef5169dcf917e18b967a7cf6Elliott Hughesstatic void* ConcurrentDlErrorFn(void*) {
6085419b9474753d25dff947c7740532f86d130c0beElliott Hughes  dlopen("/child/thread", RTLD_NOW);
6095419b9474753d25dff947c7740532f86d130c0beElliott Hughes  return reinterpret_cast<void*>(strdup(dlerror()));
6105419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
6115419b9474753d25dff947c7740532f86d130c0beElliott Hughes
612e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlerror_concurrent) {
6135419b9474753d25dff947c7740532f86d130c0beElliott Hughes  dlopen("/main/thread", RTLD_NOW);
6145419b9474753d25dff947c7740532f86d130c0beElliott Hughes  const char* main_thread_error = dlerror();
6155419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/main/thread", main_thread_error);
6165419b9474753d25dff947c7740532f86d130c0beElliott Hughes
6175419b9474753d25dff947c7740532f86d130c0beElliott Hughes  pthread_t t;
6185419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentDlErrorFn, NULL));
6195419b9474753d25dff947c7740532f86d130c0beElliott Hughes  void* result;
6205419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_EQ(0, pthread_join(t, &result));
6215419b9474753d25dff947c7740532f86d130c0beElliott Hughes  char* child_thread_error = static_cast<char*>(result);
6225419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/child/thread", child_thread_error);
6235419b9474753d25dff947c7740532f86d130c0beElliott Hughes  free(child_thread_error);
6245419b9474753d25dff947c7740532f86d130c0beElliott Hughes
6255419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/main/thread", main_thread_error);
6265419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
6275419b9474753d25dff947c7740532f86d130c0beElliott Hughes
628e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlsym_failures) {
6293b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
6303b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* self = dlopen(NULL, RTLD_NOW);
6313b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(self != NULL);
6323b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
6333b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
6343b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* sym;
6353b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
63644adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov#if defined(__BIONIC__) && !defined(__LP64__)
63744adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov  // RTLD_DEFAULT in lp32 bionic is not (void*)0
63844adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov  // so it can be distinguished from the NULL handle.
6393b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(NULL, "test");
6403b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
6413b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("dlsym library handle is null", dlerror());
6423b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
6433b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
6443b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // NULL symbol name.
645063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__BIONIC__)
6463b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // glibc marks this parameter non-null and SEGVs if you cheat.
6473b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(self, NULL);
6483b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
6493b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("", dlerror());
6503b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
6513b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
6523b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // Symbol that doesn't exist.
6533b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(self, "ThisSymbolDoesNotExist");
6543b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
6553b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
6561a6961650c82168864afe040dbdc05977db701dfElliott Hughes
6571a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
6583b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
6593b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
660e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dladdr) {
6613b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
6628e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* self = dlopen(NULL, RTLD_NOW);
6638e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(self != NULL);
6643b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
6658e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
6668e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* sym = dlsym(self, "DlSymTestFunction");
6678e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(sym != NULL);
6688e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
6698e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
6708e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
6718e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
6728e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  Dl_info info;
6738e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  int rc = dladdr(addr, &info);
6748e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
6758e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
6768e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Get the name of this executable.
6778e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  char executable_path[PATH_MAX];
6788e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  rc = readlink("/proc/self/exe", executable_path, sizeof(executable_path));
6798e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_NE(rc, -1);
6808e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  executable_path[rc] = '\0';
6818e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  std::string executable_name(basename(executable_path));
6828e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
6838e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The filename should be that of this executable.
6848e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Note that we don't know whether or not we have the full path, so we want an "ends_with" test.
6858e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  std::string dli_fname(info.dli_fname);
6868e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  dli_fname = basename(&dli_fname[0]);
6878e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dli_fname, executable_name);
6888e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
6898e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The symbol name should be the symbol we looked up.
6908e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_STREQ(info.dli_sname, "DlSymTestFunction");
6918e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
6928e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The address should be the exact address of the symbol.
6938e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(info.dli_saddr, sym);
6948e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
6958e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Look in /proc/pid/maps to find out what address we were loaded at.
6968e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // TODO: factor /proc/pid/maps parsing out into a class and reuse all over bionic.
6978e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* base_address = NULL;
6988e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  char line[BUFSIZ];
69957b7a6110e7e8b446fc23cce4765ff625ee0a105Elliott Hughes  FILE* fp = fopen("/proc/self/maps", "r");
7008e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(fp != NULL);
7018e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  while (fgets(line, sizeof(line), fp) != NULL) {
7028e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    uintptr_t start = strtoul(line, 0, 16);
7038e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    line[strlen(line) - 1] = '\0'; // Chomp the '\n'.
7048e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    char* path = strchr(line, '/');
705156da966214957c5616a0b83cc84686eedfc4e31Elliott Hughes    if (path != NULL && strcmp(executable_path, path) == 0) {
7068e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes      base_address = reinterpret_cast<void*>(start);
7078e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes      break;
7088e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    }
7098e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  }
7108e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  fclose(fp);
7118e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
7128e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The base address should be the address we were loaded at.
7138e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(info.dli_fbase, base_address);
7141a6961650c82168864afe040dbdc05977db701dfElliott Hughes
7151a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
7168e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes}
7178e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
718e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dladdr_invalid) {
7198e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  Dl_info info;
7208e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
7213b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
7223b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
7238e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // No symbol corresponding to NULL.
7248e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success.
7253b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
7268e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
7278e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // No symbol corresponding to a stack address.
7288e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
7293b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
7308e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes}
731124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes
732a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes// GNU-style ELF hash tables are incompatible with the MIPS ABI.
733a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes// MIPS requires .dynsym to be sorted to match the GOT but GNU-style requires sorting by hash code.
734e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_library_with_only_gnu_hash) {
735ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov#if !defined(__mips__)
736124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  dlerror(); // Clear any pending errors.
737ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  void* handle = dlopen("libgnu-hash-table-library.so", RTLD_NOW);
738ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
739ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  auto guard = make_scope_guard([&]() {
740ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    dlclose(handle);
741ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  });
742ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
743ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
744ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  int (*fn)(void);
745ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
746ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  EXPECT_EQ(4, fn());
747ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
748ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  Dl_info dlinfo;
749ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
750ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
751ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(fn == dlinfo.dli_saddr);
752ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
753b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_SUBSTR("libgnu-hash-table-library.so", dlinfo.dli_fname);
754ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov#else
755ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  GTEST_LOG_(INFO) << "This test does nothing for mips/mips64; mips toolchain does not support '--hash-style=gnu'\n";
756a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes#endif
757ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
758e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
759b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy IvanovTEST(dlfcn, dlopen_library_with_only_sysv_hash) {
760b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  void* handle = dlopen("libsysv-hash-table-library.so", RTLD_NOW);
761b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
762b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  auto guard = make_scope_guard([&]() {
763b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov    dlclose(handle);
764b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  });
765b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
766b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
767b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  int (*fn)(void);
768b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
769b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  EXPECT_EQ(4, fn());
770b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov
771b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  Dl_info dlinfo;
772b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
773b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov
774b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(fn == dlinfo.dli_saddr);
775b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
776b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_SUBSTR("libsysv-hash-table-library.so", dlinfo.dli_fname);
777b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov}
778b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov
779e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_bad_flags) {
780e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  dlerror(); // Clear any pending errors.
781e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  void* handle;
782e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
783063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__GLIBC__)
784e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
785e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  handle = dlopen(NULL, 0);
786e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_TRUE(handle == NULL);
787e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR("invalid", dlerror());
788e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes#endif
789e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
790e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  handle = dlopen(NULL, 0xffffffff);
791e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_TRUE(handle == NULL);
792e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR("invalid", dlerror());
793e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
794e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
795e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  handle = dlopen(NULL, RTLD_NOW|RTLD_LAZY);
796e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_TRUE(handle != NULL);
797e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR(NULL, dlerror());
798e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes}
799ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
800ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey MelnikovTEST(dlfcn, rtld_default_unknown_symbol) {
8012ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
802ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov  ASSERT_TRUE(addr == NULL);
803ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov}
804ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
805ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey MelnikovTEST(dlfcn, rtld_default_known_symbol) {
8062ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_DEFAULT, "fopen");
8072ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  ASSERT_TRUE(addr != NULL);
8082ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes}
8092ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes
8102ed710976cb0ace31aab565c95a42d4e75623894Elliott HughesTEST(dlfcn, rtld_next_unknown_symbol) {
8112ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
8122ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  ASSERT_TRUE(addr == NULL);
8132ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes}
8142ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes
8152ed710976cb0ace31aab565c95a42d4e75623894Elliott HughesTEST(dlfcn, rtld_next_known_symbol) {
8162ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_NEXT, "fopen");
817ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov  ASSERT_TRUE(addr != NULL);
818ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov}
8197db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov
820ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy IvanovTEST(dlfcn, dlsym_weak_func) {
821ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  dlerror();
822bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW);
823ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  ASSERT_TRUE(handle != NULL);
824ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov
825ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  int (*weak_func)();
826ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
827ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  ASSERT_TRUE(weak_func != NULL) << "dlerror: " << dlerror();
828ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  EXPECT_EQ(42, weak_func());
829ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  dlclose(handle);
830ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov}
831ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov
832bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy IvanovTEST(dlfcn, dlopen_undefined_weak_func) {
833bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov  test_isolated([] {
834bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov    void* handle = dlopen("libtest_dlopen_weak_undefined_func.so", RTLD_NOW);
835bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov    ASSERT_TRUE(handle != nullptr) << dlerror();
836bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov    int (*weak_func)();
837bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov    weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "use_weak_undefined_func"));
838bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov    ASSERT_TRUE(weak_func != nullptr) << dlerror();
839bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov    EXPECT_EQ(6551, weak_func());
840bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov    dlclose(handle);
841bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov  });
842bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov}
843bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov
8447db180919c335287b201e859faa8ee0dbe281cdeDmitriy IvanovTEST(dlfcn, dlopen_symlink) {
8457db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
8467db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  void* handle2 = dlopen("libdlext_test_v2.so", RTLD_NOW);
8477db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_TRUE(handle1 != NULL);
8487db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_TRUE(handle2 != NULL);
8497db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_EQ(handle1, handle2);
850319356e39cc91b4eb94b1974756f1cfc0a137351Dmitriy Ivanov  dlclose(handle1);
851319356e39cc91b4eb94b1974756f1cfc0a137351Dmitriy Ivanov  dlclose(handle2);
8527db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov}
853279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
854279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov// libtest_dlopen_from_ctor_main.so depends on
855279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov// libtest_dlopen_from_ctor.so which has a constructor
856279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov// that calls dlopen(libc...). This is to test the situation
857279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov// described in b/7941716.
858279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy IvanovTEST(dlfcn, dlopen_dlopen_from_ctor) {
859279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov#if defined(__BIONIC__)
860279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  void* handle = dlopen("libtest_dlopen_from_ctor_main.so", RTLD_NOW);
861279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
862279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  dlclose(handle);
863279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov#else
864279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  GTEST_LOG_(INFO) << "This test is disabled for glibc (glibc segfaults if you try to call dlopen from a constructor).\n";
865279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov#endif
866279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov}
867