Fix dlerror(3).

Add unit tests for dlerror(3) in various situations. I think We're at least
as good as glibc now.

Also factor out the ScopedPthreadMutexLock and use it here too.

Bug: http://code.google.com/p/android/issues/detail?id=38398
Change-Id: I040938b4366ab836e3df46d1d8055b92f4ea6ed8
diff --git a/tests/dlopen_test.cpp b/tests/dlopen_test.cpp
index 2fcfa0c..5ef32ad 100644
--- a/tests/dlopen_test.cpp
+++ b/tests/dlopen_test.cpp
@@ -24,14 +24,19 @@
 
 #include <string>
 
+#define ASSERT_SUBSTR(needle, haystack) \
+    ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
+
 static bool gCalled = false;
 extern "C" void DlSymTestFunction() {
   gCalled = true;
 }
 
 TEST(dlopen, dlsym_in_self) {
+  dlerror(); // Clear any pending errors.
   void* self = dlopen(NULL, RTLD_NOW);
   ASSERT_TRUE(self != NULL);
+  ASSERT_TRUE(dlerror() == NULL);
 
   void* sym = dlsym(self, "DlSymTestFunction");
   ASSERT_TRUE(sym != NULL);
@@ -43,9 +48,52 @@
   ASSERT_TRUE(gCalled);
 }
 
-TEST(dlopen, dladdr) {
+TEST(dlopen, dlopen_failure) {
+  void* self = dlopen("/does/not/exist", RTLD_NOW);
+  ASSERT_TRUE(self == NULL);
+#if __BIONIC__
+  ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
+#else
+  ASSERT_STREQ("/does/not/exist: cannot open shared object file: No such file or directory", dlerror());
+#endif
+}
+
+TEST(dlopen, dlsym_failures) {
+  dlerror(); // Clear any pending errors.
   void* self = dlopen(NULL, RTLD_NOW);
   ASSERT_TRUE(self != NULL);
+  ASSERT_TRUE(dlerror() == NULL);
+
+  void* sym;
+
+  // NULL handle.
+  sym = dlsym(NULL, "test");
+  ASSERT_TRUE(sym == NULL);
+#if __BIONIC__
+  ASSERT_SUBSTR("dlsym library handle is null", dlerror());
+#else
+  ASSERT_SUBSTR("undefined symbol: test", dlerror()); // glibc isn't specific about the failure.
+#endif
+
+  // NULL symbol name.
+#if __BIONIC__
+  // glibc marks this parameter non-null and SEGVs if you cheat.
+  sym = dlsym(self, NULL);
+  ASSERT_TRUE(sym == NULL);
+  ASSERT_SUBSTR("", dlerror());
+#endif
+
+  // Symbol that doesn't exist.
+  sym = dlsym(self, "ThisSymbolDoesNotExist");
+  ASSERT_TRUE(sym == NULL);
+  ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
+}
+
+TEST(dlopen, dladdr) {
+  dlerror(); // Clear any pending errors.
+  void* self = dlopen(NULL, RTLD_NOW);
+  ASSERT_TRUE(self != NULL);
+  ASSERT_TRUE(dlerror() == NULL);
 
   void* sym = dlsym(self, "DlSymTestFunction");
   ASSERT_TRUE(sym != NULL);
@@ -102,9 +150,13 @@
 TEST(dlopen, dladdr_invalid) {
   Dl_info info;
 
+  dlerror(); // Clear any pending errors.
+
   // No symbol corresponding to NULL.
   ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success.
+  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
 
   // No symbol corresponding to a stack address.
   ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
+  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
 }