linker: fix error message for inaccessible libs

Added a test to make sure linker produces correct error message
when user attempts to load a library in a linked namespace and fails.

Bug: http://b/67866190
Bug: http://b/64950640
Bug: http://b/64888291
Test: bionic-unit-test --gtest_filter=dlext*
Change-Id: I5b5c2070d1388eff123118350b2b5c8fc7571a29
diff --git a/linker/linker.cpp b/linker/linker.cpp
index ec92c92..5f906c8 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1433,6 +1433,8 @@
 
   if (search_linked_namespaces) {
     // if a library was not found - look into linked namespaces
+    // preserve current dlerror in the case it fails.
+    DlErrorRestorer dlerror_restorer;
     for (auto& linked_namespace : ns->linked_namespaces()) {
       if (find_library_in_linked_namespace(linked_namespace,
                                            task)) {
diff --git a/linker/linker_globals.h b/linker/linker_globals.h
index d8134af..11ccbd5 100644
--- a/linker/linker_globals.h
+++ b/linker/linker_globals.h
@@ -32,6 +32,7 @@
 #include <link.h>
 #include <stddef.h>
 
+#include <string>
 #include <unordered_map>
 
 #include <async_safe/log.h>
@@ -39,7 +40,6 @@
 #define DL_ERR(fmt, x...) \
     do { \
       async_safe_format_buffer(linker_get_error_buffer(), linker_get_error_buffer_size(), fmt, ##x); \
-      /* If LD_DEBUG is set high enough, log every dlerror(3) message. */ \
     } while (false)
 
 #define DL_WARN(fmt, x...) \
@@ -75,4 +75,16 @@
 char* linker_get_error_buffer();
 size_t linker_get_error_buffer_size();
 
+class DlErrorRestorer {
+ public:
+  DlErrorRestorer() {
+    saved_error_msg_ = linker_get_error_buffer();
+  }
+  ~DlErrorRestorer() {
+    strlcpy(linker_get_error_buffer(), saved_error_msg_.c_str(), linker_get_error_buffer_size());
+  }
+ private:
+  std::string saved_error_msg_;
+};
+
 #endif  /* __LINKER_GLOBALS_H */