Merge m-c to autoland. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 15 Jun 2018 19:03:36 -0400
changeset 476966 bd2e2ab593fcc62f1f10a87009ac0c2dd1913757
parent 476965 2792dcc6b2eb6e5a7dd6dcfeff07490a2ec187a6 (current diff)
parent 476921 a7384267f89c6cc5856c1aa2a01e1e556cea1f16 (diff)
child 476967 1a8d4d870932115f30500b1d15d2f69c0109586c
push id9374
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:43:20 +0000
treeherdermozilla-beta@160e085dfb0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to autoland. a=merge
--- a/mozglue/linker/ElfLoader.cpp
+++ b/mozglue/linker/ElfLoader.cpp
@@ -21,16 +21,17 @@
 
 using namespace mozilla;
 
 // From Utils.h
 Atomic<size_t, ReleaseAcquire> gPageSize;
 
 #if defined(ANDROID)
 #include <sys/syscall.h>
+#include <sys/system_properties.h>
 #include <math.h>
 
 #include <android/api-level.h>
 #if __ANDROID_API__ < 8
 /* Android API < 8 doesn't provide sigaltstack */
 
 extern "C" {
 
@@ -306,16 +307,66 @@ const char *
 LeafName(const char *path)
 {
   const char *lastSlash = strrchr(path, '/');
   if (lastSlash)
     return lastSlash + 1;
   return path;
 }
 
+#if defined(ANDROID)
+/**
+ * Return the current Android version, or 0 on failure.
+ */
+int
+GetAndroidSDKVersion() {
+  static int version = 0;
+  if (version) {
+    return version;
+  }
+
+  char version_string[PROP_VALUE_MAX] = {'\0'};
+  int len = __system_property_get("ro.build.version.sdk", version_string);
+  if (len) {
+    version = static_cast<int>(strtol(version_string, nullptr, 10));
+  }
+  return version;
+}
+#endif
+
+/**
+ * Run the given lambda while holding the internal lock of the system linker.
+ * To take the lock, we call the system dl_iterate_phdr and invoke the lambda
+ * from the callback, which is called while the lock is held. Return true on
+ * success.
+ */
+template<class Lambda>
+static bool
+RunWithSystemLinkerLock(Lambda&& aLambda) {
+  if (!dl_iterate_phdr) {
+    // No dl_iterate_phdr support.
+    return false;
+  }
+
+#if defined(ANDROID)
+  if (GetAndroidSDKVersion() < 23) {
+    // dl_iterate_phdr is _not_ protected by a lock on Android < 23.
+    // Also return false here if we failed to get the version.
+    return false;
+  }
+#endif
+
+  dl_iterate_phdr([] (dl_phdr_info*, size_t, void* lambda) -> int {
+    (*static_cast<Lambda*>(lambda))();
+    // Return 1 to stop iterating.
+    return 1;
+  }, &aLambda);
+  return true;
+}
+
 } /* Anonymous namespace */
 
 /**
  * LibHandle
  */
 LibHandle::~LibHandle()
 {
   free(path);
@@ -571,17 +622,19 @@ ElfLoader::Register(LibHandle *handle)
   handles.push_back(handle);
 }
 
 void
 ElfLoader::Register(CustomElf *handle)
 {
   Register(static_cast<LibHandle *>(handle));
   if (dbg) {
-    dbg.Add(handle);
+    // We could race with the system linker when modifying the debug map, so
+    // only do so while holding the system linker's internal lock.
+    RunWithSystemLinkerLock([this, handle] { dbg.Add(handle); });
   }
 }
 
 void
 ElfLoader::Forget(LibHandle *handle)
 {
   /* Ensure logging is initialized or refresh if environment changed. */
   Logging::Init();
@@ -598,17 +651,19 @@ ElfLoader::Forget(LibHandle *handle)
   }
 }
 
 void
 ElfLoader::Forget(CustomElf *handle)
 {
   Forget(static_cast<LibHandle *>(handle));
   if (dbg) {
-    dbg.Remove(handle);
+    // We could race with the system linker when modifying the debug map, so
+    // only do so while holding the system linker's internal lock.
+    RunWithSystemLinkerLock([this, handle] { dbg.Remove(handle); });
   }
 }
 
 void
 ElfLoader::Init()
 {
   Dl_info info;
   /* On Android < 4.1 can't reenter dl* functions. So when the library