dlfcn_test.cpp revision aae859cc3ca127d890e853cbf12b731e05624a22
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
29aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#include "utils.h"
30aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
313b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#define ASSERT_SUBSTR(needle, haystack) \
323b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
333b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
34aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
351728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic bool g_called = false;
36acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhaoextern "C" void DlSymTestFunction() {
371728b2396591853345507a063ed6075dfd251706Elliott Hughes  g_called = true;
38acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao}
39acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
40f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovstatic int g_ctor_function_called = 0;
41f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
42f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovextern "C" void ctor_function() __attribute__ ((constructor));
43f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
44f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovextern "C" void ctor_function() {
45f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov  g_ctor_function_called = 17;
46f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov}
47f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
48f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy IvanovTEST(dlfcn, ctor_function_call) {
49f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov  ASSERT_EQ(17, g_ctor_function_called);
50f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov}
51f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
5276ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy IvanovTEST(dlfcn, dlsym_in_executable) {
533b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
54acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void* self = dlopen(NULL, RTLD_NOW);
55acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  ASSERT_TRUE(self != NULL);
563b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
57acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
58acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void* sym = dlsym(self, "DlSymTestFunction");
59acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  ASSERT_TRUE(sym != NULL);
60acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
61acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void (*function)() = reinterpret_cast<void(*)()>(sym);
62acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
631728b2396591853345507a063ed6075dfd251706Elliott Hughes  g_called = false;
64acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  function();
651728b2396591853345507a063ed6075dfd251706Elliott Hughes  ASSERT_TRUE(g_called);
661a6961650c82168864afe040dbdc05977db701dfElliott Hughes
671a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
68acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao}
698e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
7076ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy IvanovTEST(dlfcn, dlsym_from_sofile) {
7176ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_LAZY | RTLD_LOCAL);
7276ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
7376ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
7476ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  // check that we cant find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
7576ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
7676ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  ASSERT_TRUE(symbol == nullptr);
7776ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
7876ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
7976ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  typedef int* (*fn_t)();
8076ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
8176ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
8276ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
8376ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
8476ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  int* ptr = fn();
8576ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  ASSERT_TRUE(ptr != nullptr) << dlerror();
8676ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  ASSERT_EQ(42, *ptr);
8776ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
8876ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  dlclose(handle);
8976ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov}
9076ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
91aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy IvanovTEST(dlfcn, dlsym_with_dependencies) {
92aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
93aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  ASSERT_TRUE(handle != NULL);
94aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  dlerror();
95aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  // This symbol is in DT_NEEDED library.
96aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
97aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  ASSERT_TRUE(sym != NULL);
98aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  int (*fn)(void);
99aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
100aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  EXPECT_EQ(4, fn());
101aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  dlclose(handle);
102aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov}
103aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
104b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy IvanovTEST(dlfcn, dlopen_noload) {
105b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
106b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle == NULL);
107b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  handle = dlopen("libtest_simple.so", RTLD_NOW);
108b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
109b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle != NULL);
110b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle2 != NULL);
111b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle == handle2);
112b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
113b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle2));
114b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov}
115b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
116618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy IvanovTEST(dlfcn, dlopen_by_soname) {
117618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  static const char* soname = "libdlext_test_soname.so";
118618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  static const char* filename = "libdlext_test_different_soname.so";
119618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // 1. Make sure there is no library with soname in default search path
120618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  void* handle = dlopen(soname, RTLD_NOW);
121618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
122618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
123618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // 2. Load a library using filename
124618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  handle = dlopen(filename, RTLD_NOW);
125618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
126618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
127618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // 3. Find library by soname
128618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  void* handle_soname = dlopen(soname, RTLD_NOW | RTLD_NOLOAD);
129618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_TRUE(handle_soname != nullptr) << dlerror();
130618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_EQ(handle, handle_soname);
131618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
132618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // 4. RTLD_NOLOAD should still work with filename
133618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  void* handle_filename = dlopen(filename, RTLD_NOW | RTLD_NOLOAD);
134618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_TRUE(handle_filename != nullptr) << dlerror();
135618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_EQ(handle, handle_filename);
136618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
137618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  dlclose(handle_filename);
138618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  dlclose(handle_soname);
139618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  dlclose(handle);
140618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov}
141618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
1429aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov// ifuncs are only supported on intel and arm64 for now
1439aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov#if defined (__aarch64__) || defined(__i386__) || defined(__x86_64__)
144c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid SmithTEST(dlfcn, ifunc) {
1459598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  typedef const char* (*fn_ptr)();
146c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
147c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // ifunc's choice depends on whether IFUNC_CHOICE has a value
148c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // first check the set case
149c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  setenv("IFUNC_CHOICE", "set", 1);
150c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
151c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(handle != NULL);
1529598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
1539598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
154c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(foo_ptr != NULL);
155c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(foo_library_ptr != NULL);
1569598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
1579598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
158c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  dlclose(handle);
159c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
160c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // then check the unset case
161c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  unsetenv("IFUNC_CHOICE");
162c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  handle = dlopen("libtest_ifunc.so", RTLD_NOW);
163c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(handle != NULL);
1649598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
1659598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
166c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(foo_ptr != NULL);
167c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  ASSERT_TRUE(foo_library_ptr != NULL);
1689598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
1699598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
1709598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  dlclose(handle);
1719598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov}
1729598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov
1739598b8c415e2fa9f240508185fe8c964b83f538dDmitriy IvanovTEST(dlfcn, ifunc_ctor_call) {
1749598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  typedef const char* (*fn_ptr)();
1759598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov
1769598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
1779aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
1789aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  fn_ptr is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
1799aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
1809aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_STREQ("false", is_ctor_called());
1819aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov
1829aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
1839aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
1849598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_STREQ("true", is_ctor_called());
185c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  dlclose(handle);
186c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith}
187c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith#endif
188c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
189b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy IvanovTEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
190b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // This is the structure of the test library and
191b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // its dt_needed libraries
192b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // libtest_relo_check_dt_needed_order.so
193b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // |
194b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // +-> libtest_relo_check_dt_needed_order_1.so
195b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // |
196b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // +-> libtest_relo_check_dt_needed_order_2.so
197b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  //
198b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // The root library references relo_test_get_answer_lib - which is defined
199b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // in both dt_needed libraries, the correct relocation should
200b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // use the function defined in libtest_relo_check_dt_needed_order_1.so
201b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  void* handle = nullptr;
202d9ff7226613014056c9edd79a68dc5af939107a0Dmitriy Ivanov  auto guard = make_scope_guard([&]() {
203b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov    dlclose(handle);
204b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  });
205b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
206b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
207b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
208b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
209b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  typedef int (*fn_t) (void);
210b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
211b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
212b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_EQ(1, fn());
213b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov}
214b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
215cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_dlsym) {
21614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Here is how the test library and its dt_needed
21714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // libraries are arranged
21814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
219cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  libtest_check_order_children.so
22014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
221cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  +-> ..._1_left.so
22214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
223cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |   +-> ..._a.so
22414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
225cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |   +-> ...r_b.so
22614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
227cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  +-> ..._2_right.so
22814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
229cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |   +-> ..._d.so
23014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |       |
231cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |       +-> ..._b.so
23214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
233cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  +-> ..._3_c.so
23414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
23514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  load order should be (1, 2, 3, a, b, d)
23614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
23714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // get_answer() is defined in (2, 3, a, b, c)
23814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // get_answer2() is defined in (b, d)
239cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer");
24014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
241cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL);
242cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
24314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  typedef int (*fn_t) (void);
24414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  fn_t fn, fn2;
245cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"));
246eb27bbae8f0edc6b62ca2db73256c7fb53b9e9bfDmitriy Ivanov  ASSERT_TRUE(fn != NULL) << dlerror();
247cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2"));
248eb27bbae8f0edc6b62ca2db73256c7fb53b9e9bfDmitriy Ivanov  ASSERT_TRUE(fn2 != NULL) << dlerror();
24914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
25014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_EQ(42, fn());
25114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_EQ(43, fn2());
25214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  dlclose(handle);
25314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
25414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
255cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_siblings) {
256cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This is how this one works:
257cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // we lookup and call get_answer which is defined in '_2.so'
258cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so'
259cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // the correct _impl() is implemented by '_a.so';
260cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
261cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?)
262cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
263cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Here is the picture:
264cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
265cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_siblings.so
266cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
267cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._1.so <- empty
268cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
269cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._a.so <- exports correct answer_impl()
270cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
271cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._b.so <- every other letter exporting incorrect one.
272cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
273cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._2.so <- empty
274cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
275cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._c.so
276cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
277cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._d.so
278cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
279cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._3.so <- empty
280cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
281cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._e.so
282cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
283cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._f.so <- exports get_answer() that calls get_anser_impl();
284cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //                     implements incorrect get_answer_impl()
285cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
286cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
287cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
288cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#ifdef __BIONIC__
289cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
290cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
291cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#endif
292cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
293cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
294cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
295cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
296cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
297cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
298cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
299cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
300cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
301cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
302cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
303cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
304cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) {
305cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This test uses the same library as dlopen_check_order_reloc_siblings.
306cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Unlike dlopen_check_order_reloc_siblings it preloads
307cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_siblings_1.so (first dependency) prior to
308cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // dlopen(libtest_check_order_reloc_siblings.so)
309cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
310cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
311cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
312cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD);
313cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
314cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
315cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL);
316cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle_for_1 != nullptr) << dlerror();
317cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
318cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
319cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
320cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
321cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle_for_1));
322cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
323cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
324cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
325cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
326cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
327cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
328cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
329cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
330cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
3317699d13a74769fe8063fcca95588c87c571226c0Dmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_grandchild) {
3327699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // This is how this one works:
3337699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // we lookup and call grandchild_get_answer which is defined in '_2.so'
3347699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // and in turn calls external get_answer_impl() defined in '_c_1.so and _c_2.so'
3357699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // the correct _impl() is implemented by '_c_1.so';
3367699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //
3377699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // Here is the picture of subtree:
3387699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //
3397699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // libtest_check_order_reloc_siblings.so
3407699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // |
3417699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // +-> ..._2.so <- grandchild_get_answer()
3427699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |
3437699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     +-> ..._c.so <- empty
3447699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |   |
3457699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |   +-> _c_1.so <- exports correct answer_impl()
3467699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |   |
3477699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |   +-> _c_2.so <- exports incorrect answer_impl()
3487699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |
3497699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     +-> ..._d.so <- empty
3507699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
3517699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
3527699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
3537699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov#ifdef __BIONIC__
3547699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
3557699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
3567699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov#endif
3577699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
3587699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
3597699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
3607699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
3617699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  typedef int (*fn_t) (void);
3627699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_grandchild_get_answer"));
3637699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
3647699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_EQ(42, fn());
3657699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
3667699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
3677699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov}
3687699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
369cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_nephew) {
370cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This is how this one works:
371cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // we lookup and call nephew_get_answer which is defined in '_2.so'
372cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // and in turn calls external get_answer_impl() defined in '_[a-f].so'
373cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // the correct _impl() is implemented by '_a.so';
374cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
375cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Here is the picture:
376cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
377cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_siblings.so
378cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
379cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._1.so <- empty
380cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
381cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._a.so <- exports correct answer_impl()
382cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
383cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._b.so <- every other letter exporting incorrect one.
384cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
385cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._2.so <- empty
386cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
387cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._c.so
388cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
389cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._d.so
390cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
391cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl();
392cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
393cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._e.so
394cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
395cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._f.so
396cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
397cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
398cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
399cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#ifdef __BIONIC__
400cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
401cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
402cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#endif
403cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
404cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
405cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
406cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
407cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
408cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_nephew_get_answer"));
409cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
410cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
411cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
412cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
413cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
414cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
415ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy IvanovTEST(dlfcn, check_unload_after_reloc) {
416ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // This is how this one works:
417ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // libtest_two_parents_parent1 <- answer_impl() used by libtest_two_parents_child
418ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // |
419ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // +-> libtest_two_parents_child
420ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  //
421ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // libtest_two_parents_parent2 <- answer_impl() not used by libtest_two_parents_child
422ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // |
423ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // +-> libtest_two_parents_child
424ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  //
425ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // Test dlopens parent1 which loads and relocates libtest_two_parents_child.so
426ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // as a second step it dlopens parent2 and dlcloses parent1...
427ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
428cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  void* handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL);
429cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
430ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
431cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  void* handle2 = dlopen("libtest_two_parents_parent2.so", RTLD_NOW | RTLD_LOCAL);
432cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle2 != nullptr) << dlerror();
433ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
434cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  typedef int (*fn_t) (void);
435cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
436cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
437cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(42, fn());
438ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
439cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
440ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
441cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
442cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle != nullptr);
443cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
444ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
445cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
446cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
447cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(42, fn());
448ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
449cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle2));
450ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
451cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
452cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
453ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
454ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
455cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanovextern "C" int check_order_reloc_root_get_answer_impl() {
456cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  return 42;
457cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
458cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
459cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_main_executable) {
460cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This is how this one works:
461cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // we lookup and call get_answer3 which is defined in 'root.so'
462cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // and in turn calls external root_get_answer_impl() defined in _2.so and
463cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // above the correct _impl() is one in the executable.
464cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
465cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_root.so
466cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
467cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._1.so <- empty
468cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
469cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._2.so <- gives incorrect answer for answer_main_impl()
470cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
471cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
472cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD);
473cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
474cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#ifdef __BIONIC__
475cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
476cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
477cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#endif
478cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
479cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL);
480cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
481cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
482cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
483cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_root_get_answer"));
484cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
485cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
486cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
487cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
488cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
489cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
490e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy IvanovTEST(dlfcn, dlopen_check_rtld_local) {
491e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
492e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
493e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
494e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  // implicit RTLD_LOCAL
495e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW);
496e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
497e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
498e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
499e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(handle, "dlopen_testlib_simple_func");
500e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr);
501e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
502e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  dlclose(handle);
503e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
504e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  // explicit RTLD_LOCAL
505e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL);
506e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
507e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
508e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
509e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(handle, "dlopen_testlib_simple_func");
510e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr);
511e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
512e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  dlclose(handle);
513e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov}
514e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
515e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy IvanovTEST(dlfcn, dlopen_check_rtld_global) {
516e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
517e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
518e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
519e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL);
5201b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
521e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
522e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
523e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
524e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  dlclose(handle);
5251b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5261b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  // RTLD_GLOBAL implies RTLD_NODELETE, let's check that
5271b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
5281b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(sym, sym_after_dlclose);
529e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov}
530e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
53114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
53214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so ->
53314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop_a.so
53414669a939d113214a4a20b9318fca0992d5453f0Dmitriy IvanovTEST(dlfcn, dlopen_check_loop) {
535cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW);
536cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
537cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  void* f = dlsym(handle, "dlopen_test_loopy_function");
538cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(f != nullptr) << dlerror();
539cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  EXPECT_TRUE(reinterpret_cast<bool (*)(void)>(f)());
540cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
541cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov
542cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  // dlopen second time to make sure that the library was unloaded correctly
543cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
544cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
545ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov#ifdef __BIONIC__
546cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
547cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
548eb27bbae8f0edc6b62ca2db73256c7fb53b9e9bfDmitriy Ivanov#endif
549ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
550cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  handle = dlopen("libtest_with_dependency_a.so", RTLD_NOW | RTLD_NOLOAD);
551cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
55214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
55314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
5541b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy IvanovTEST(dlfcn, dlopen_nodelete) {
5551b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  static bool is_unloaded = false;
5561b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5571b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE);
5581b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
5591b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void (*set_unload_flag_ptr)(bool*);
5601b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr"));
5611b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
5621b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr(&is_unloaded);
5631b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5641b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
5651b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
5661b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(1729U, *taxicab_number);
5671b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  *taxicab_number = 2;
5681b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5691b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
5701b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(!is_unloaded);
5711b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5721b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number_after_dlclose = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
5731b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number);
5741b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(2U, *taxicab_number_after_dlclose);
5751b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5761b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5771b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  handle = dlopen("libtest_nodelete_1.so", RTLD_NOW);
5781b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number2 = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
5791b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(taxicab_number2, taxicab_number);
5801b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5811b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(2U, *taxicab_number2);
5821b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5831b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
5841b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(!is_unloaded);
5851b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
5861b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5871b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy IvanovTEST(dlfcn, dlopen_nodelete_on_second_dlopen) {
5881b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  static bool is_unloaded = false;
5891b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5901b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW);
5911b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
5921b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void (*set_unload_flag_ptr)(bool*);
5931b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr"));
5941b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
5951b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr(&is_unloaded);
5961b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
5971b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_2_taxicab_number"));
5981b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
5991b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
6001b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(1729U, *taxicab_number);
6011b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  *taxicab_number = 2;
6021b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
6031b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  // This RTLD_NODELETE should be ignored
6041b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE);
6051b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle1 != nullptr) << dlerror();
6061b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(handle, handle1);
6071b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
6081b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle1);
6091b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
6101b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
6111b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(is_unloaded);
6121b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
6131b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
6141b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy IvanovTEST(dlfcn, dlopen_nodelete_dt_flags_1) {
6151b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  static bool is_unloaded = false;
6161b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
6171b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW);
6181b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
6191b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void (*set_unload_flag_ptr)(bool*);
6201b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr"));
6211b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
6221b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr(&is_unloaded);
6231b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
6241b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
6251b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(!is_unloaded);
6261b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
6271b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
628d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy IvanovTEST(dlfcn, dlsym_df_1_global) {
6294e446b19d8710cd2004785db4a00f18f249fe73fDmitriy Ivanov#if !defined(__arm__) && !defined(__aarch64__)
630d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW);
631d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
632d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  int (*get_answer)();
633d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  get_answer = reinterpret_cast<int (*)()>(dlsym(handle, "dl_df_1_global_get_answer"));
634d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_TRUE(get_answer != nullptr) << dlerror();
635d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_EQ(42, get_answer());
636d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
637d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov#else
6384e446b19d8710cd2004785db4a00f18f249fe73fDmitriy Ivanov  GTEST_LOG_(INFO) << "This test does nothing on arm/arm64 (to be reenabled once b/18137520 or b/18130452 are fixed).\n";
639d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov#endif
640d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov}
641d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
642e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_failure) {
6433b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* self = dlopen("/does/not/exist", RTLD_NOW);
6443b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(self == NULL);
645063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__BIONIC__)
6463b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
6473b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#else
6483b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
6493b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
6503b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
6513b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
652ad88a0863110798cef5169dcf917e18b967a7cf6Elliott Hughesstatic void* ConcurrentDlErrorFn(void*) {
6535419b9474753d25dff947c7740532f86d130c0beElliott Hughes  dlopen("/child/thread", RTLD_NOW);
6545419b9474753d25dff947c7740532f86d130c0beElliott Hughes  return reinterpret_cast<void*>(strdup(dlerror()));
6555419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
6565419b9474753d25dff947c7740532f86d130c0beElliott Hughes
657e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlerror_concurrent) {
6585419b9474753d25dff947c7740532f86d130c0beElliott Hughes  dlopen("/main/thread", RTLD_NOW);
6595419b9474753d25dff947c7740532f86d130c0beElliott Hughes  const char* main_thread_error = dlerror();
6605419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/main/thread", main_thread_error);
6615419b9474753d25dff947c7740532f86d130c0beElliott Hughes
6625419b9474753d25dff947c7740532f86d130c0beElliott Hughes  pthread_t t;
6635419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentDlErrorFn, NULL));
6645419b9474753d25dff947c7740532f86d130c0beElliott Hughes  void* result;
6655419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_EQ(0, pthread_join(t, &result));
6665419b9474753d25dff947c7740532f86d130c0beElliott Hughes  char* child_thread_error = static_cast<char*>(result);
6675419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/child/thread", child_thread_error);
6685419b9474753d25dff947c7740532f86d130c0beElliott Hughes  free(child_thread_error);
6695419b9474753d25dff947c7740532f86d130c0beElliott Hughes
6705419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/main/thread", main_thread_error);
6715419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
6725419b9474753d25dff947c7740532f86d130c0beElliott Hughes
673e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlsym_failures) {
6743b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
6753b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* self = dlopen(NULL, RTLD_NOW);
6763b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(self != NULL);
6773b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
6783b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
6793b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* sym;
6803b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
68144adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov#if defined(__BIONIC__) && !defined(__LP64__)
68244adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov  // RTLD_DEFAULT in lp32 bionic is not (void*)0
68344adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov  // so it can be distinguished from the NULL handle.
6843b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(NULL, "test");
6853b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
6863b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("dlsym library handle is null", dlerror());
6873b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
6883b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
6893b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // NULL symbol name.
690063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__BIONIC__)
6913b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // glibc marks this parameter non-null and SEGVs if you cheat.
6923b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(self, NULL);
6933b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
6943b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("", dlerror());
6953b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
6963b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
6973b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // Symbol that doesn't exist.
6983b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(self, "ThisSymbolDoesNotExist");
6993b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(sym == NULL);
7003b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
7011a6961650c82168864afe040dbdc05977db701dfElliott Hughes
7021a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
7033b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
7043b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
705aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy IvanovTEST(dlfcn, dladdr_executable) {
7063b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
7078e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* self = dlopen(NULL, RTLD_NOW);
7088e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(self != NULL);
7093b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL);
7108e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
7118e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* sym = dlsym(self, "DlSymTestFunction");
7128e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_TRUE(sym != NULL);
7138e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
7148e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
7158e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
7168e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
7178e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  Dl_info info;
7188e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  int rc = dladdr(addr, &info);
7198e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
7208e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
7218e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Get the name of this executable.
7228e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  char executable_path[PATH_MAX];
7238e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  rc = readlink("/proc/self/exe", executable_path, sizeof(executable_path));
7248e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_NE(rc, -1);
7258e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  executable_path[rc] = '\0';
7268e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
7278e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The filename should be that of this executable.
728aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  char dli_realpath[PATH_MAX];
729aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_TRUE(realpath(info.dli_fname, dli_realpath) != nullptr);
730aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_STREQ(executable_path, dli_realpath);
7318e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
7328e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The symbol name should be the symbol we looked up.
7338e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_STREQ(info.dli_sname, "DlSymTestFunction");
7348e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
7358e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The address should be the exact address of the symbol.
7368e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(info.dli_saddr, sym);
7378e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
738aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  std::vector<map_record> maps;
739aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_TRUE(Maps::parse_maps(&maps));
740aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
741aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  void* base_address = nullptr;
742aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  for (const map_record& rec : maps) {
743aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    if (executable_path == rec.pathname) {
744aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov      base_address = reinterpret_cast<void*>(rec.addr_start);
7458e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes      break;
7468e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    }
7478e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  }
7488e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
7498e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The base address should be the address we were loaded at.
7508e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(info.dli_fbase, base_address);
7511a6961650c82168864afe040dbdc05977db701dfElliott Hughes
7521a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
7538e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes}
7548e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
755aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#if defined(__LP64__)
756aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#define BIONIC_PATH_TO_LIBC "/system/lib64/libc.so"
757aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#else
758aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#define BIONIC_PATH_TO_LIBC "/system/lib/libc.so"
759aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#endif
760aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
761aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy IvanovTEST(dlfcn, dladdr_libc) {
762aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#if defined(__BIONIC__)
763aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  Dl_info info;
764aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  void* addr = reinterpret_cast<void*>(puts); // well-known libc function
765aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_TRUE(dladdr(addr, &info) != 0);
766aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
767aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_STREQ(BIONIC_PATH_TO_LIBC, info.dli_fname);
768aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  // TODO: add check for dfi_fbase
769aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_STREQ("puts", info.dli_sname);
770aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_EQ(addr, info.dli_saddr);
771aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#else
772aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  GTEST_LOG_(INFO) << "This test does nothing for glibc. Glibc returns path from ldconfig "
773aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov      "for libc.so, which is symlink itself (not a realpath).\n";
774aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#endif
775aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov}
776aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
777e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dladdr_invalid) {
7788e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  Dl_info info;
7798e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
7803b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
7813b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
7828e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // No symbol corresponding to NULL.
7838e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success.
7843b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
7858e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
7868e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // No symbol corresponding to a stack address.
7878e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
7883b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
7898e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes}
790124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes
791a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes// GNU-style ELF hash tables are incompatible with the MIPS ABI.
792a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes// MIPS requires .dynsym to be sorted to match the GOT but GNU-style requires sorting by hash code.
793e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_library_with_only_gnu_hash) {
794ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov#if !defined(__mips__)
795124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  dlerror(); // Clear any pending errors.
796ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  void* handle = dlopen("libgnu-hash-table-library.so", RTLD_NOW);
797ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
798ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  auto guard = make_scope_guard([&]() {
799ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    dlclose(handle);
800ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  });
801ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
802ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
803ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  int (*fn)(void);
804ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
805ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  EXPECT_EQ(4, fn());
806ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
807ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  Dl_info dlinfo;
808ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
809ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
810ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(fn == dlinfo.dli_saddr);
811ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
812b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_SUBSTR("libgnu-hash-table-library.so", dlinfo.dli_fname);
813ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov#else
814ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  GTEST_LOG_(INFO) << "This test does nothing for mips/mips64; mips toolchain does not support '--hash-style=gnu'\n";
815a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes#endif
816ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
817e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
818b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy IvanovTEST(dlfcn, dlopen_library_with_only_sysv_hash) {
819b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  void* handle = dlopen("libsysv-hash-table-library.so", RTLD_NOW);
820b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
821b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  auto guard = make_scope_guard([&]() {
822b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov    dlclose(handle);
823b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  });
824b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
825b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
826b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  int (*fn)(void);
827b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
828b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  EXPECT_EQ(4, fn());
829b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov
830b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  Dl_info dlinfo;
831b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
832b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov
833b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(fn == dlinfo.dli_saddr);
834b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
835b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_SUBSTR("libsysv-hash-table-library.so", dlinfo.dli_fname);
836b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov}
837b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov
838e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_bad_flags) {
839e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  dlerror(); // Clear any pending errors.
840e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  void* handle;
841e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
842063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__GLIBC__)
843e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
844e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  handle = dlopen(NULL, 0);
845e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_TRUE(handle == NULL);
846e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR("invalid", dlerror());
847e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes#endif
848e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
849e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  handle = dlopen(NULL, 0xffffffff);
850e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_TRUE(handle == NULL);
851e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR("invalid", dlerror());
852e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
853e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
854e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  handle = dlopen(NULL, RTLD_NOW|RTLD_LAZY);
855e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_TRUE(handle != NULL);
856e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR(NULL, dlerror());
857e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes}
858ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
859ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey MelnikovTEST(dlfcn, rtld_default_unknown_symbol) {
8602ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
861ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov  ASSERT_TRUE(addr == NULL);
862ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov}
863ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
864ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey MelnikovTEST(dlfcn, rtld_default_known_symbol) {
8652ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_DEFAULT, "fopen");
8662ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  ASSERT_TRUE(addr != NULL);
8672ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes}
8682ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes
8692ed710976cb0ace31aab565c95a42d4e75623894Elliott HughesTEST(dlfcn, rtld_next_unknown_symbol) {
8702ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
8712ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  ASSERT_TRUE(addr == NULL);
8722ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes}
8732ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes
8742ed710976cb0ace31aab565c95a42d4e75623894Elliott HughesTEST(dlfcn, rtld_next_known_symbol) {
8752ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_NEXT, "fopen");
876ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov  ASSERT_TRUE(addr != NULL);
877ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov}
8787db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov
879ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy IvanovTEST(dlfcn, dlsym_weak_func) {
880ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  dlerror();
881bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW);
882ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  ASSERT_TRUE(handle != NULL);
883ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov
884ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  int (*weak_func)();
885ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
886ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  ASSERT_TRUE(weak_func != NULL) << "dlerror: " << dlerror();
887ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  EXPECT_EQ(42, weak_func());
888ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  dlclose(handle);
889ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov}
890ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov
891bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy IvanovTEST(dlfcn, dlopen_undefined_weak_func) {
892cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  void* handle = dlopen("libtest_dlopen_weak_undefined_func.so", RTLD_NOW);
893cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
894cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  int (*weak_func)();
895cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "use_weak_undefined_func"));
896cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(weak_func != nullptr) << dlerror();
897cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  EXPECT_EQ(6551, weak_func());
898cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  dlclose(handle);
899bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov}
900bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov
9017db180919c335287b201e859faa8ee0dbe281cdeDmitriy IvanovTEST(dlfcn, dlopen_symlink) {
9027db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
9037db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  void* handle2 = dlopen("libdlext_test_v2.so", RTLD_NOW);
9047db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_TRUE(handle1 != NULL);
9057db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_TRUE(handle2 != NULL);
9067db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_EQ(handle1, handle2);
907319356e39cc91b4eb94b1974756f1cfc0a137351Dmitriy Ivanov  dlclose(handle1);
908319356e39cc91b4eb94b1974756f1cfc0a137351Dmitriy Ivanov  dlclose(handle2);
9097db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov}
910279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
911279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov// libtest_dlopen_from_ctor_main.so depends on
912279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov// libtest_dlopen_from_ctor.so which has a constructor
913279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov// that calls dlopen(libc...). This is to test the situation
914279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov// described in b/7941716.
915279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy IvanovTEST(dlfcn, dlopen_dlopen_from_ctor) {
916279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov#if defined(__BIONIC__)
917279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  void* handle = dlopen("libtest_dlopen_from_ctor_main.so", RTLD_NOW);
918279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
919279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  dlclose(handle);
920279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov#else
921279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  GTEST_LOG_(INFO) << "This test is disabled for glibc (glibc segfaults if you try to call dlopen from a constructor).\n";
922279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov#endif
923279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov}
924