Fix bionic-unit-tests-glibc

Also add another test for dlsym(RTLD_NEXT, ..)

Bug: http://b/33106624
Test: run bionic-unit-tests-glibc and bionic-unit-tests
Change-Id: I340165d66bf2360b0e3273d3561a08cb5e7bd025
diff --git a/tests/Android.bp b/tests/Android.bp
index 3e1e13b..688d8e1 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -476,7 +476,10 @@
 
     include_dirs: ["bionic/libc"],
 
-    ldflags: ["-Wl,--export-dynamic"],
+    ldflags: [
+        "-Wl,--rpath,${ORIGIN}/../bionic-loader-test-libs",
+        "-Wl,--export-dynamic",
+    ],
 
     sanitize: {
         never: false,
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index ed50ea5..e629e41 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -98,7 +98,7 @@
 }
 
 TEST_F(DlExtTest, ExtInfoUseFd) {
-  const std::string lib_path = g_testlib_root + "/libdlext_test_fd/libdlext_test_fd.so";
+  const std::string lib_path = get_testlib_root() + "/libdlext_test_fd/libdlext_test_fd.so";
 
   android_dlextinfo extinfo;
   extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD;
@@ -116,7 +116,7 @@
 }
 
 TEST_F(DlExtTest, ExtInfoUseFdWithOffset) {
-  const std::string lib_path = g_testlib_root + "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
+  const std::string lib_path = get_testlib_root() + "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
 
   android_dlextinfo extinfo;
   extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
@@ -142,7 +142,7 @@
 }
 
 TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) {
-  const std::string lib_path = g_testlib_root + "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
+  const std::string lib_path = get_testlib_root() + "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
 
   android_dlextinfo extinfo;
   extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
@@ -228,7 +228,7 @@
 
 TEST(dlfcn, dlopen_from_zip_absolute_path) {
   const std::string lib_zip_path = "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
-  const std::string lib_path = g_testlib_root + lib_zip_path;
+  const std::string lib_path = get_testlib_root() + lib_zip_path;
 
   void* handle = dlopen((lib_path + "!/libdir/libatest_simple_zip.so").c_str(), RTLD_NOW);
   ASSERT_TRUE(handle != nullptr) << dlerror();
@@ -242,7 +242,7 @@
 
 TEST(dlfcn, dlopen_from_zip_with_dt_runpath) {
   const std::string lib_zip_path = "/libdlext_test_runpath_zip/libdlext_test_runpath_zip_zipaligned.zip";
-  const std::string lib_path = g_testlib_root + lib_zip_path;
+  const std::string lib_path = get_testlib_root() + lib_zip_path;
 
   void* handle = dlopen((lib_path + "!/libdir/libtest_dt_runpath_d_zip.so").c_str(), RTLD_NOW);
 
@@ -261,7 +261,7 @@
 
 TEST(dlfcn, dlopen_from_zip_ld_library_path) {
   const std::string lib_zip_path = "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
-  const std::string lib_path = g_testlib_root + lib_zip_path + "!/libdir";
+  const std::string lib_path = get_testlib_root() + lib_zip_path + "!/libdir";
 
   typedef void (*fn_t)(const char*);
   fn_t android_update_LD_LIBRARY_PATH =
@@ -631,7 +631,7 @@
   ASSERT_STREQ("android_init_namespaces failed: error initializing public namespace: "
                "the list of public libraries is empty.", dlerror());
 
-  const std::string lib_public_path = g_testlib_root + "/public_namespace_libs/" + g_public_lib;
+  const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
   void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
   ASSERT_TRUE(handle_public != nullptr) << dlerror();
 
@@ -639,20 +639,20 @@
 
   // Check that libraries added to public namespace are NODELETE
   dlclose(handle_public);
-  handle_public = dlopen((g_testlib_root + "/public_namespace_libs/" + g_public_lib).c_str(),
+  handle_public = dlopen((get_testlib_root() + "/public_namespace_libs/" + g_public_lib).c_str(),
                          RTLD_NOW | RTLD_NOLOAD);
 
   ASSERT_TRUE(handle_public != nullptr) << dlerror();
 
   android_namespace_t* ns1 =
           android_create_namespace("private", nullptr,
-                                   (g_testlib_root + "/private_namespace_libs").c_str(),
+                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, nullptr);
   ASSERT_TRUE(ns1 != nullptr) << dlerror();
 
   android_namespace_t* ns2 =
           android_create_namespace("private_isolated", nullptr,
-                                   (g_testlib_root + "/private_namespace_libs").c_str(),
+                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED, nullptr, nullptr);
   ASSERT_TRUE(ns2 != nullptr) << dlerror();
 
@@ -743,7 +743,7 @@
   static const char* root_lib = "libnstest_root_not_isolated.so";
   std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
 
-  const std::string lib_public_path = g_testlib_root + "/public_namespace_libs/" + g_public_lib;
+  const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
   void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
   ASSERT_TRUE(handle_public != nullptr) << dlerror();
 
@@ -753,14 +753,14 @@
 
   android_namespace_t* ns_not_isolated =
           android_create_namespace("private", nullptr,
-                                   (g_testlib_root + "/private_namespace_libs").c_str(),
+                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, nullptr);
   ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
 
   android_namespace_t* ns_isolated =
           android_create_namespace("private_isolated1",
                                    nullptr,
-                                   (g_testlib_root + "/private_namespace_libs").c_str(),
+                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
                                    nullptr,
                                    nullptr);
@@ -768,10 +768,10 @@
 
   android_namespace_t* ns_isolated2 =
           android_create_namespace("private_isolated2",
-                                   (g_testlib_root + "/private_namespace_libs").c_str(),
+                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
                                    nullptr,
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
-                                   g_testlib_root.c_str(),
+                                   get_testlib_root().c_str(),
                                    nullptr);
   ASSERT_TRUE(ns_isolated2 != nullptr) << dlerror();
 
@@ -779,7 +779,7 @@
   ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror());
 
   std::string lib_private_external_path =
-      g_testlib_root + "/private_namespace_libs_external/libnstest_private_external.so";
+      get_testlib_root() + "/private_namespace_libs_external/libnstest_private_external.so";
 
   // Load lib_private_external_path to default namespace
   // (it should remain invisible for the isolated namespaces after this)
@@ -808,7 +808,7 @@
 
   extinfo.library_namespace = ns_isolated2;
 
-  // this should work because isolation_path for private_isolated2 includes g_testlib_root
+  // this should work because isolation_path for private_isolated2 includes get_testlib_root()
   handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
   ASSERT_TRUE(handle2 != nullptr) << dlerror();
   dlclose(handle2);
@@ -849,7 +849,7 @@
   static const char* root_lib_isolated = "libnstest_root.so";
   std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
 
-  const std::string lib_public_path = g_testlib_root + "/public_namespace_libs/" + g_public_lib;
+  const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
   void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
   ASSERT_TRUE(handle_public != nullptr) << dlerror();
 
@@ -860,18 +860,18 @@
   // preload this library to the default namespace to check if it
   // is shared later on.
   void* handle_dlopened =
-          dlopen((g_testlib_root + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW);
+          dlopen((get_testlib_root() + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW);
   ASSERT_TRUE(handle_dlopened != nullptr) << dlerror();
 
   android_namespace_t* ns_not_isolated =
           android_create_namespace("private", nullptr,
-                                   (g_testlib_root + "/private_namespace_libs").c_str(),
+                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, nullptr);
   ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
 
   android_namespace_t* ns_isolated_shared =
           android_create_namespace("private_isolated_shared", nullptr,
-                                   (g_testlib_root + "/private_namespace_libs").c_str(),
+                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED,
                                    nullptr, nullptr);
   ASSERT_TRUE(ns_isolated_shared != nullptr) << dlerror();
@@ -880,7 +880,7 @@
   ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror());
 
   std::string lib_private_external_path =
-      g_testlib_root + "/private_namespace_libs_external/libnstest_private_external.so";
+      get_testlib_root() + "/private_namespace_libs_external/libnstest_private_external.so";
 
   // Load lib_private_external_path to default namespace
   // (it should remain invisible for the isolated namespaces after this)
@@ -971,12 +971,12 @@
   // preload this library to the default namespace to check if it
   // is shared later on.
   void* handle_dlopened =
-          dlopen((g_testlib_root + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW);
+          dlopen((get_testlib_root() + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW);
   ASSERT_TRUE(handle_dlopened != nullptr) << dlerror();
 
   android_namespace_t* ns_isolated_shared =
           android_create_namespace("private_isolated_shared", nullptr,
-                                   (g_testlib_root + "/private_namespace_libs").c_str(),
+                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED,
                                    nullptr, nullptr);
   ASSERT_TRUE(ns_isolated_shared != nullptr) << dlerror();
@@ -997,7 +997,7 @@
   ASSERT_TRUE(handle == nullptr)
       << "Error: libnstest_dlopened.so is still accessible in shared namespace";
 
-  handle = android_dlopen_ext((g_testlib_root + "/private_namespace_libs/libnstest_dlopened.so").c_str(),
+  handle = android_dlopen_ext((get_testlib_root() + "/private_namespace_libs/libnstest_dlopened.so").c_str(),
                               RTLD_NOW | RTLD_NOLOAD, &extinfo);
   ASSERT_TRUE(handle == nullptr)
       << "Error: libnstest_dlopened.so is still accessible in shared namespace";
@@ -1006,14 +1006,14 @@
   ASSERT_TRUE(handle == nullptr)
       << "Error: libnstest_dlopened.so is still accessible in default namespace";
 
-  handle = dlopen((g_testlib_root + "/private_namespace_libs/libnstest_dlopened.so").c_str(),
+  handle = dlopen((get_testlib_root() + "/private_namespace_libs/libnstest_dlopened.so").c_str(),
                   RTLD_NOW | RTLD_NOLOAD);
   ASSERT_TRUE(handle == nullptr)
       << "Error: libnstest_dlopened.so is still accessible in default namespace";
 
   // Now lets see if the soinfo area gets reused in the wrong way:
   // load a library to default namespace.
-  const std::string lib_public_path = g_testlib_root + "/public_namespace_libs/" + g_public_lib;
+  const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
   void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
   ASSERT_TRUE(handle_public != nullptr) << dlerror();
 
@@ -1029,12 +1029,12 @@
 
   ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr));
 
-  const std::string lib_public_path = g_testlib_root + "/public_namespace_libs";
+  const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs";
 
   android_namespace_t* ns1 =
           android_create_namespace("isolated1",
                                    nullptr,
-                                   (g_testlib_root + "/private_namespace_libs").c_str(),
+                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
                                    lib_public_path.c_str(),
                                    nullptr);
@@ -1043,7 +1043,7 @@
   android_namespace_t* ns2 =
           android_create_namespace("isolated2",
                                    nullptr,
-                                   (g_testlib_root + "/private_namespace_libs").c_str(),
+                                   (get_testlib_root() + "/private_namespace_libs").c_str(),
                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
                                    lib_public_path.c_str(),
                                    nullptr);
@@ -1062,7 +1062,7 @@
   android_namespace_t* ns1_child =
         android_create_namespace("isolated1_child",
                                  nullptr,
-                                 (g_testlib_root + "/private_namespace_libs").c_str(),
+                                 (get_testlib_root() + "/private_namespace_libs").c_str(),
                                  ANDROID_NAMESPACE_TYPE_ISOLATED,
                                  nullptr,
                                  ns1);
@@ -1097,22 +1097,22 @@
   static const char* root_lib = "libnstest_root.so";
   std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
 
-  const std::string lib_public_path = g_testlib_root + "/public_namespace_libs/" + g_public_lib;
+  const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
   void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
 
   ASSERT_TRUE(handle_public != nullptr) << dlerror();
 
-  ASSERT_TRUE(android_init_namespaces(path.c_str(), (g_testlib_root + "/private_namespace_libs").c_str()))
+  ASSERT_TRUE(android_init_namespaces(path.c_str(), (get_testlib_root() + "/private_namespace_libs").c_str()))
       << dlerror();
 
   android_namespace_t* ns = android_create_namespace(
                                 "private", nullptr,
-                                (g_testlib_root + "/private_namespace_libs").c_str(),
+                                (get_testlib_root() + "/private_namespace_libs").c_str(),
                                 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, nullptr);
 
   ASSERT_TRUE(ns != nullptr) << dlerror();
 
-  std::string private_library_absolute_path = g_testlib_root + "/private_namespace_libs/" + root_lib;
+  std::string private_library_absolute_path = get_testlib_root() + "/private_namespace_libs/" + root_lib;
 
   android_dlextinfo extinfo;
   extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 4d8e697..46f6ec0 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -1013,6 +1013,22 @@
   ASSERT_TRUE(addr != nullptr);
 }
 
+// Check that RTLD_NEXT of a libc symbol works in dlopened library
+TEST(dlfcn, rtld_next_from_library) {
+  void* library_with_close = dlopen("libtest_check_rtld_next_from_library.so", RTLD_NOW);
+  ASSERT_TRUE(library_with_close != nullptr) << dlerror();
+  void* expected_addr = dlsym(RTLD_DEFAULT, "close");
+  ASSERT_TRUE(expected_addr != nullptr) << dlerror();
+  typedef void* (*get_libc_close_ptr_fn_t)();
+  get_libc_close_ptr_fn_t get_libc_close_ptr =
+      reinterpret_cast<get_libc_close_ptr_fn_t>(dlsym(library_with_close, "get_libc_close_ptr"));
+  ASSERT_TRUE(get_libc_close_ptr != nullptr) << dlerror();
+  ASSERT_EQ(expected_addr, get_libc_close_ptr());
+
+  dlclose(library_with_close);
+}
+
+
 TEST(dlfcn, dlsym_weak_func) {
   dlerror();
   void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW);
@@ -1159,7 +1175,7 @@
 #if defined(__BIONIC__)
 
 TEST(dlfcn, dt_runpath_absolute_path) {
-  std::string libpath = g_testlib_root + "/libtest_dt_runpath_d.so";
+  std::string libpath = get_testlib_root() + "/libtest_dt_runpath_d.so";
   void* handle = dlopen(libpath.c_str(), RTLD_NOW);
   ASSERT_TRUE(handle != nullptr) << dlerror();
 
@@ -1174,7 +1190,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_rw_load_segment) {
-  const std::string libpath = g_testlib_root +
+  const std::string libpath = get_testlib_root() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-rw_load_segment.so";
   void* handle = dlopen(libpath.c_str(), RTLD_NOW);
@@ -1184,7 +1200,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_unaligned_shdr_offset) {
-  const std::string libpath = g_testlib_root +
+  const std::string libpath = get_testlib_root() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-unaligned_shdr_offset.so";
 
@@ -1195,7 +1211,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_zero_shentsize) {
-  const std::string libpath = g_testlib_root +
+  const std::string libpath = get_testlib_root() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-zero_shentsize.so";
 
@@ -1206,7 +1222,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_zero_shstrndx) {
-  const std::string libpath = g_testlib_root +
+  const std::string libpath = get_testlib_root() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-zero_shstrndx.so";
 
@@ -1217,7 +1233,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_empty_shdr_table) {
-  const std::string libpath = g_testlib_root +
+  const std::string libpath = get_testlib_root() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-empty_shdr_table.so";
 
@@ -1228,7 +1244,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_zero_shdr_table_offset) {
-  const std::string libpath = g_testlib_root +
+  const std::string libpath = get_testlib_root() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-zero_shdr_table_offset.so";
 
@@ -1239,7 +1255,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_zero_shdr_table_content) {
-  const std::string libpath = g_testlib_root +
+  const std::string libpath = get_testlib_root() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-zero_shdr_table_content.so";
 
@@ -1250,7 +1266,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_textrels) {
-  const std::string libpath = g_testlib_root +
+  const std::string libpath = get_testlib_root() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-textrels.so";
 
@@ -1261,7 +1277,7 @@
 }
 
 TEST(dlfcn, dlopen_invalid_textrels2) {
-  const std::string libpath = g_testlib_root +
+  const std::string libpath = get_testlib_root() +
                               "/" + kPrebuiltElfDir +
                               "/libtest_invalid-textrels2.so";
 
diff --git a/tests/gtest_globals.cpp b/tests/gtest_globals.cpp
index 4f2c82e..bb99dd6 100644
--- a/tests/gtest_globals.cpp
+++ b/tests/gtest_globals.cpp
@@ -21,11 +21,20 @@
 
 #include <string>
 
-static std::string get_testlib_root() {
+static std::string init_testlib_root() {
   std::string out_path;
   const char* data_dir = getenv("ANDROID_DATA");
   if (data_dir == nullptr) {
-    out_path = "/data";
+    // Calculate ANDROID_DATA assuming the binary is in "$ANDROID_DATA/somedir/binary-dir/binary"
+    std::string path = get_executable_path();
+
+    path = get_dirname(path.c_str());
+    path += "/../..";
+
+    if (!get_realpath(path.c_str(), &out_path)) {
+      printf("Failed to get realpath for \"%s\"", path.c_str());
+      abort();
+    }
   } else {
     out_path = data_dir;
   }
@@ -35,12 +44,18 @@
   out_path += "64";
 #endif
   out_path += "/bionic-loader-test-libs";
+
   std::string real_path;
   if (!get_realpath(out_path, &real_path)) {
+    printf("\"%s\": does not exists", out_path.c_str());
     abort();
   }
 
   return real_path;
 }
 
-const std::string g_testlib_root = get_testlib_root();
+const std::string& get_testlib_root() {
+  static const std::string testlib_root = init_testlib_root();
+  return testlib_root;
+}
+
diff --git a/tests/gtest_globals.h b/tests/gtest_globals.h
index fab2a39..019849d 100644
--- a/tests/gtest_globals.h
+++ b/tests/gtest_globals.h
@@ -21,6 +21,6 @@
 
 constexpr const char* kPrebuiltElfDir = "prebuilt-elf-files";
 
-extern const std::string g_testlib_root;
+const std::string& get_testlib_root();
 
 #endif  // _BIONIC_TESTS_GTEST_GLOBALS_H
diff --git a/tests/gtest_globals_cts.cpp b/tests/gtest_globals_cts.cpp
index bf891a1..2532ef1 100644
--- a/tests/gtest_globals_cts.cpp
+++ b/tests/gtest_globals_cts.cpp
@@ -18,4 +18,8 @@
 
 #include <string>
 
-const std::string g_testlib_root = "/data/local/tmp/lib/bionic-loader-test-libs";
+static const std::string g_testlib_root = "/data/local/tmp/lib/bionic-loader-test-libs";
+
+const std::string& get_testlib_root() {
+  return g_testlib_root;
+}
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index aacf9ae..b12c28f 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <libgen.h>
 #include <limits.h>
 #include <signal.h>
 #include <stdarg.h>
@@ -65,6 +66,15 @@
   return true;
 }
 
+std::string get_dirname(const char* path) {
+#if defined(__BIONIC__)
+  return dirname(path);
+#else
+  // GLIBC does not have const char* dirname
+  return dirname(const_cast<char*>(path));
+#endif
+}
+
 int get_argc() {
   return g_argc;
 }
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index fe0d6ab..4cd991a 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -411,6 +411,24 @@
 }
 
 // -----------------------------------------------------------------------------
+// Check that RTLD_NEXT of a libc symbol works in dlopened library
+// -----------------------------------------------------------------------------
+cc_test_library {
+    name: "libtest_check_rtld_next_from_library",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["check_rtld_next_from_library.cpp"],
+
+    target: {
+        android: {
+            shared_libs: ["libdl"],
+        },
+        host: {
+            host_ldlibs: ["-ldl"],
+        },
+    },
+}
+
+// -----------------------------------------------------------------------------
 // Library with constructor that calls dlopen() b/7941716
 // -----------------------------------------------------------------------------
 cc_test_library {
diff --git a/tests/libs/check_rtld_next_from_library.cpp b/tests/libs/check_rtld_next_from_library.cpp
new file mode 100644
index 0000000..45d8eea
--- /dev/null
+++ b/tests/libs/check_rtld_next_from_library.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 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 <dlfcn.h>
+#include <stdlib.h>
+
+static void* g_libc_close_ptr;
+
+static void __attribute__((constructor)) __libc_close_lookup() {
+  g_libc_close_ptr = dlsym(RTLD_NEXT, "close");
+}
+
+// A libc function used for RTLD_NEXT
+// This function in not supposed to be called
+extern "C" int __attribute__((weak)) close(int) {
+  abort();
+}
+
+extern "C" void* get_libc_close_ptr() {
+  return g_libc_close_ptr;
+}
+
+
diff --git a/tests/utils.h b/tests/utils.h
index c62da75..4c3aef4 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -128,6 +128,8 @@
 
 // Get realpath
 bool get_realpath(const std::string& path, std::string* realpath);
+// Get dirname
+std::string get_dirname(const char* path);
 
 // Access to argc/argv/envp
 int get_argc();