Bug 1066760 - Redirect mozalloc_abort through Java exception handling; r=snorp
authorJim Chen <nchen@mozilla.com>
Wed, 24 Sep 2014 14:12:54 -0400
changeset 206961 421c30629ac5bca71a03dead2a7d8889609e188d
parent 206960 4aafc40bcd62ad4e289fa28ed0269ef33e52b399
child 206962 4cf6c10a0ab9cc18f46f876a86fbe84ec82a5eee
push id49580
push usernchen@mozilla.com
push dateWed, 24 Sep 2014 18:16:58 +0000
treeherdermozilla-inbound@4cf6c10a0ab9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp
bugs1066760
milestone35.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
Bug 1066760 - Redirect mozalloc_abort through Java exception handling; r=snorp
memory/mozalloc/mozalloc_abort.cpp
mobile/android/base/mozglue/GeckoLoader.java.in
mozglue/android/APKOpen.cpp
mozglue/android/APKOpen.h
mozglue/linker/ElfLoader.h
--- a/memory/mozalloc/mozalloc_abort.cpp
+++ b/memory/mozalloc/mozalloc_abort.cpp
@@ -9,29 +9,35 @@
 #  define MOZALLOC_EXPORT __declspec(dllexport)
 #endif
 
 #include "mozilla/mozalloc_abort.h"
 
 #ifdef ANDROID
 # include <android/log.h>
 #endif
+#ifdef MOZ_WIDGET_ANDROID
+# include "APKOpen.h"
+#endif
 #include <stdio.h>
 
 #include "mozilla/Assertions.h"
 
 void
 mozalloc_abort(const char* const msg)
 {
 #ifndef ANDROID
     fputs(msg, stderr);
     fputs("\n", stderr);
 #else
     __android_log_print(ANDROID_LOG_ERROR, "Gecko", "mozalloc_abort: %s", msg);
 #endif
+#ifdef MOZ_WIDGET_ANDROID
+    abortThroughJava(msg);
+#endif
     MOZ_CRASH();
 }
 
 #if defined(XP_UNIX)
 // Define abort() here, so that it is used instead of the system abort(). This
 // lets us control the behavior when aborting, in order to get better results
 // on *NIX platforms. See mozalloc_abort for details.
 void abort(void)
--- a/mobile/android/base/mozglue/GeckoLoader.java.in
+++ b/mobile/android/base/mozglue/GeckoLoader.java.in
@@ -526,16 +526,33 @@ public final class GeckoLoader {
             DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
 
             putenv("LOCALE_DECIMAL_POINT=" + dfs.getDecimalSeparator());
             putenv("LOCALE_THOUSANDS_SEP=" + dfs.getGroupingSeparator());
             putenv("LOCALE_GROUPING=" + (char)df.getGroupingSize());
         }
     }
 
+    @SuppressWarnings("serial")
+    public static class AbortException extends Exception {
+        public AbortException(String msg) {
+            super(msg);
+        }
+    }
+
+    @JNITarget
+    public static void abort(final String msg) {
+        final Thread thread = Thread.currentThread();
+        final Thread.UncaughtExceptionHandler uncaughtHandler =
+            thread.getUncaughtExceptionHandler();
+        if (uncaughtHandler != null) {
+            uncaughtHandler.uncaughtException(thread, new AbortException(msg));
+        }
+    }
+
     // These methods are implemented in mozglue/android/nsGeckoUtils.cpp
     private static native void putenv(String map);
 
     // These methods are implemented in mozglue/android/APKOpen.cpp
     public static native void nativeRun(String args);
     private static native void loadGeckoLibsNative(String apkName);
     private static native void loadSQLiteLibsNative(String apkName);
     private static native void loadNSSLibsNative(String apkName);
--- a/mozglue/android/APKOpen.cpp
+++ b/mozglue/android/APKOpen.cpp
@@ -119,16 +119,60 @@ JNI_Throw(JNIEnv* jenv, const char* clas
     int rc = jenv->ThrowNew(cls, msg);
     if (rc < 0) {
         __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Error throwing exception %s\n", msg);
         exit(FAILURE);
     }
     jenv->DeleteLocalRef(cls);
 }
 
+namespace {
+    JavaVM* sJavaVM;
+}
+
+void
+abortThroughJava(const char* msg)
+{
+    struct sigaction sigact = {};
+    if (SEGVHandler::__wrap_sigaction(SIGSEGV, nullptr, &sigact)) {
+        return; // sigaction call failed.
+    }
+
+    Dl_info info = {};
+    if ((sigact.sa_flags & SA_SIGINFO) &&
+        __wrap_dladdr(reinterpret_cast<void*>(sigact.sa_sigaction), &info) &&
+        info.dli_fname && strstr(info.dli_fname, "libxul.so")) {
+
+        return; // Existing signal handler is in libxul (i.e. we have crash reporter).
+    }
+
+    JNIEnv* env = nullptr;
+    if (!sJavaVM || sJavaVM->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
+        return;
+    }
+
+    if (!env || env->PushLocalFrame(2) != JNI_OK) {
+        return;
+    }
+
+    jclass loader = env->FindClass("org/mozilla/gecko/mozglue/GeckoLoader");
+    if (!loader) {
+        return;
+    }
+
+    jmethodID method = env->GetStaticMethodID(loader, "abort", "(Ljava/lang/String;)V");
+    jstring str = env->NewStringUTF(msg);
+
+    if (method && str) {
+        env->CallStaticVoidMethod(loader, method, str);
+    }
+
+    env->PopLocalFrame(nullptr);
+}
+
 #define JNI_STUBS
 #include "jni-stubs.inc"
 #undef JNI_STUBS
 
 static void * xul_handle = nullptr;
 #ifndef MOZ_FOLD_LIBS
 static void * sqlite_handle = nullptr;
 static void * nspr_handle = nullptr;
@@ -297,16 +341,18 @@ loadNSSLibs(const char *apkName)
 #endif
 
   return setup_nss_functions(nss_handle, nspr_handle, plc_handle);
 }
 
 extern "C" NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_mozglue_GeckoLoader_loadGeckoLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName)
 {
+  jenv->GetJavaVM(&sJavaVM);
+
   const char* str;
   // XXX: java doesn't give us true UTF8, we should figure out something
   // better to do here
   str = jenv->GetStringUTFChars(jApkName, nullptr);
   if (str == nullptr)
     return;
 
   int res = loadGeckoLibs(str);
--- a/mozglue/android/APKOpen.h
+++ b/mozglue/android/APKOpen.h
@@ -14,14 +14,15 @@
 struct mapping_info {
   char * name;
   uintptr_t base;
   size_t len;
   size_t offset;
 };
 
 NS_EXPORT const struct mapping_info * getLibraryMapping();
+NS_EXPORT void abortThroughJava(const char* msg);
 
 static const int SUCCESS = 0;
 static const int FAILURE = 1;
 void JNI_Throw(JNIEnv* jenv, const char* classname, const char* msg);
 
 #endif /* APKOpen_h */
--- a/mozglue/linker/ElfLoader.h
+++ b/mozglue/linker/ElfLoader.h
@@ -322,23 +322,24 @@ public:
       FinishInitialization();
     return registeredHandler;
   }
 
   bool isSignalHandlingBroken() {
     return signalHandlingBroken;
   }
 
+  static int __wrap_sigaction(int signum, const struct sigaction *act,
+                              struct sigaction *oldact);
+
 protected:
   SEGVHandler();
   ~SEGVHandler();
 
 private:
-  static int __wrap_sigaction(int signum, const struct sigaction *act,
-                              struct sigaction *oldact);
 
   /**
    * The constructor doesn't do all initialization, and the tail is done
    * at a later time.
    */
   void FinishInitialization();
 
   /**