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 <limits.h>
218e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <stdio.h>
228e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <stdint.h>
23708589f5e8244a17d690848eed5f0fbfcce48a26Dimitry Ivanov#include <string.h>
248e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
25b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov#include "private/ScopeGuard.h"
26b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
278e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes#include <string>
28c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov#include <thread>
29acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
30927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov#include "gtest_globals.h"
31708589f5e8244a17d690848eed5f0fbfcce48a26Dimitry Ivanov#include "dlfcn_symlink_support.h"
32aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#include "utils.h"
33aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
34ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#if defined(__BIONIC__) && (defined(__arm__) || defined(__i386__))
35ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#pragma clang diagnostic push
36ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#pragma clang diagnostic ignored "-Wunused-parameter"
37ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
38ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#include <llvm/ADT/StringRef.h>
39ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#include <llvm/Object/Binary.h>
40ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#include <llvm/Object/ELFObjectFile.h>
41ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#include <llvm/Object/ObjectFile.h>
42ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
43ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#pragma clang diagnostic pop
44ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#endif //  defined(__ANDROID__) && (defined(__arm__) || defined(__i386__))
45ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
463b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#define ASSERT_SUBSTR(needle, haystack) \
473b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes    ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
483b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
49aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
501728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic bool g_called = false;
51acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhaoextern "C" void DlSymTestFunction() {
521728b2396591853345507a063ed6075dfd251706Elliott Hughes  g_called = true;
53acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao}
54acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
55f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanovstatic int g_ctor_function_called = 0;
56554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanovstatic int g_ctor_argc = 0;
57554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanovstatic char** g_ctor_argv = reinterpret_cast<char**>(0xDEADBEEF);
58554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanovstatic char** g_ctor_envp = g_ctor_envp;
59f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
60554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanovextern "C" void ctor_function(int argc, char** argv, char** envp) __attribute__ ((constructor));
61f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
62554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanovextern "C" void ctor_function(int argc, char** argv, char** envp) {
63f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov  g_ctor_function_called = 17;
64554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanov  g_ctor_argc = argc;
65554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanov  g_ctor_argv = argv;
66554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanov  g_ctor_envp = envp;
67f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov}
68f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
69f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy IvanovTEST(dlfcn, ctor_function_call) {
70f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov  ASSERT_EQ(17, g_ctor_function_called);
71554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanov  ASSERT_TRUE(g_ctor_argc = get_argc());
72554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanov  ASSERT_TRUE(g_ctor_argv = get_argv());
73554374693408cd7c74d0cae596fca7349661edeaDimitry Ivanov  ASSERT_TRUE(g_ctor_envp = get_envp());
74f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov}
75f8846a45878faa9eb51fab3a2b347e9a36ecd250Dmitriy Ivanov
7676ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy IvanovTEST(dlfcn, dlsym_in_executable) {
773b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
78aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  void* self = dlopen(nullptr, RTLD_NOW);
79aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(self != nullptr);
80aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(dlerror() == nullptr);
81acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
82acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void* sym = dlsym(self, "DlSymTestFunction");
83aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr);
84acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
85acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  void (*function)() = reinterpret_cast<void(*)()>(sym);
86acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao
871728b2396591853345507a063ed6075dfd251706Elliott Hughes  g_called = false;
88acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao  function();
891728b2396591853345507a063ed6075dfd251706Elliott Hughes  ASSERT_TRUE(g_called);
901a6961650c82168864afe040dbdc05977db701dfElliott Hughes
911a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
92acf5aa76a56f101607aeb8e6d1fbea24d0d4f68cjeffhao}
938e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
9476ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy IvanovTEST(dlfcn, dlsym_from_sofile) {
9576ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_LAZY | RTLD_LOCAL);
9676ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
9776ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
98697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
9976ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
10076ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  ASSERT_TRUE(symbol == nullptr);
10176ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
10276ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
10376ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  typedef int* (*fn_t)();
104697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT =
105697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
106697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror();
10776ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
108697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT();
109697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(ptr != nullptr) << dlerror();
110697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_EQ(42, *ptr);
111697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
112697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT =
113697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT"));
114697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror();
115697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
116697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT();
117697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(ptr != nullptr) << dlerror();
118697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_EQ(44, *ptr);
119697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
120697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  fn_t lookup_dlsym_symbol_using_RTLD_NEXT =
121697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT"));
122697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror();
123697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
124697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ptr = lookup_dlsym_symbol_using_RTLD_NEXT();
125697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(ptr != nullptr) << dlerror();
126697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_EQ(43, *ptr);
127697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
128697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  dlclose(handle);
129697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov}
130697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
131697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy IvanovTEST(dlfcn, dlsym_from_sofile_with_preload) {
132697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  void* preload = dlopen("libtest_dlsym_from_this_grandchild.so", RTLD_NOW | RTLD_LOCAL);
133697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(preload != nullptr) << dlerror();
134697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
135697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW | RTLD_LOCAL);
136697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
137697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
138697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
139697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
140697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(symbol == nullptr);
141697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
142697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
143697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  typedef int* (*fn_t)();
144697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT =
145697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
146697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror();
14776ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
148697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT();
14976ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  ASSERT_TRUE(ptr != nullptr) << dlerror();
15076ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  ASSERT_EQ(42, *ptr);
15176ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
152697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT =
153697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT"));
154697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror();
155697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
156697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT();
157697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(ptr != nullptr) << dlerror();
158697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_EQ(44, *ptr);
159697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
160697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  fn_t lookup_dlsym_symbol_using_RTLD_NEXT =
161697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov      reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT"));
162697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror();
163697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
164697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ptr = lookup_dlsym_symbol_using_RTLD_NEXT();
165697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_TRUE(ptr != nullptr) << dlerror();
166697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  ASSERT_EQ(43, *ptr);
167697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov
16876ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov  dlclose(handle);
169697bd9fd38ab078a117ad9a5777cf286c467b9b9Dmitriy Ivanov  dlclose(preload);
17076ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov}
17176ac1acdacc045cf1e56504e011dca68137dcd61Dmitriy Ivanov
172f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy IvanovTEST(dlfcn, dlsym_handle_global_sym) {
173f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  // check that we do not look into global group
174f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  // when looking up symbol by handle
175f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  void* handle = dlopen("libtest_empty.so", RTLD_NOW);
176f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  dlopen("libtest_with_dependency.so", RTLD_NOW | RTLD_GLOBAL);
177f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
178f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
179f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: getRandomNumber", dlerror());
180f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov
181f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  sym = dlsym(handle, "DlSymTestFunction");
182f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
183f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: DlSymTestFunction", dlerror());
184f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  dlclose(handle);
185f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov}
186f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov
187d5b578ac15330d7a872c198427628b723e0cc1cbDimitry IvanovTEST(dlfcn, dlsym_handle_empty_symbol) {
188d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov  // check that dlsym of an empty symbol fails (see http://b/33530622)
189d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov  void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW);
190d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
191d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov  void* sym = dlsym(handle, "");
192d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov  ASSERT_TRUE(sym == nullptr);
193d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov  ASSERT_SUBSTR("undefined symbol: ", dlerror());
194d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov  dlclose(handle);
195d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov}
196d5b578ac15330d7a872c198427628b723e0cc1cbDimitry Ivanov
197aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy IvanovTEST(dlfcn, dlsym_with_dependencies) {
198aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
199f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  ASSERT_TRUE(handle != nullptr);
200aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  dlerror();
201aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  // This symbol is in DT_NEEDED library.
202aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
203f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
204aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  int (*fn)(void);
205aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
206aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  EXPECT_EQ(4, fn());
207aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov  dlclose(handle);
208aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov}
209aa0f2bdbc22d4b7aec5d3f8f5f01eaeaa13414c2Dmitriy Ivanov
210b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy IvanovTEST(dlfcn, dlopen_noload) {
211b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
212aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
213b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  handle = dlopen("libtest_simple.so", RTLD_NOW);
214b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
215aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr);
216aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle2 != nullptr);
217b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_TRUE(handle == handle2);
218b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
219b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle2));
220b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov}
221b648a8a57ee42533a5bf127225a252f73ca2cbbcDmitriy Ivanov
222618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy IvanovTEST(dlfcn, dlopen_by_soname) {
223618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  static const char* soname = "libdlext_test_soname.so";
224618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  static const char* filename = "libdlext_test_different_soname.so";
225618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // 1. Make sure there is no library with soname in default search path
226618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  void* handle = dlopen(soname, RTLD_NOW);
227618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
228618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
229618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // 2. Load a library using filename
230618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  handle = dlopen(filename, RTLD_NOW);
231618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
232618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
233618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // 3. Find library by soname
234618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  void* handle_soname = dlopen(soname, RTLD_NOW | RTLD_NOLOAD);
235618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_TRUE(handle_soname != nullptr) << dlerror();
236618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_EQ(handle, handle_soname);
237618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
238618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  // 4. RTLD_NOLOAD should still work with filename
239618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  void* handle_filename = dlopen(filename, RTLD_NOW | RTLD_NOLOAD);
240618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_TRUE(handle_filename != nullptr) << dlerror();
241618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  ASSERT_EQ(handle, handle_filename);
242618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
243618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  dlclose(handle_filename);
244618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  dlclose(handle_soname);
245618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov  dlclose(handle);
246618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov}
247618f1a36f8635fa0f2d60c621fbf79ead2c3f3deDmitriy Ivanov
2480a2ab0203cc12c9b4b7647b18caf0343af8ca1a4Dimitry Ivanov// mips doesn't support ifuncs
2490a2ab0203cc12c9b4b7647b18caf0343af8ca1a4Dimitry Ivanov#if !defined(__mips__)
250c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid SmithTEST(dlfcn, ifunc) {
2519598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  typedef const char* (*fn_ptr)();
252c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
253c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // ifunc's choice depends on whether IFUNC_CHOICE has a value
254c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // first check the set case
255c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  setenv("IFUNC_CHOICE", "set", 1);
256c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
257aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr);
2589598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
2599598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
260aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(foo_ptr != nullptr);
261aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(foo_library_ptr != nullptr);
2629598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
2639598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
264c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  dlclose(handle);
265c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
266c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  // then check the unset case
267c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  unsetenv("IFUNC_CHOICE");
268c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  handle = dlopen("libtest_ifunc.so", RTLD_NOW);
269aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr);
2709598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
2719598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
272aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(foo_ptr != nullptr);
273aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(foo_library_ptr != nullptr);
2749598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
2759598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
2769598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  dlclose(handle);
2779598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov}
2789598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov
27901c888c857f6f19837c5db581be83cc06f13fa1cDimitry Ivanov// ld.gold for arm produces incorrect binary (see http://b/27930475 for details)
28001c888c857f6f19837c5db581be83cc06f13fa1cDimitry Ivanov#if defined(__arm__)
28101c888c857f6f19837c5db581be83cc06f13fa1cDimitry IvanovTEST(dlfcn, KNOWN_FAILURE_ON_BIONIC(ifunc_ctor_call)) {
28201c888c857f6f19837c5db581be83cc06f13fa1cDimitry Ivanov#else
2839598b8c415e2fa9f240508185fe8c964b83f538dDmitriy IvanovTEST(dlfcn, ifunc_ctor_call) {
28401c888c857f6f19837c5db581be83cc06f13fa1cDimitry Ivanov#endif
2859598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  typedef const char* (*fn_ptr)();
2869598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov
2879598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
2889aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
2899aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  fn_ptr is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
2909aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
2919aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_STREQ("false", is_ctor_called());
2929aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov
2939aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
2949aea164457c269c475592da36b4655d45f55c7bcDmitriy Ivanov  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
2959598b8c415e2fa9f240508185fe8c964b83f538dDmitriy Ivanov  ASSERT_STREQ("true", is_ctor_called());
296c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith  dlclose(handle);
297c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith}
298ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov
29901c888c857f6f19837c5db581be83cc06f13fa1cDimitry Ivanov// ld.gold for arm produces incorrect binary (see http://b/27930475 for details)
30001c888c857f6f19837c5db581be83cc06f13fa1cDimitry Ivanov#if defined(__arm__)
30101c888c857f6f19837c5db581be83cc06f13fa1cDimitry IvanovTEST(dlfcn, KNOWN_FAILURE_ON_BIONIC(ifunc_ctor_call_rtld_lazy)) {
30201c888c857f6f19837c5db581be83cc06f13fa1cDimitry Ivanov#else
303ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry IvanovTEST(dlfcn, ifunc_ctor_call_rtld_lazy) {
30401c888c857f6f19837c5db581be83cc06f13fa1cDimitry Ivanov#endif
305ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  typedef const char* (*fn_ptr)();
306ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov
307ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  void* handle = dlopen("libtest_ifunc.so", RTLD_LAZY);
308ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
309ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  fn_ptr is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
310ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
311ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  ASSERT_STREQ("false", is_ctor_called());
312ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov
313ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
314ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
315ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  ASSERT_STREQ("true", is_ctor_called());
316ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov  dlclose(handle);
317ba35b2d1b91459568133c1f4729a6fff8359e3d9Dimitry Ivanov}
3180a2ab0203cc12c9b4b7647b18caf0343af8ca1a4Dimitry Ivanov#endif
319c5a13efa9bc4264be0a9a9e37c00633af01584edBrigid Smith
320b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy IvanovTEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
321b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // This is the structure of the test library and
322b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // its dt_needed libraries
323b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // libtest_relo_check_dt_needed_order.so
324b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // |
325b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // +-> libtest_relo_check_dt_needed_order_1.so
326b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // |
327b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // +-> libtest_relo_check_dt_needed_order_2.so
328b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  //
329b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // The root library references relo_test_get_answer_lib - which is defined
330b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // in both dt_needed libraries, the correct relocation should
331b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  // use the function defined in libtest_relo_check_dt_needed_order_1.so
332b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  void* handle = nullptr;
333d9ff7226613014056c9edd79a68dc5af939107a0Dmitriy Ivanov  auto guard = make_scope_guard([&]() {
334b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov    dlclose(handle);
335b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  });
336b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
337b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
338b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
339b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
340b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  typedef int (*fn_t) (void);
341b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
342b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
343b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov  ASSERT_EQ(1, fn());
344b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov}
345b2a30ee8d209154efc367db11b4167a5d6db605fDmitriy Ivanov
346cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_dlsym) {
34714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // Here is how the test library and its dt_needed
34814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // libraries are arranged
34914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
350cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  libtest_check_order_children.so
35114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
352cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  +-> ..._1_left.so
35314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
354cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |   +-> ..._a.so
35514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
356cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |   +-> ...r_b.so
35714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
358cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  +-> ..._2_right.so
35914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |   |
360cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |   +-> ..._d.so
36114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |       |
362cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  |       +-> ..._b.so
36314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  |
364cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //  +-> ..._3_c.so
36514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
36614669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //  load order should be (1, 2, 3, a, b, d)
36714669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  //
36814669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // get_answer() is defined in (2, 3, a, b, c)
36914669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  // get_answer2() is defined in (b, d)
370cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* sym = dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer");
37114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
372cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_dlsym.so", RTLD_NOW | RTLD_GLOBAL);
373cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
37414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  typedef int (*fn_t) (void);
37514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  fn_t fn, fn2;
376cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"));
377aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
378cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2"));
379aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(fn2 != nullptr) << dlerror();
38014669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
38114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_EQ(42, fn());
38214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  ASSERT_EQ(43, fn2());
38314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov  dlclose(handle);
38414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
38514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
386cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_siblings) {
387cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This is how this one works:
388cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // we lookup and call get_answer which is defined in '_2.so'
389cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // and in turn calls external get_answer_impl() defined in _1.so and in '_[a-f].so'
390cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // the correct _impl() is implemented by '_a.so';
391cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
392cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Note that this is test for RTLD_LOCAL (TODO: test for GLOBAL?)
393cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
394cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Here is the picture:
395cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
396cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_siblings.so
397cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
398cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._1.so <- empty
399cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
400cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._a.so <- exports correct answer_impl()
401cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
402cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._b.so <- every other letter exporting incorrect one.
403cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
404cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._2.so <- empty
405cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
406cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._c.so
407cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
408cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._d.so
409cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
410cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._3.so <- empty
411cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
412cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._e.so
413cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
414cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._f.so <- exports get_answer() that calls get_anser_impl();
415cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //                     implements incorrect get_answer_impl()
416cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
417cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
418cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
419cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#ifdef __BIONIC__
420cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
421cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
422cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#endif
423cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
424cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
425cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
426cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
427cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
428cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
429cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
430cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
431cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
432cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
433cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
434cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
435cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_siblings_with_preload) {
436cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This test uses the same library as dlopen_check_order_reloc_siblings.
437cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Unlike dlopen_check_order_reloc_siblings it preloads
438cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_siblings_1.so (first dependency) prior to
439cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // dlopen(libtest_check_order_reloc_siblings.so)
440cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
441cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
442cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
443cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_NOLOAD);
444cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
445cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
446cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle_for_1 = dlopen("libtest_check_order_reloc_siblings_1.so", RTLD_NOW | RTLD_LOCAL);
447cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle_for_1 != nullptr) << dlerror();
448cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
449cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
450cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
451cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
452cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle_for_1));
453cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
454cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
455cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_get_answer"));
456cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
457cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
458cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
459cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
460cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
461cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
4627699d13a74769fe8063fcca95588c87c571226c0Dmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_grandchild) {
4637699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // This is how this one works:
4647699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // we lookup and call grandchild_get_answer which is defined in '_2.so'
4657699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // and in turn calls external get_answer_impl() defined in '_c_1.so and _c_2.so'
4667699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // the correct _impl() is implemented by '_c_1.so';
4677699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //
4687699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // Here is the picture of subtree:
4697699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //
4707699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // libtest_check_order_reloc_siblings.so
4717699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // |
4727699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // +-> ..._2.so <- grandchild_get_answer()
4737699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |
4747699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     +-> ..._c.so <- empty
4757699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |   |
4767699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |   +-> _c_1.so <- exports correct answer_impl()
4777699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |   |
4787699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |   +-> _c_2.so <- exports incorrect answer_impl()
4797699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     |
4807699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  //     +-> ..._d.so <- empty
4817699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
4827699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
4837699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
4847699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov#ifdef __BIONIC__
4857699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
4867699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
4877699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov#endif
4887699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
4897699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
4907699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
4917699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
4927699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  typedef int (*fn_t) (void);
4937699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_grandchild_get_answer"));
4947699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
4957699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_EQ(42, fn());
4967699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
4977699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
4987699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov}
4997699d13a74769fe8063fcca95588c87c571226c0Dmitriy Ivanov
500cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_nephew) {
501cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This is how this one works:
502cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // we lookup and call nephew_get_answer which is defined in '_2.so'
503cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // and in turn calls external get_answer_impl() defined in '_[a-f].so'
504cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // the correct _impl() is implemented by '_a.so';
505cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
506cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // Here is the picture:
507cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
508cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_siblings.so
509cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
510cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._1.so <- empty
511cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
512cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._a.so <- exports correct answer_impl()
513cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
514cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._b.so <- every other letter exporting incorrect one.
515cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
516cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._2.so <- empty
517cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
518cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._c.so
519cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   |
520cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |   +-> ..._d.so
521cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
522cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._3.so <- nephew_get_answer() that calls get_answer_impl();
523cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
524cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._e.so
525cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     |
526cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //     +-> ..._f.so
527cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
528cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_NOLOAD);
529cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
530cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#ifdef __BIONIC__
531cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
532cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_siblings.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
533cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#endif
534cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
535cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_siblings.so", RTLD_NOW | RTLD_LOCAL);
536cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
537cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
538cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
539cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_nephew_get_answer"));
540cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
541cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
542cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
543cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
544cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
545cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
546ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy IvanovTEST(dlfcn, check_unload_after_reloc) {
547ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // This is how this one works:
548ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // libtest_two_parents_parent1 <- answer_impl() used by libtest_two_parents_child
549ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // |
550ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // +-> libtest_two_parents_child
551ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  //
552ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // libtest_two_parents_parent2 <- answer_impl() not used by libtest_two_parents_child
553ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // |
554ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // +-> libtest_two_parents_child
555ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  //
556ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // Test dlopens parent1 which loads and relocates libtest_two_parents_child.so
557ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov  // as a second step it dlopens parent2 and dlcloses parent1...
558ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
559cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  void* handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL);
560cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
561ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
562cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  void* handle2 = dlopen("libtest_two_parents_parent2.so", RTLD_NOW | RTLD_LOCAL);
563cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle2 != nullptr) << dlerror();
564ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
565cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  typedef int (*fn_t) (void);
566cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
567cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
568cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(42, fn());
569ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
570cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
571ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
572cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
573cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle != nullptr);
574cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
575ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
576cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  fn = reinterpret_cast<fn_t>(dlsym(handle2, "check_order_reloc_get_answer"));
577cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
578cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(42, fn());
579ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
580cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle2));
581ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
582cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  handle = dlopen("libtest_two_parents_parent1.so", RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD);
583cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
584ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov}
585ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
586cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanovextern "C" int check_order_reloc_root_get_answer_impl() {
587cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  return 42;
588cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
589cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
590cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy IvanovTEST(dlfcn, dlopen_check_order_reloc_main_executable) {
591cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // This is how this one works:
592cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // we lookup and call get_answer3 which is defined in 'root.so'
593cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // and in turn calls external root_get_answer_impl() defined in _2.so and
594cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // above the correct _impl() is one in the executable.
595cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
596cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // libtest_check_order_reloc_root.so
597cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
598cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._1.so <- empty
599cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // |
600cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // +-> ..._2.so <- gives incorrect answer for answer_main_impl()
601cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  //
602cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
603cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  void* handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_NOLOAD);
604cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
605cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#ifdef __BIONIC__
606cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
607cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_check_order_reloc_root.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
608cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov#endif
609cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
610cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  handle = dlopen("libtest_check_order_reloc_root.so", RTLD_NOW | RTLD_LOCAL);
611cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
612cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
613cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  typedef int (*fn_t) (void);
614cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "check_order_reloc_root_get_answer"));
615cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
616cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(42, fn());
617cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
618cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
619cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov}
620cfa97f172dc1b10d650fefbb6ccffd88ce72a5fbDmitriy Ivanov
621e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy IvanovTEST(dlfcn, dlopen_check_rtld_local) {
622e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
623e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
624e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
625e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  // implicit RTLD_LOCAL
626e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW);
627e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
628e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
629e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
630e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(handle, "dlopen_testlib_simple_func");
631e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr);
632e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
633e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  dlclose(handle);
634e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
635e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  // explicit RTLD_LOCAL
636e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL);
637e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
638e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
639e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
640e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(handle, "dlopen_testlib_simple_func");
641e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr);
642e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
643e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  dlclose(handle);
644e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov}
645e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
646e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy IvanovTEST(dlfcn, dlopen_check_rtld_global) {
647e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
648e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
649e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
650e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL);
6511b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
652e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
653e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
654e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
655e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov  dlclose(handle);
6561b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
6571b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  // RTLD_GLOBAL implies RTLD_NODELETE, let's check that
6581b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
6591b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(sym, sym_after_dlclose);
660f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov
661f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  // Check if dlsym() for main program's handle searches RTLD_GLOBAL
662f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  // shared libraries after symbol was not found in the main executable
663f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  // and dependent libraries.
664f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  void* handle_for_main_executable = dlopen(nullptr, RTLD_NOW);
665f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  sym = dlsym(handle_for_main_executable, "dlopen_testlib_simple_func");
666f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
667f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov
668f439b5a3186ca0fef1092f45770abc716da9d87aDmitriy Ivanov  dlclose(handle_for_main_executable);
669e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov}
670e8ba50fe0d51fbefee1a8f5bb62bf51d841512c8Dmitriy Ivanov
67114669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
67214669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so ->
67314669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov// libtest_with_dependency_loop_a.so
67414669a939d113214a4a20b9318fca0992d5453f0Dmitriy IvanovTEST(dlfcn, dlopen_check_loop) {
675cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW);
676cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
677cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  void* f = dlsym(handle, "dlopen_test_loopy_function");
678cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(f != nullptr) << dlerror();
679cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  EXPECT_TRUE(reinterpret_cast<bool (*)(void)>(f)());
680cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
681cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov
682cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  // dlopen second time to make sure that the library was unloaded correctly
683cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD);
684cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
685ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov#ifdef __BIONIC__
686cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
6879cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov#else
6889cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  // TODO: glibc returns nullptr on dlerror() here. Is it bug?
6899cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  ASSERT_TRUE(dlerror() == nullptr);
690eb27bbae8f0edc6b62ca2db73256c7fb53b9e9bfDmitriy Ivanov#endif
691ab972b9adf8789a9e1b03129cd7f0c22e6bba117Dmitriy Ivanov
692cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  handle = dlopen("libtest_with_dependency_a.so", RTLD_NOW | RTLD_NOLOAD);
693cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
69414669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov}
69514669a939d113214a4a20b9318fca0992d5453f0Dmitriy Ivanov
6961b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy IvanovTEST(dlfcn, dlopen_nodelete) {
6971b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  static bool is_unloaded = false;
6981b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
6991b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle = dlopen("libtest_nodelete_1.so", RTLD_NOW | RTLD_NODELETE);
7001b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
7011b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void (*set_unload_flag_ptr)(bool*);
7021b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_1_set_unload_flag_ptr"));
7031b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
7041b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr(&is_unloaded);
7051b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7061b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
7071b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
7081b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(1729U, *taxicab_number);
7091b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  *taxicab_number = 2;
7101b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7111b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
7121b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(!is_unloaded);
7131b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7141b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number_after_dlclose = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
7151b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(taxicab_number_after_dlclose, taxicab_number);
7161b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(2U, *taxicab_number_after_dlclose);
7171b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7181b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7191b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  handle = dlopen("libtest_nodelete_1.so", RTLD_NOW);
7201b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number2 = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_1_taxicab_number"));
7211b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(taxicab_number2, taxicab_number);
7221b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7231b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(2U, *taxicab_number2);
7241b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7251b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
7261b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(!is_unloaded);
7271b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
7281b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7291b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy IvanovTEST(dlfcn, dlopen_nodelete_on_second_dlopen) {
7301b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  static bool is_unloaded = false;
7311b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7321b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle = dlopen("libtest_nodelete_2.so", RTLD_NOW);
7331b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
7341b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void (*set_unload_flag_ptr)(bool*);
7351b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_2_set_unload_flag_ptr"));
7361b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
7371b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr(&is_unloaded);
7381b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7391b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_nodelete_2_taxicab_number"));
7401b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(taxicab_number != nullptr) << dlerror();
7411b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7421b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(1729U, *taxicab_number);
7431b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  *taxicab_number = 2;
7441b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7451b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  // This RTLD_NODELETE should be ignored
7461b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle1 = dlopen("libtest_nodelete_2.so", RTLD_NOW | RTLD_NODELETE);
7471b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle1 != nullptr) << dlerror();
7481b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_EQ(handle, handle1);
7491b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7501b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle1);
7511b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
7521b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7531b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(is_unloaded);
7541b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
7551b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7561b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy IvanovTEST(dlfcn, dlopen_nodelete_dt_flags_1) {
7571b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  static bool is_unloaded = false;
7581b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7591b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void* handle = dlopen("libtest_nodelete_dt_flags_1.so", RTLD_NOW);
7601b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
7611b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  void (*set_unload_flag_ptr)(bool*);
7621b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr = reinterpret_cast<void (*)(bool*)>(dlsym(handle, "dlopen_nodelete_dt_flags_1_set_unload_flag_ptr"));
7631b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(set_unload_flag_ptr != nullptr) << dlerror();
7641b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  set_unload_flag_ptr(&is_unloaded);
7651b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
7661b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  dlclose(handle);
7671b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov  ASSERT_TRUE(!is_unloaded);
7681b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov}
7691b20dafdbe65e43b9f4c95057e8482380833ea91Dmitriy Ivanov
770d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy IvanovTEST(dlfcn, dlsym_df_1_global) {
771d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_df_1_global.so", RTLD_NOW);
772d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
773d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  int (*get_answer)();
774d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  get_answer = reinterpret_cast<int (*)()>(dlsym(handle, "dl_df_1_global_get_answer"));
775d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_TRUE(get_answer != nullptr) << dlerror();
776d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_EQ(42, get_answer());
777d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov  ASSERT_EQ(0, dlclose(handle));
778d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov}
779d225a5e65223b375a63548c4b780f04d8f3d7b60Dmitriy Ivanov
780e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_failure) {
7813b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* self = dlopen("/does/not/exist", RTLD_NOW);
782aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(self == nullptr);
783063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__BIONIC__)
7843b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
7853b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#else
7863b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
7873b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
7883b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
7893b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
790c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanovstatic void ConcurrentDlErrorFn(std::string& error) {
791c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_TRUE(dlerror() == nullptr);
792c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov
793c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  void* handle = dlopen("/child/thread", RTLD_NOW);
794c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_TRUE(handle == nullptr);
795c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov
796c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  const char* err = dlerror();
797c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_TRUE(err != nullptr);
798c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov
799c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  error = err;
8005419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
8015419b9474753d25dff947c7740532f86d130c0beElliott Hughes
802c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry IvanovTEST(dlfcn, dlerror_concurrent_buffer) {
803c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  void* handle = dlopen("/main/thread", RTLD_NOW);
804c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_TRUE(handle == nullptr);
8055419b9474753d25dff947c7740532f86d130c0beElliott Hughes  const char* main_thread_error = dlerror();
806c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_TRUE(main_thread_error != nullptr);
8075419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/main/thread", main_thread_error);
8085419b9474753d25dff947c7740532f86d130c0beElliott Hughes
809c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  std::string child_thread_error;
810c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  std::thread t(ConcurrentDlErrorFn, std::ref(child_thread_error));
811c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  t.join();
812c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_SUBSTR("/child/thread", child_thread_error.c_str());
8135419b9474753d25dff947c7740532f86d130c0beElliott Hughes
814c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  // Check that main thread local buffer was not modified.
815c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_SUBSTR("/main/thread", main_thread_error);
816c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov}
817c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov
818c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry IvanovTEST(dlfcn, dlerror_concurrent) {
819c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  void* handle = dlopen("/main/thread", RTLD_NOW);
820c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_TRUE(handle == nullptr);
821c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov
822c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  std::string child_thread_error;
823c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  std::thread t(ConcurrentDlErrorFn, std::ref(child_thread_error));
824c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  t.join();
825c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_SUBSTR("/child/thread", child_thread_error.c_str());
826c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov
827c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  const char* main_thread_error = dlerror();
828c7365eb2fa996e72c5ea7f4e20222d6b48b9c6e0Dimitry Ivanov  ASSERT_TRUE(main_thread_error != nullptr);
8295419b9474753d25dff947c7740532f86d130c0beElliott Hughes  ASSERT_SUBSTR("/main/thread", main_thread_error);
8305419b9474753d25dff947c7740532f86d130c0beElliott Hughes}
8315419b9474753d25dff947c7740532f86d130c0beElliott Hughes
832e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlsym_failures) {
8333b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
834aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  void* self = dlopen(nullptr, RTLD_NOW);
835aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(self != nullptr);
836aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(dlerror() == nullptr);
8373b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
8383b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  void* sym;
8393b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
84044adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov#if defined(__BIONIC__) && !defined(__LP64__)
84144adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov  // RTLD_DEFAULT in lp32 bionic is not (void*)0
84244adf93b8eddb3a7965a3e9abc189408a1f5a7eaDmitriy Ivanov  // so it can be distinguished from the NULL handle.
843aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  sym = dlsym(nullptr, "test");
844aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
8454a2c5aa30ceea2aaf8dcaee2feb4879978af4fceDimitry Ivanov  ASSERT_STREQ("dlsym failed: library handle is null", dlerror());
8463b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes#endif
8473b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
8483b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  // Symbol that doesn't exist.
8493b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  sym = dlsym(self, "ThisSymbolDoesNotExist");
850aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(sym == nullptr);
8513b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
8521a6961650c82168864afe040dbdc05977db701dfElliott Hughes
8531a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
8543b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes}
8553b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
856aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy IvanovTEST(dlfcn, dladdr_executable) {
8573b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
858aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  void* self = dlopen(nullptr, RTLD_NOW);
859aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(self != nullptr);
860aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(dlerror() == nullptr);
8618e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
8628e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* sym = dlsym(self, "DlSymTestFunction");
863aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr);
8648e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
8658e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
8668e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
8678e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
8688e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  Dl_info info;
8698e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  int rc = dladdr(addr, &info);
8708e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_NE(rc, 0); // Zero on error, non-zero on success.
8718e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
8728e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // Get the name of this executable.
8732ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov  const std::string& executable_path = get_executable_path();
8748e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
8758e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The filename should be that of this executable.
876aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  char dli_realpath[PATH_MAX];
877aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_TRUE(realpath(info.dli_fname, dli_realpath) != nullptr);
8782ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov  ASSERT_STREQ(executable_path.c_str(), dli_realpath);
8798e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
8808e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The symbol name should be the symbol we looked up.
8818e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_STREQ(info.dli_sname, "DlSymTestFunction");
8828e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
8838e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The address should be the exact address of the symbol.
8848e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(info.dli_saddr, sym);
8858e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
886aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  std::vector<map_record> maps;
887aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_TRUE(Maps::parse_maps(&maps));
888aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
889aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  void* base_address = nullptr;
890aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  for (const map_record& rec : maps) {
891aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov    if (executable_path == rec.pathname) {
892aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov      base_address = reinterpret_cast<void*>(rec.addr_start);
8938e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes      break;
8948e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes    }
8958e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  }
8968e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
8978e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // The base address should be the address we were loaded at.
8988e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(info.dli_fbase, base_address);
8991a6961650c82168864afe040dbdc05977db701dfElliott Hughes
9001a6961650c82168864afe040dbdc05977db701dfElliott Hughes  ASSERT_EQ(0, dlclose(self));
9018e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes}
9028e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
9032ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry IvanovTEST(dlfcn, dlopen_executable_by_absolute_path) {
9042ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov  void* handle1 = dlopen(nullptr, RTLD_NOW);
9052ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov  ASSERT_TRUE(handle1 != nullptr) << dlerror();
9062ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov
9072ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov  void* handle2 = dlopen(get_executable_path().c_str(), RTLD_NOW);
9082ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov  ASSERT_TRUE(handle2 != nullptr) << dlerror();
9092ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov
9102ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov#if defined(__BIONIC__)
9112ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov  ASSERT_EQ(handle1, handle2);
9122ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov#else
9132ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov  GTEST_LOG_(INFO) << "Skipping ASSERT_EQ(handle1, handle2) for glibc: "
9142ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov                      "it loads a separate copy of the main executable "
9152ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov                      "on dlopen by absolute path.";
9162ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov#endif
9172ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov}
9182ba1cf39ae6087249a839ec7b3793d4d4fa75438Dimitry Ivanov
91914b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#if defined (__aarch64__)
92014b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/arm64/"
92114b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#elif defined (__arm__)
92214b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/arm/"
92314b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#elif defined (__i386__)
92414b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/x86/"
92514b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#elif defined (__x86_64__)
92614b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/x86_64/"
92714b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#elif defined (__mips__)
92814b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#if defined(__LP64__)
92914b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/mips64/"
93014b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#else
93114b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/mips/"
93214b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#endif
93314b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#else
93414b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#error "Unknown architecture"
93514b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#endif
9366f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar Trsic#define PATH_TO_LIBC PATH_TO_SYSTEM_LIB "libc.so"
93714b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko#define ALTERNATE_PATH_TO_LIBC ALTERNATE_PATH_TO_SYSTEM_LIB "libc.so"
938aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
939aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy IvanovTEST(dlfcn, dladdr_libc) {
940aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#if defined(__BIONIC__)
941aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  Dl_info info;
942aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  void* addr = reinterpret_cast<void*>(puts); // well-known libc function
943aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_TRUE(dladdr(addr, &info) != 0);
944aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
945ef25592f14d23ce6294ea103e9edf894779d141dDmitriy Ivanov  char libc_realpath[PATH_MAX];
94614b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko
94714b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko  // Check if libc is in canonical path or in alternate path.
94814b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko  if (strncmp(ALTERNATE_PATH_TO_SYSTEM_LIB,
94914b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko              info.dli_fname,
95014b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko              sizeof(ALTERNATE_PATH_TO_SYSTEM_LIB) - 1) == 0) {
95114b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko    // Platform with emulated architecture.  Symlink on ARC++.
95214b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko    ASSERT_TRUE(realpath(ALTERNATE_PATH_TO_LIBC, libc_realpath) == libc_realpath);
95314b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko  } else {
95414b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko    // /system/lib is symlink when this test is executed on host.
95514b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko    ASSERT_TRUE(realpath(PATH_TO_LIBC, libc_realpath) == libc_realpath);
95614b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko  }
957ef25592f14d23ce6294ea103e9edf894779d141dDmitriy Ivanov
958ef25592f14d23ce6294ea103e9edf894779d141dDmitriy Ivanov  ASSERT_STREQ(libc_realpath, info.dli_fname);
959aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  // TODO: add check for dfi_fbase
960aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_STREQ("puts", info.dli_sname);
961aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  ASSERT_EQ(addr, info.dli_saddr);
962aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#else
963aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov  GTEST_LOG_(INFO) << "This test does nothing for glibc. Glibc returns path from ldconfig "
964aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov      "for libc.so, which is symlink itself (not a realpath).\n";
965aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov#endif
966aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov}
967aae859cc3ca127d890e853cbf12b731e05624a22Dmitriy Ivanov
968e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dladdr_invalid) {
9698e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  Dl_info info;
9708e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
9713b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes  dlerror(); // Clear any pending errors.
9723b297c40794b23d50cb5240f9b03f6ef25fd98dbElliott Hughes
9738e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // No symbol corresponding to NULL.
974aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_EQ(dladdr(nullptr, &info), 0); // Zero on error, non-zero on success.
975aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(dlerror() == nullptr); // dladdr(3) doesn't set dlerror(3).
9768e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes
9778e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  // No symbol corresponding to a stack address.
9788e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes  ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
979aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(dlerror() == nullptr); // dladdr(3) doesn't set dlerror(3).
9808e15b08ae22a5230c1fea4779410de0420fa939cElliott Hughes}
981124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes
982a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes// GNU-style ELF hash tables are incompatible with the MIPS ABI.
983a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes// MIPS requires .dynsym to be sorted to match the GOT but GNU-style requires sorting by hash code.
984e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_library_with_only_gnu_hash) {
985ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov#if !defined(__mips__)
986124fae9eabd7a25d80dfa8c3b56bed0f0fba16f1Elliott Hughes  dlerror(); // Clear any pending errors.
987ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  void* handle = dlopen("libgnu-hash-table-library.so", RTLD_NOW);
988ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
989ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  auto guard = make_scope_guard([&]() {
990ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov    dlclose(handle);
991ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  });
992ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
993ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
994ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  int (*fn)(void);
995ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
996ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  EXPECT_EQ(4, fn());
997ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
998ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  Dl_info dlinfo;
999ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
1000ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov
1001ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_TRUE(fn == dlinfo.dli_saddr);
1002ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
1003b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_SUBSTR("libgnu-hash-table-library.so", dlinfo.dli_fname);
1004ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov#else
1005ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov  GTEST_LOG_(INFO) << "This test does nothing for mips/mips64; mips toolchain does not support '--hash-style=gnu'\n";
1006a43e906221a3e9c70a66118a8692cd46f77e144eElliott Hughes#endif
1007ec18ce06f2d007be40ad6f043058f5a4c7236573Dmitriy Ivanov}
1008e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
1009b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy IvanovTEST(dlfcn, dlopen_library_with_only_sysv_hash) {
1010b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  void* handle = dlopen("libsysv-hash-table-library.so", RTLD_NOW);
1011b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
1012b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  auto guard = make_scope_guard([&]() {
1013b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov    dlclose(handle);
1014b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  });
1015b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  void* sym = dlsym(handle, "getRandomNumber");
1016b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(sym != nullptr) << dlerror();
1017b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  int (*fn)(void);
1018b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  fn = reinterpret_cast<int (*)(void)>(sym);
1019b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  EXPECT_EQ(4, fn());
1020b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov
1021b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  Dl_info dlinfo;
1022b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(0 != dladdr(reinterpret_cast<void*>(fn), &dlinfo));
1023b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov
1024b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_TRUE(fn == dlinfo.dli_saddr);
1025b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_STREQ("getRandomNumber", dlinfo.dli_sname);
1026b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov  ASSERT_SUBSTR("libsysv-hash-table-library.so", dlinfo.dli_fname);
1027b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov}
1028b3356773c6b5fbbbb26d22b3d6c6e0e598840e44Dmitriy Ivanov
1029e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott HughesTEST(dlfcn, dlopen_bad_flags) {
1030e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  dlerror(); // Clear any pending errors.
1031e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  void* handle;
1032e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
1033063525c61d24776094d76971f33920e2a2079530Elliott Hughes#if defined(__GLIBC__)
1034e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
1035aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  handle = dlopen(nullptr, 0);
1036aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
1037e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR("invalid", dlerror());
1038e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes#endif
1039e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
1040aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  handle = dlopen(nullptr, 0xffffffff);
1041aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle == nullptr);
1042e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  ASSERT_SUBSTR("invalid", dlerror());
1043e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes
1044e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes  // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
1045aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  handle = dlopen(nullptr, RTLD_NOW|RTLD_LAZY);
1046aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr);
1047aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_SUBSTR(nullptr, dlerror());
1048e66190d2a97a713ae4b4786e60ca3d67ab8aa192Elliott Hughes}
1049ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
1050ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey MelnikovTEST(dlfcn, rtld_default_unknown_symbol) {
10512ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
1052aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(addr == nullptr);
1053ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov}
1054ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov
1055ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey MelnikovTEST(dlfcn, rtld_default_known_symbol) {
10562ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_DEFAULT, "fopen");
1057aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(addr != nullptr);
10582ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes}
10592ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes
10602ed710976cb0ace31aab565c95a42d4e75623894Elliott HughesTEST(dlfcn, rtld_next_unknown_symbol) {
10612ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
1062aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(addr == nullptr);
10632ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes}
10642ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes
10652ed710976cb0ace31aab565c95a42d4e75623894Elliott HughesTEST(dlfcn, rtld_next_known_symbol) {
10662ed710976cb0ace31aab565c95a42d4e75623894Elliott Hughes  void* addr = dlsym(RTLD_NEXT, "fopen");
1067aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(addr != nullptr);
1068ebd506c69e12b6dcaf5be94cc8ed1b53af299f9fSergey Melnikov}
10697db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov
1070d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov// Check that RTLD_NEXT of a libc symbol works in dlopened library
1071d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry IvanovTEST(dlfcn, rtld_next_from_library) {
1072d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  void* library_with_close = dlopen("libtest_check_rtld_next_from_library.so", RTLD_NOW);
1073d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  ASSERT_TRUE(library_with_close != nullptr) << dlerror();
1074d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  void* expected_addr = dlsym(RTLD_DEFAULT, "close");
1075d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  ASSERT_TRUE(expected_addr != nullptr) << dlerror();
1076d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  typedef void* (*get_libc_close_ptr_fn_t)();
1077d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  get_libc_close_ptr_fn_t get_libc_close_ptr =
1078d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov      reinterpret_cast<get_libc_close_ptr_fn_t>(dlsym(library_with_close, "get_libc_close_ptr"));
1079d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  ASSERT_TRUE(get_libc_close_ptr != nullptr) << dlerror();
1080d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  ASSERT_EQ(expected_addr, get_libc_close_ptr());
1081d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov
1082d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  dlclose(library_with_close);
1083d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov}
1084d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov
1085d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov
1086ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy IvanovTEST(dlfcn, dlsym_weak_func) {
1087ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  dlerror();
1088bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov  void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW);
1089aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr);
1090ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov
1091ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  int (*weak_func)();
1092ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
1093aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(weak_func != nullptr) << "dlerror: " << dlerror();
1094ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  EXPECT_EQ(42, weak_func());
1095ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov  dlclose(handle);
1096ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov}
1097ce44166c737b6737c3a0820bef10b074a5e36cf8Dmitriy Ivanov
1098bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy IvanovTEST(dlfcn, dlopen_undefined_weak_func) {
1099cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  void* handle = dlopen("libtest_dlopen_weak_undefined_func.so", RTLD_NOW);
1100cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
1101cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  int (*weak_func)();
1102cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "use_weak_undefined_func"));
1103cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  ASSERT_TRUE(weak_func != nullptr) << dlerror();
1104cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  EXPECT_EQ(6551, weak_func());
1105cb0443c0fa07e4c049f426e3041894df522732dfDmitriy Ivanov  dlclose(handle);
1106bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov}
1107bfa88bca5ca387d6b3560074050856527cfc7514Dmitriy Ivanov
11087db180919c335287b201e859faa8ee0dbe281cdeDmitriy IvanovTEST(dlfcn, dlopen_symlink) {
1109708589f5e8244a17d690848eed5f0fbfcce48a26Dimitry Ivanov  DlfcnSymlink symlink("dlopen_symlink");
1110708589f5e8244a17d690848eed5f0fbfcce48a26Dimitry Ivanov  const std::string symlink_name = basename(symlink.get_symlink_path().c_str());
11117db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
1112708589f5e8244a17d690848eed5f0fbfcce48a26Dimitry Ivanov  void* handle2 = dlopen(symlink_name.c_str(), RTLD_NOW);
1113aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle1 != nullptr);
1114aff18fd60804e177c319d04dd4c12f3ee1c0cba8Dmitriy Ivanov  ASSERT_TRUE(handle2 != nullptr);
11157db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov  ASSERT_EQ(handle1, handle2);
1116319356e39cc91b4eb94b1974756f1cfc0a137351Dmitriy Ivanov  dlclose(handle1);
1117319356e39cc91b4eb94b1974756f1cfc0a137351Dmitriy Ivanov  dlclose(handle2);
11187db180919c335287b201e859faa8ee0dbe281cdeDmitriy Ivanov}
1119279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov
1120279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov// libtest_dlopen_from_ctor_main.so depends on
1121279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov// libtest_dlopen_from_ctor.so which has a constructor
1122279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov// that calls dlopen(libc...). This is to test the situation
1123279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov// described in b/7941716.
1124279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy IvanovTEST(dlfcn, dlopen_dlopen_from_ctor) {
1125279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov#if defined(__BIONIC__)
1126279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  void* handle = dlopen("libtest_dlopen_from_ctor_main.so", RTLD_NOW);
1127279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
1128279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  dlclose(handle);
1129279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov#else
1130279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov  GTEST_LOG_(INFO) << "This test is disabled for glibc (glibc segfaults if you try to call dlopen from a constructor).\n";
1131279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov#endif
1132279a22f96e639e76c801bdb39aee5576f2280fe0Dmitriy Ivanov}
11332a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
1134ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanovstatic std::string g_fini_call_order_str;
1135ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov
1136ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanovstatic void register_fini_call(const char* s) {
1137ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  g_fini_call_order_str += s;
1138ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov}
1139ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov
1140ec90e24d33837e107b45e7c98b2f5fb4bc115a5eDimitry Ivanovstatic void test_init_fini_call_order_for(const char* libname) {
1141ec90e24d33837e107b45e7c98b2f5fb4bc115a5eDimitry Ivanov  g_fini_call_order_str.clear();
1142ec90e24d33837e107b45e7c98b2f5fb4bc115a5eDimitry Ivanov  void* handle = dlopen(libname, RTLD_NOW);
1143ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
1144ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  typedef int (*get_init_order_number_t)();
1145ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  get_init_order_number_t get_init_order_number =
1146ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov          reinterpret_cast<get_init_order_number_t>(dlsym(handle, "get_init_order_number"));
1147ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  ASSERT_EQ(321, get_init_order_number());
1148ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov
1149ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  typedef void (*set_fini_callback_t)(void (*f)(const char*));
1150ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  set_fini_callback_t set_fini_callback =
1151ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov          reinterpret_cast<set_fini_callback_t>(dlsym(handle, "set_fini_callback"));
1152ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  set_fini_callback(register_fini_call);
1153ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  dlclose(handle);
1154ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov  ASSERT_EQ("(root)(child)(grandchild)", g_fini_call_order_str);
1155ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov}
1156ea8f396c59f824993044d9474c2dc04423003c59Dimitry Ivanov
1157ec90e24d33837e107b45e7c98b2f5fb4bc115a5eDimitry IvanovTEST(dlfcn, init_fini_call_order) {
1158ec90e24d33837e107b45e7c98b2f5fb4bc115a5eDimitry Ivanov  test_init_fini_call_order_for("libtest_init_fini_order_root.so");
1159ec90e24d33837e107b45e7c98b2f5fb4bc115a5eDimitry Ivanov  test_init_fini_call_order_for("libtest_init_fini_order_root2.so");
1160ec90e24d33837e107b45e7c98b2f5fb4bc115a5eDimitry Ivanov}
1161ec90e24d33837e107b45e7c98b2f5fb4bc115a5eDimitry Ivanov
11622a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovTEST(dlfcn, symbol_versioning_use_v1) {
11632a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  void* handle = dlopen("libtest_versioned_uselibv1.so", RTLD_NOW);
11642a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
11652a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  typedef int (*fn_t)();
11662a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
11672a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
11682a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_EQ(1, fn());
11692a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  dlclose(handle);
11702a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
11712a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
11722a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovTEST(dlfcn, symbol_versioning_use_v2) {
11732a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  void* handle = dlopen("libtest_versioned_uselibv2.so", RTLD_NOW);
11742a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
11752a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  typedef int (*fn_t)();
11762a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
11772a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
11782a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_EQ(2, fn());
11792a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  dlclose(handle);
11802a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
11812a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
11822a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovTEST(dlfcn, symbol_versioning_use_other_v2) {
11832a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  void* handle = dlopen("libtest_versioned_uselibv2_other.so", RTLD_NOW);
11842a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
11852a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  typedef int (*fn_t)();
11862a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
11872a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
11882a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_EQ(20, fn());
11892a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  dlclose(handle);
11902a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
11912a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
11922a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovTEST(dlfcn, symbol_versioning_use_other_v3) {
11932a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  void* handle = dlopen("libtest_versioned_uselibv3_other.so", RTLD_NOW);
11942a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
11952a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  typedef int (*fn_t)();
11962a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
11972a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
11982a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_EQ(3, fn());
11992a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  dlclose(handle);
12002a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
12012a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
12022a815361448d01b0f4e575f507ce31913214c536Dmitriy IvanovTEST(dlfcn, symbol_versioning_default_via_dlsym) {
12032a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  void* handle = dlopen("libtest_versioned_lib.so", RTLD_NOW);
12042a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
12052a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  typedef int (*fn_t)();
12062a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "versioned_function"));
12072a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_TRUE(fn != nullptr) << dlerror();
12082a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  ASSERT_EQ(3, fn()); // the default version is 3
12092a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  dlclose(handle);
12102a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
12112a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
12129cf99cbad89c8495828788ce693a99ced434f66fDimitry IvanovTEST(dlfcn, dlvsym_smoke) {
12139cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  void* handle = dlopen("libtest_versioned_lib.so", RTLD_NOW);
12149cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  ASSERT_TRUE(handle != nullptr) << dlerror();
12159cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  typedef int (*fn_t)();
12169cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov
12179cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  {
12189cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov    fn_t fn = reinterpret_cast<fn_t>(dlvsym(handle, "versioned_function", "nonversion"));
12199cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov    ASSERT_TRUE(fn == nullptr);
12209cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov    ASSERT_SUBSTR("undefined symbol: versioned_function, version nonversion", dlerror());
12219cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  }
12229cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov
12239cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  {
12249cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov    fn_t fn = reinterpret_cast<fn_t>(dlvsym(handle, "versioned_function", "TESTLIB_V2"));
12259cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov    ASSERT_TRUE(fn != nullptr) << dlerror();
12269cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov    ASSERT_EQ(2, fn());
12279cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  }
12289cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov
12299cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov  dlclose(handle);
12309cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov}
12319cf99cbad89c8495828788ce693a99ced434f66fDimitry Ivanov
12322a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov// This preempts the implementation from libtest_versioned_lib.so
12332a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovextern "C" int version_zero_function() {
12342a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return 0;
12352a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
12362a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov
12372a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov// This preempts the implementation from libtest_versioned_uselibv*.so
12382a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanovextern "C" int version_zero_function2() {
12392a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov  return 0;
12402a815361448d01b0f4e575f507ce31913214c536Dmitriy Ivanov}
12416865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov
12426f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar TrsicTEST(dlfcn, dt_runpath_smoke) {
12436865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov  void* handle = dlopen("libtest_dt_runpath_d.so", RTLD_NOW);
12446865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov  ASSERT_TRUE(handle != nullptr) << dlerror();
12456865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov
12466865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov  typedef void *(* dlopen_b_fn)();
12476865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov  dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
12486865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov  ASSERT_TRUE(fn != nullptr) << dlerror();
12496865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov
12506865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov  void *p = fn();
12510cdef7e7f3c6837b56a969120d9098463d1df8d8Evgenii Stepanov  ASSERT_TRUE(p != nullptr);
12526865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov
12536865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov  dlclose(handle);
12546865082ca6d887766c6651ed2d079dca56a99d32Evgenii Stepanov}
12556f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar Trsic
1256a36e59bb9973aaae2e3487e0bfadd1f79814097eDimitry Ivanov// Bionic specific tests
1257a36e59bb9973aaae2e3487e0bfadd1f79814097eDimitry Ivanov#if defined(__BIONIC__)
1258a36e59bb9973aaae2e3487e0bfadd1f79814097eDimitry Ivanov
1259fc32dcb128efe35442830e2dcfa378f1d50fef1cDimitry Ivanov#if defined(__arm__)
1260ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanovconst llvm::ELF::Elf32_Dyn* to_dynamic_table(const char* p) {
1261ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  return reinterpret_cast<const llvm::ELF::Elf32_Dyn*>(p);
1262ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov}
1263ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
1264ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov// Duplicate these definitions here because they are android specific
1265ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov// note that we cannot include <elf.h> because #defines conflict with
1266ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov// enum names provided by LLVM.
1267ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#define DT_ANDROID_REL (llvm::ELF::DT_LOOS + 2)
1268ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov#define DT_ANDROID_RELA (llvm::ELF::DT_LOOS + 4)
1269ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
1270ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanovtemplate<typename ELFT>
1271ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanovvoid validate_compatibility_of_native_library(const std::string& path, ELFT* elf) {
1272ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  bool has_elf_hash = false;
1273ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  bool has_android_rel = false;
1274ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  bool has_rel = false;
1275ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  // Find dynamic section and check that DT_HASH and there is no DT_ANDROID_REL
1276ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
1277ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov    const llvm::object::ELFSectionRef& section_ref = *it;
1278ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov    if (section_ref.getType() == llvm::ELF::SHT_DYNAMIC) {
1279ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov      llvm::StringRef data;
1280ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov      ASSERT_TRUE(!it->getContents(data)) << "unable to get SHT_DYNAMIC section data";
1281ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov      for (auto d = to_dynamic_table(data.data()); d->d_tag != llvm::ELF::DT_NULL; ++d) {
1282ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov        if (d->d_tag == llvm::ELF::DT_HASH) {
1283ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov          has_elf_hash = true;
1284ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov        } else if (d->d_tag == DT_ANDROID_REL || d->d_tag == DT_ANDROID_RELA) {
1285ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov          has_android_rel = true;
1286ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov        } else if (d->d_tag == llvm::ELF::DT_REL || d->d_tag == llvm::ELF::DT_RELA) {
1287ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov          has_rel = true;
1288ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov        }
1289ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov      }
1290ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
1291ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov      break;
1292ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov    }
1293ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  }
1294ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
1295ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  ASSERT_TRUE(has_elf_hash) << path.c_str() << ": missing elf hash (DT_HASH)";
1296ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  ASSERT_TRUE(!has_android_rel) << path.c_str() << ": has packed relocations";
1297ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  ASSERT_TRUE(has_rel) << path.c_str() << ": missing DT_REL/DT_RELA";
1298ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov}
1299ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
1300ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanovvoid validate_compatibility_of_native_library(const char* soname) {
130114b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko  // On the systems with emulation system libraries would be of different
130214b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko  // architecture.  Try to use alternate paths first.
130314b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko  std::string path = std::string(ALTERNATE_PATH_TO_SYSTEM_LIB) + soname;
1304ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  auto binary_or_error = llvm::object::createBinary(path);
130514b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko  if (!binary_or_error) {
130614b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko    path = std::string(PATH_TO_SYSTEM_LIB) + soname;
130714b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko    binary_or_error = llvm::object::createBinary(path);
130814b9d7199c1b147ef6ce6e522ff14413930d2127Victor Khimenko  }
1309ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  ASSERT_FALSE(!binary_or_error);
1310ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
1311ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  llvm::object::Binary* binary = binary_or_error.get().getBinary();
1312ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
1313ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  auto obj = llvm::dyn_cast<llvm::object::ObjectFile>(binary);
1314ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  ASSERT_TRUE(obj != nullptr);
1315ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
1316ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj);
1317ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
1318ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  ASSERT_TRUE(elf != nullptr);
1319ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
1320ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  validate_compatibility_of_native_library(path, elf);
1321ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov}
1322ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
1323fc32dcb128efe35442830e2dcfa378f1d50fef1cDimitry Ivanov// This is a test for app compatibility workaround for arm apps
1324ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov// affected by http://b/24465209
1325ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry IvanovTEST(dlext, compat_elf_hash_and_relocation_tables) {
1326ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  validate_compatibility_of_native_library("libc.so");
1327ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  validate_compatibility_of_native_library("liblog.so");
1328ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  validate_compatibility_of_native_library("libstdc++.so");
1329ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  validate_compatibility_of_native_library("libdl.so");
1330ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  validate_compatibility_of_native_library("libm.so");
1331ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  validate_compatibility_of_native_library("libz.so");
1332ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov  validate_compatibility_of_native_library("libjnigraphics.so");
1333ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov}
1334ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
1335fc32dcb128efe35442830e2dcfa378f1d50fef1cDimitry Ivanov#endif //  defined(__arm__)
1336ac4bd2f79316e8ee79e9a69463e5d12d0f792aadDimitry Ivanov
13376f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar TrsicTEST(dlfcn, dt_runpath_absolute_path) {
1338d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  std::string libpath = get_testlib_root() + "/libtest_dt_runpath_d.so";
1339a36e59bb9973aaae2e3487e0bfadd1f79814097eDimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
13406f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar Trsic  ASSERT_TRUE(handle != nullptr) << dlerror();
13416f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar Trsic
13426f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar Trsic  typedef void *(* dlopen_b_fn)();
13436f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar Trsic  dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
13446f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar Trsic  ASSERT_TRUE(fn != nullptr) << dlerror();
13456f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar Trsic
13466f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar Trsic  void *p = fn();
13476f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar Trsic  ASSERT_TRUE(p != nullptr);
13486f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar Trsic
13496f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar Trsic  dlclose(handle);
13506f2d3104c82f81c1f0123a3cfb25ae670841d0baLazar Trsic}
13519700babc051f5839b4fc861587d63bf06bab6324Dimitry Ivanov
13529700babc051f5839b4fc861587d63bf06bab6324Dimitry IvanovTEST(dlfcn, dlopen_invalid_rw_load_segment) {
1353d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1354927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/" + kPrebuiltElfDir +
1355927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/libtest_invalid-rw_load_segment.so";
13569700babc051f5839b4fc861587d63bf06bab6324Dimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
13579700babc051f5839b4fc861587d63bf06bab6324Dimitry Ivanov  ASSERT_TRUE(handle == nullptr);
13589700babc051f5839b4fc861587d63bf06bab6324Dimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\": W + E load segments are not allowed";
13599700babc051f5839b4fc861587d63bf06bab6324Dimitry Ivanov  ASSERT_STREQ(expected_dlerror.c_str(), dlerror());
13609700babc051f5839b4fc861587d63bf06bab6324Dimitry Ivanov}
1361972e3d0787cf177450cdc1b52e177c747b94cabaDimitry Ivanov
1362972e3d0787cf177450cdc1b52e177c747b94cabaDimitry IvanovTEST(dlfcn, dlopen_invalid_unaligned_shdr_offset) {
1363d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1364927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/" + kPrebuiltElfDir +
1365927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/libtest_invalid-unaligned_shdr_offset.so";
1366927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov
1367972e3d0787cf177450cdc1b52e177c747b94cabaDimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1368972e3d0787cf177450cdc1b52e177c747b94cabaDimitry Ivanov  ASSERT_TRUE(handle == nullptr);
1369972e3d0787cf177450cdc1b52e177c747b94cabaDimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has invalid shdr offset/size: ";
1370972e3d0787cf177450cdc1b52e177c747b94cabaDimitry Ivanov  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1371972e3d0787cf177450cdc1b52e177c747b94cabaDimitry Ivanov}
1372972e3d0787cf177450cdc1b52e177c747b94cabaDimitry Ivanov
1373cb86c3128f5e59348d91f2edfa2de908d69cd384Dimitry IvanovTEST(dlfcn, dlopen_invalid_zero_shentsize) {
1374d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1375927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/" + kPrebuiltElfDir +
1376927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/libtest_invalid-zero_shentsize.so";
1377927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov
1378cb86c3128f5e59348d91f2edfa2de908d69cd384Dimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1379cb86c3128f5e59348d91f2edfa2de908d69cd384Dimitry Ivanov  ASSERT_TRUE(handle == nullptr);
1380cb86c3128f5e59348d91f2edfa2de908d69cd384Dimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has unsupported e_shentsize: 0x0 (expected 0x";
1381cb86c3128f5e59348d91f2edfa2de908d69cd384Dimitry Ivanov  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1382cb86c3128f5e59348d91f2edfa2de908d69cd384Dimitry Ivanov}
1383cb86c3128f5e59348d91f2edfa2de908d69cd384Dimitry Ivanov
1384c9a95613a95b1a275ff897594abb89786ae387edDimitry IvanovTEST(dlfcn, dlopen_invalid_zero_shstrndx) {
1385d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1386927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/" + kPrebuiltElfDir +
1387927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/libtest_invalid-zero_shstrndx.so";
1388927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov
1389c9a95613a95b1a275ff897594abb89786ae387edDimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1390c9a95613a95b1a275ff897594abb89786ae387edDimitry Ivanov  ASSERT_TRUE(handle == nullptr);
1391c9a95613a95b1a275ff897594abb89786ae387edDimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has invalid e_shstrndx";
1392c9a95613a95b1a275ff897594abb89786ae387edDimitry Ivanov  ASSERT_STREQ(expected_dlerror.c_str(), dlerror());
1393c9a95613a95b1a275ff897594abb89786ae387edDimitry Ivanov}
1394c9a95613a95b1a275ff897594abb89786ae387edDimitry Ivanov
13958bdf70e6e481d4ff0c1097f738d8e857a43c1b16Dimitry IvanovTEST(dlfcn, dlopen_invalid_empty_shdr_table) {
1396d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1397927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/" + kPrebuiltElfDir +
1398927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/libtest_invalid-empty_shdr_table.so";
1399927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov
14008bdf70e6e481d4ff0c1097f738d8e857a43c1b16Dimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
14018bdf70e6e481d4ff0c1097f738d8e857a43c1b16Dimitry Ivanov  ASSERT_TRUE(handle == nullptr);
14028bdf70e6e481d4ff0c1097f738d8e857a43c1b16Dimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has no section headers";
14038bdf70e6e481d4ff0c1097f738d8e857a43c1b16Dimitry Ivanov  ASSERT_STREQ(expected_dlerror.c_str(), dlerror());
14048bdf70e6e481d4ff0c1097f738d8e857a43c1b16Dimitry Ivanov}
14058bdf70e6e481d4ff0c1097f738d8e857a43c1b16Dimitry Ivanov
140646230445172d3cd72c38102d57f5a1b725c80367Dimitry IvanovTEST(dlfcn, dlopen_invalid_zero_shdr_table_offset) {
1407d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1408927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/" + kPrebuiltElfDir +
1409927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/libtest_invalid-zero_shdr_table_offset.so";
1410927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov
141146230445172d3cd72c38102d57f5a1b725c80367Dimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
141246230445172d3cd72c38102d57f5a1b725c80367Dimitry Ivanov  ASSERT_TRUE(handle == nullptr);
141346230445172d3cd72c38102d57f5a1b725c80367Dimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has invalid shdr offset/size: 0/";
141446230445172d3cd72c38102d57f5a1b725c80367Dimitry Ivanov  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
141546230445172d3cd72c38102d57f5a1b725c80367Dimitry Ivanov}
141646230445172d3cd72c38102d57f5a1b725c80367Dimitry Ivanov
1417559583469cd6425cdf3f63bcfc453d7d885ce131Dimitry IvanovTEST(dlfcn, dlopen_invalid_zero_shdr_table_content) {
1418d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1419927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/" + kPrebuiltElfDir +
1420927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov                              "/libtest_invalid-zero_shdr_table_content.so";
1421927877c7d3173c1259732e51428f4ae38dc6bc4fDimitry Ivanov
1422559583469cd6425cdf3f63bcfc453d7d885ce131Dimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1423559583469cd6425cdf3f63bcfc453d7d885ce131Dimitry Ivanov  ASSERT_TRUE(handle == nullptr);
1424559583469cd6425cdf3f63bcfc453d7d885ce131Dimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" .dynamic section header was not found";
1425559583469cd6425cdf3f63bcfc453d7d885ce131Dimitry Ivanov  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1426559583469cd6425cdf3f63bcfc453d7d885ce131Dimitry Ivanov}
1427559583469cd6425cdf3f63bcfc453d7d885ce131Dimitry Ivanov
1428816676e70da0e00761b0d23f512ea3571211b3aeDimitry IvanovTEST(dlfcn, dlopen_invalid_textrels) {
1429d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1430816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov                              "/" + kPrebuiltElfDir +
1431816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov                              "/libtest_invalid-textrels.so";
1432816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov
1433816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1434816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov  ASSERT_TRUE(handle == nullptr);
1435816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has text relocations";
1436816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1437816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov}
1438816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov
1439816676e70da0e00761b0d23f512ea3571211b3aeDimitry IvanovTEST(dlfcn, dlopen_invalid_textrels2) {
1440d0b5c3ad65accd2c0298edbdfd527ede63e68ba1Dimitry Ivanov  const std::string libpath = get_testlib_root() +
1441816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov                              "/" + kPrebuiltElfDir +
1442816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov                              "/libtest_invalid-textrels2.so";
1443816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov
1444816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
1445816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov  ASSERT_TRUE(handle == nullptr);
1446816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\" has text relocations";
1447816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov  ASSERT_SUBSTR(expected_dlerror.c_str(), dlerror());
1448816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov}
1449816676e70da0e00761b0d23f512ea3571211b3aeDimitry Ivanov
14509700babc051f5839b4fc861587d63bf06bab6324Dimitry Ivanov#endif
1451