Merge "Fix dlsym(handle_of_main_executable, ...)"
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 531cd19..1382a9c 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -948,6 +948,17 @@
 // This is used by dlsym(3).  It performs symbol lookup only within the
 // specified soinfo object and its dependencies in breadth first order.
 const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
+  // According to man dlopen(3) and posix docs in the case when si is handle
+  // of the main executable we need to search not only in the executable and its
+  // dependencies but also in all libraries loaded with RTLD_GLOBAL.
+  //
+  // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
+  // libraries and they are loaded in breath-first (correct) order we can just execute
+  // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
+  if (si == somain) {
+    return dlsym_linear_lookup(name, found, nullptr, RTLD_DEFAULT);
+  }
+
   SymbolName symbol_name(name);
   return dlsym_handle_lookup(si, nullptr, found, symbol_name);
 }
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index a5abda7..3c9b8e3 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -145,13 +145,28 @@
   dlclose(preload);
 }
 
+TEST(dlfcn, dlsym_handle_global_sym) {
+  // check that we do not look into global group
+  // when looking up symbol by handle
+  void* handle = dlopen("libtest_empty.so", RTLD_NOW);
+  dlopen("libtest_with_dependency.so", RTLD_NOW | RTLD_GLOBAL);
+  void* sym = dlsym(handle, "getRandomNumber");
+  ASSERT_TRUE(sym == nullptr);
+  ASSERT_SUBSTR("undefined symbol: getRandomNumber", dlerror());
+
+  sym = dlsym(handle, "DlSymTestFunction");
+  ASSERT_TRUE(sym == nullptr);
+  ASSERT_SUBSTR("undefined symbol: DlSymTestFunction", dlerror());
+  dlclose(handle);
+}
+
 TEST(dlfcn, dlsym_with_dependencies) {
   void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
-  ASSERT_TRUE(handle != NULL);
+  ASSERT_TRUE(handle != nullptr);
   dlerror();
   // This symbol is in DT_NEEDED library.
   void* sym = dlsym(handle, "getRandomNumber");
-  ASSERT_TRUE(sym != NULL);
+  ASSERT_TRUE(sym != nullptr) << dlerror();
   int (*fn)(void);
   fn = reinterpret_cast<int (*)(void)>(sym);
   EXPECT_EQ(4, fn());
@@ -583,6 +598,15 @@
   // RTLD_GLOBAL implies RTLD_NODELETE, let's check that
   void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
   ASSERT_EQ(sym, sym_after_dlclose);
+
+  // Check if dlsym() for main program's handle searches RTLD_GLOBAL
+  // shared libraries after symbol was not found in the main executable
+  // and dependent libraries.
+  void* handle_for_main_executable = dlopen(nullptr, RTLD_NOW);
+  sym = dlsym(handle_for_main_executable, "dlopen_testlib_simple_func");
+  ASSERT_TRUE(sym != nullptr) << dlerror();
+
+  dlclose(handle_for_main_executable);
 }
 
 // libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index 15fa55c..a5ef622 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -405,6 +405,14 @@
 include $(LOCAL_PATH)/Android.build.testlib.mk
 
 # -----------------------------------------------------------------------------
+# Empty library
+# -----------------------------------------------------------------------------
+libtest_empty_src_files := empty.cpp
+
+module := libtest_empty
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
+# -----------------------------------------------------------------------------
 # Library with weak undefined function
 # -----------------------------------------------------------------------------
 libtest_dlopen_weak_undefined_func_src_files := \