diff --git a/linker/Android.mk b/linker/Android.mk index a962c760b..585a73809 100644 --- a/linker/Android.mk +++ b/linker/Android.mk @@ -12,6 +12,7 @@ LOCAL_SRC_FILES:= \ linker_libc_support.c \ linker_memory.cpp \ linker_phdr.cpp \ + linker_utils.cpp \ rt.cpp \ LOCAL_SRC_FILES_arm := arch/arm/begin.S diff --git a/linker/linker.cpp b/linker/linker.cpp index 3e59218b8..39f618d89 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -58,6 +58,7 @@ #include "linker_phdr.h" #include "linker_relocs.h" #include "linker_reloc_iterators.h" +#include "linker_utils.h" #include "base/strings.h" #include "ziparchive/zip_archive.h" @@ -360,13 +361,13 @@ static void parse_LD_PRELOAD(const char* path) { static bool realpath_fd(int fd, std::string* realpath) { std::vector buf(PATH_MAX), proc_self_fd(PATH_MAX); - snprintf(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd); + __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd); if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) { PRINT("readlink('%s') failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd); return false; } - *realpath = std::string(&buf[0]); + *realpath = &buf[0]; return true; } @@ -1165,15 +1166,21 @@ ZipArchiveCache::~ZipArchiveCache() { } static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache, - const char* const path, - off64_t* file_offset) { - TRACE("Trying zip file open from path '%s'", path); + const char* const input_path, + off64_t* file_offset, std::string* realpath) { + std::string normalized_path; + if (!normalize_path(input_path, &normalized_path)) { + return -1; + } + + const char* const path = normalized_path.c_str(); + TRACE("Trying zip file open from path '%s' -> normalized '%s'", input_path, path); // Treat an '!/' separator inside a path as the separator between the name // of the zip file on disk and the subdirectory to search within it. // For example, if path is "foo.zip!/bar/bas/x.so", then we search for // "bar/bas/x.so" within "foo.zip". - const char* separator = strstr(path, kZipFileSeparator); + const char* const separator = strstr(path, kZipFileSeparator); if (separator == nullptr) { return -1; } @@ -1215,6 +1222,15 @@ static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache, } *file_offset = entry.offset; + + if (realpath_fd(fd, realpath)) { + *realpath += separator; + } else { + PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", + normalized_path.c_str()); + *realpath = normalized_path; + } + return fd; } @@ -1228,7 +1244,7 @@ static bool format_path(char* buf, size_t buf_size, const char* path, const char return true; } -static int open_library_on_default_path(const char* name, off64_t* file_offset) { +static int open_library_on_default_path(const char* name, off64_t* file_offset, std::string* realpath) { for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) { char buf[512]; if (!format_path(buf, sizeof(buf), g_default_ld_paths[i], name)) { @@ -1238,6 +1254,10 @@ static int open_library_on_default_path(const char* name, off64_t* file_offset) int fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC)); if (fd != -1) { *file_offset = 0; + if (!realpath_fd(fd, realpath)) { + PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf); + *realpath = buf; + } return fd; } } @@ -1247,7 +1267,8 @@ static int open_library_on_default_path(const char* name, off64_t* file_offset) static int open_library_on_paths(ZipArchiveCache* zip_archive_cache, const char* name, off64_t* file_offset, - const std::vector& paths) { + const std::vector& paths, + std::string* realpath) { for (const auto& path_str : paths) { char buf[512]; const char* const path = path_str.c_str(); @@ -1257,13 +1278,17 @@ static int open_library_on_paths(ZipArchiveCache* zip_archive_cache, int fd = -1; if (strstr(buf, kZipFileSeparator) != nullptr) { - fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset); + fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath); } if (fd == -1) { fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC)); if (fd != -1) { *file_offset = 0; + if (!realpath_fd(fd, realpath)) { + PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf); + *realpath = buf; + } } } @@ -1277,13 +1302,13 @@ static int open_library_on_paths(ZipArchiveCache* zip_archive_cache, static int open_library(ZipArchiveCache* zip_archive_cache, const char* name, soinfo *needed_by, - off64_t* file_offset) { + off64_t* file_offset, std::string* realpath) { TRACE("[ opening %s ]", name); // If the name contains a slash, we should attempt to open it directly and not search the paths. if (strchr(name, '/') != nullptr) { if (strstr(name, kZipFileSeparator) != nullptr) { - int fd = open_library_in_zipfile(zip_archive_cache, name, file_offset); + int fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath); if (fd != -1) { return fd; } @@ -1297,13 +1322,13 @@ static int open_library(ZipArchiveCache* zip_archive_cache, } // Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths. - int fd = open_library_on_paths(zip_archive_cache, name, file_offset, g_ld_library_paths); + int fd = open_library_on_paths(zip_archive_cache, name, file_offset, g_ld_library_paths, realpath); if (fd == -1 && needed_by) { - fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath()); + fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath); } if (fd == -1) { - fd = open_library_on_default_path(name, file_offset); + fd = open_library_on_default_path(name, file_offset, realpath); } return fd; @@ -1336,7 +1361,8 @@ static void for_each_dt_needed(const soinfo* si, F action) { static soinfo* load_library(int fd, off64_t file_offset, LoadTaskList& load_tasks, const char* name, int rtld_flags, - const android_dlextinfo* extinfo) { + const android_dlextinfo* extinfo, + const std::string& realpath) { if ((file_offset % PAGE_SIZE) != 0) { DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset); return nullptr; @@ -1378,12 +1404,6 @@ static soinfo* load_library(int fd, off64_t file_offset, return nullptr; } - std::string realpath = name; - if (!realpath_fd(fd, &realpath)) { - PRINT("warning: unable to get realpath for the library \"%s\". Will use given name.", name); - realpath = name; - } - // Read the ELF header and load the segments. ElfReader elf_reader(realpath.c_str(), fd, file_offset, file_stat.st_size); if (!elf_reader.Load(extinfo)) { @@ -1416,22 +1436,29 @@ static soinfo* load_library(ZipArchiveCache* zip_archive_cache, LoadTaskList& load_tasks, const char* name, soinfo* needed_by, int rtld_flags, const android_dlextinfo* extinfo) { + off64_t file_offset; + std::string realpath; if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { - off64_t file_offset = 0; + file_offset = 0; if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) { file_offset = extinfo->library_fd_offset; } - return load_library(extinfo->library_fd, file_offset, load_tasks, name, rtld_flags, extinfo); + + if (!realpath_fd(extinfo->library_fd, &realpath)) { + PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. " + "Will use given name.", name); + realpath = name; + } + return load_library(extinfo->library_fd, file_offset, load_tasks, name, rtld_flags, extinfo, realpath); } // Open the file. - off64_t file_offset; - int fd = open_library(zip_archive_cache, name, needed_by, &file_offset); + int fd = open_library(zip_archive_cache, name, needed_by, &file_offset, &realpath); if (fd == -1) { DL_ERR("library \"%s\" not found", name); return nullptr; } - soinfo* result = load_library(fd, file_offset, load_tasks, name, rtld_flags, extinfo); + soinfo* result = load_library(fd, file_offset, load_tasks, name, rtld_flags, extinfo, realpath); close(fd); return result; } diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp new file mode 100644 index 000000000..5d39d835f --- /dev/null +++ b/linker/linker_utils.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "linker_utils.h" +#include "linker_debug.h" + +bool normalize_path(const char* path, std::string* normalized_path) { + // Input should be an absolute path + if (path[0] != '/') { + PRINT("canonize_path - invalid input: '%s', the input path should be absolute", path); + return false; + } + + const size_t len = strlen(path) + 1; + char buf[len]; + + const char* in_ptr = path; + char* out_ptr = buf; + + while (*in_ptr != 0) { + if (*in_ptr == '/') { + char c1 = in_ptr[1]; + if (c1 == '.') { + char c2 = in_ptr[2]; + if (c2 == '/') { + in_ptr += 2; + continue; + } else if (c2 == '.' && (in_ptr[3] == '/' || in_ptr[3] == 0)) { + in_ptr += 3; + while (out_ptr > buf && *--out_ptr != '/') { + } + if (in_ptr[0] == 0) { + // retain '/' + out_ptr++; + } + continue; + } + } else if (c1 == '/') { + ++in_ptr; + continue; + } + } + *out_ptr++ = *in_ptr++; + } + + *out_ptr = 0; + *normalized_path = buf; + return true; +} + diff --git a/linker/linker_utils.h b/linker/linker_utils.h new file mode 100644 index 000000000..fc79fd193 --- /dev/null +++ b/linker/linker_utils.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __LINKER_UTILS_H +#define __LINKER_UTILS_H + +#include + +bool normalize_path(const char* path, std::string* normalized_path); + +#endif diff --git a/linker/tests/Android.mk b/linker/tests/Android.mk index 0aaee3e40..a0618771f 100644 --- a/linker/tests/Android.mk +++ b/linker/tests/Android.mk @@ -27,11 +27,14 @@ LOCAL_CFLAGS += -g -Wall -Wextra -Wunused -Werror LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../libc/ LOCAL_SRC_FILES := \ + linker_globals.cpp \ linked_list_test.cpp \ linker_block_allocator_test.cpp \ ../linker_block_allocator.cpp \ linker_memory_allocator_test.cpp \ - ../linker_allocator.cpp + ../linker_allocator.cpp \ + linker_utils_test.cpp \ + ../linker_utils.cpp # for __libc_fatal LOCAL_SRC_FILES += ../../libc/bionic/libc_logging.cpp diff --git a/linker/tests/linker_globals.cpp b/linker/tests/linker_globals.cpp new file mode 100644 index 000000000..7762a87ce --- /dev/null +++ b/linker/tests/linker_globals.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// To enable logging +int g_ld_debug_verbosity = 0; + diff --git a/linker/tests/linker_utils_test.cpp b/linker/tests/linker_utils_test.cpp new file mode 100644 index 000000000..458474eed --- /dev/null +++ b/linker/tests/linker_utils_test.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include "../linker_utils.h" + +TEST(linker_utils, normalize_path_smoke) { + std::string output; + ASSERT_TRUE(normalize_path("/../root///dir/.///dir2/somedir/../zipfile!/dir/dir9//..///afile", &output)); + ASSERT_EQ("/root/dir/dir2/zipfile!/dir/afile", output); + + ASSERT_TRUE(normalize_path("/../root///dir/.///dir2/somedir/.../zipfile!/.dir/dir9//..///afile", &output)); + ASSERT_EQ("/root/dir/dir2/somedir/.../zipfile!/.dir/afile", output); + + ASSERT_TRUE(normalize_path("/root/..", &output)); + ASSERT_EQ("/", output); + + ASSERT_TRUE(normalize_path("/root/notroot/..", &output)); + ASSERT_EQ("/root/", output); + + ASSERT_TRUE(normalize_path("/a/../../b", &output)); + ASSERT_EQ("/b", output); + + output = "unchanged"; + ASSERT_FALSE(normalize_path("root///dir/.///dir2/somedir/../zipfile!/dir/dir9//..///afile", &output)); + ASSERT_EQ("unchanged", output); +} diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp index 9d8b71d0a..d5a5e562b 100644 --- a/tests/dlext_test.cpp +++ b/tests/dlext_test.cpp @@ -59,6 +59,7 @@ typedef int (*fn)(void); #define LIBPATH LIBPATH_PREFIX "libdlext_test_fd/libdlext_test_fd.so" #define LIBZIPPATH LIBPATH_PREFIX "libdlext_test_zip/libdlext_test_zip_zipaligned.zip" +#define LIBZIPPATH_WITH_RUNPATH LIBPATH_PREFIX "libdlext_test_runpath_zip/libdlext_test_runpath_zip_zipaligned.zip" #define LIBZIP_OFFSET PAGE_SIZE @@ -228,6 +229,24 @@ TEST(dlfcn, dlopen_from_zip_absolute_path) { dlclose(handle); } +TEST(dlfcn, dlopen_from_zip_with_dt_runpath) { + const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH_WITH_RUNPATH; + + void* handle = dlopen((lib_path + "!/libdir/libtest_dt_runpath_d_zip.so").c_str(), RTLD_NOW); + + ASSERT_TRUE(handle != nullptr) << dlerror(); + + typedef void *(* dlopen_b_fn)(); + dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b"); + ASSERT_TRUE(fn != nullptr) << dlerror(); + + void *p = fn(); + ASSERT_TRUE(p != nullptr) << dlerror(); + + dlclose(p); + dlclose(handle); +} + TEST(dlfcn, dlopen_from_zip_ld_library_path) { const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH + "!/libdir"; diff --git a/tests/libs/Android.build.dlext_testzip.mk b/tests/libs/Android.build.dlext_testzip.mk index 93df21369..c06f4a9bc 100644 --- a/tests/libs/Android.build.dlext_testzip.mk +++ b/tests/libs/Android.build.dlext_testzip.mk @@ -34,8 +34,49 @@ my_shared_libs := \ $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libatest_simple_zip.so $(LOCAL_BUILT_MODULE) : $(my_shared_libs) | $(ZIPALIGN) - @echo "Zipalign $(PRIVATE_ALIGNMENT): $@" + @echo "Zipalign: $@" $(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)/libdir $(hide) cp $^ $(dir $@)/libdir $(hide) (cd $(dir $@) && touch empty_file.txt && zip -qrD0 $(notdir $@).unaligned empty_file.txt libdir/*.so) $(hide) $(ZIPALIGN) -p 4 $@.unaligned $@ + +include $(CLEAR_VARS) + +LOCAL_MODULE_CLASS := SHARED_LIBRARIES +LOCAL_MODULE := libdlext_test_runpath_zip_zipaligned +LOCAL_MODULE_SUFFIX := .zip +LOCAL_MODULE_TAGS := tests +LOCAL_MODULE_PATH := $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/libdlext_test_runpath_zip +LOCAL_2ND_ARCH_VAR_PREFIX := $(bionic_2nd_arch_prefix) + +include $(BUILD_SYSTEM)/base_rules.mk +my_shared_libs := \ + $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_d_zip.so \ + $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_b.so \ + $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_a.so \ + $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_c.so \ + $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_x.so + + +$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_D := \ + $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_d_zip.so +$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_A := \ + $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_a.so +$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_B := \ + $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_b.so +$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_C := \ + $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_c.so +$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_X := \ + $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_x.so +$(LOCAL_BUILT_MODULE) : $(my_shared_libs) | $(ZIPALIGN) + @echo "Zipalign: $@" + $(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)/libdir && \ + mkdir -p $(dir $@)/libdir/dt_runpath_a && mkdir -p $(dir $@)/libdir/dt_runpath_b_c_x + $(hide) cp $(PRIVATE_LIB_D) $(dir $@)/libdir + $(hide) cp $(PRIVATE_LIB_A) $(dir $@)/libdir/dt_runpath_a + $(hide) cp $(PRIVATE_LIB_B) $(dir $@)/libdir/dt_runpath_b_c_x + $(hide) cp $(PRIVATE_LIB_C) $(dir $@)/libdir/dt_runpath_b_c_x + $(hide) cp $(PRIVATE_LIB_X) $(dir $@)/libdir/dt_runpath_b_c_x + $(hide) (cd $(dir $@) && touch empty_file.txt && zip -qrD0 $(notdir $@).unaligned empty_file.txt libdir) + $(hide) $(ZIPALIGN) -p 4 $@.unaligned $@ + diff --git a/tests/libs/Android.build.dt_runpath.mk b/tests/libs/Android.build.dt_runpath.mk index 44c8125bb..4544bb151 100644 --- a/tests/libs/Android.build.dt_runpath.mk +++ b/tests/libs/Android.build.dt_runpath.mk @@ -18,6 +18,19 @@ # Libraries used by dt_runpath tests. # ----------------------------------------------------------------------------- +# +# Dependencies +# +# libtest_dt_runpath_d.so runpath: ${ORIGIN}/dt_runpath_b_c_x +# |-> dt_runpath_b_c_x/libtest_dt_runpath_b.so runpath: ${ORIGIN}/../dt_runpath_a +# | |-> dt_runpath_a/libtest_dt_runpath_a.so +# |-> dt_runpath_b_c_x/libtest_dt_runpath_c.so runpath: ${ORIGIN}/invalid_dt_runpath +# | |-> libtest_dt_runpath_a.so (soname) +# +# This one is used to test dlopen +# dt_runpath_b_c_x/libtest_dt_runpath_x.so +# + # A leaf library in a non-standard directory. libtest_dt_runpath_a_src_files := \ empty.cpp @@ -57,6 +70,20 @@ libtest_dt_runpath_d_ldflags := -Wl,--rpath,\$${ORIGIN}/dt_runpath_b_c_x -Wl,--e module := libtest_dt_runpath_d include $(LOCAL_PATH)/Android.build.testlib.mk +# D version for open-from-zip test with runpath +libtest_dt_runpath_d_zip_src_files := \ + dlopen_b.cpp + +libtest_dt_runpath_d_zip_shared_libraries := libtest_dt_runpath_b libtest_dt_runpath_c +libtest_dt_runpath_d_zip_ldflags := -Wl,--rpath,\$${ORIGIN}/dt_runpath_b_c_x -Wl,--enable-new-dtags +libtest_dt_runpath_d_zip_install_to_out_data := true +module := libtest_dt_runpath_d_zip +module_tag := optional +build_type := target +build_target := SHARED_LIBRARY +include $(TEST_PATH)/Android.build.mk + + # A leaf library in a directory library D has DT_RUNPATH for. libtest_dt_runpath_x_src_files := \ empty.cpp @@ -64,3 +91,4 @@ libtest_dt_runpath_x_src_files := \ libtest_dt_runpath_x_relative_path := dt_runpath_b_c_x module := libtest_dt_runpath_x include $(LOCAL_PATH)/Android.build.testlib.mk + diff --git a/tests/libs/dlopen_b.cpp b/tests/libs/dlopen_b.cpp index 5291d81fa..cd81e16c1 100644 --- a/tests/libs/dlopen_b.cpp +++ b/tests/libs/dlopen_b.cpp @@ -4,8 +4,9 @@ extern "C" void *dlopen_b() { // remove once it is fixed static int dummy = 0; - // This is not supposed to succeed. Even though this library has DT_RUNPATH - // for libtest_dt_runpath_x.so, it is not taked into account for dlopen. + // This is supposed to succeed because this library has DT_RUNPATH + // for libtest_dt_runpath_x.so which should be taken into account + // by dlopen. void *handle = dlopen("libtest_dt_runpath_x.so", RTLD_NOW); if (handle != nullptr) { dummy++;