Bug 1278325 - Hook exit to catch early 3rd party exits in crash reports. r=ted draft
authorBenoit Girard <b56girard@gmail.com>
Tue, 07 Jun 2016 15:58:14 -0400
changeset 413737 658ec6d15a23aa731a5a89d805dc38b2c9075c04
parent 413053 f5d043ce6d36a3c461cbd829d4a4a38394b7c436
child 531274 c5a18a263adb4f398cc0f14537063e06790de791
push id29481
push userb56girard@gmail.com
push dateWed, 14 Sep 2016 17:59:41 +0000
reviewersted
bugs1278325
milestone51.0a1
Bug 1278325 - Hook exit to catch early 3rd party exits in crash reports. r=ted MozReview-Commit-ID: 6x6DLcqqkAe
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsAppRunner.h
toolkit/xre/nsNativeAppSupportUnix.cpp
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -7,22 +7,23 @@
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ChaosMode.h"
 #include "mozilla/IOInterposer.h"
 #include "mozilla/Likely.h"
+#include "mozilla/MemoryChecking.h"
 #include "mozilla/Poison.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/ScopeExit.h"
 #include "mozilla/Services.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/Telemetry.h"
-#include "mozilla/MemoryChecking.h"
 
 #include "nsAppRunner.h"
 #include "mozilla/AppData.h"
 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
 #include "nsUpdateDriver.h"
 #endif
 #include "ProfileReset.h"
 
@@ -373,16 +374,35 @@ strimatch(const char* lowerstr, const ch
     ++mixedstr;
   }
 
   if (*mixedstr) return false; // lowerstr is shorter
 
   return true;
 }
 
+static bool gIsExpectedExit = false;
+
+void MozExpectedExit() {
+  gIsExpectedExit = true;
+}
+
+/**
+ * Runs atexit() to catch unexpected exit from 3rd party libraries like the
+ * Intel graphics driver calling exit in an error condition. When they
+ * call exit() to report an error we won't shutdown correctly and wont catch
+ * the issue with our crash reporter.
+ */
+static void UnexpectedExit() {
+  if (!gIsExpectedExit) {
+    gIsExpectedExit = true; // Don't risk re-entrency issues when crashing.
+    MOZ_CRASH("Exit called by third party code.");
+  }
+}
+
 /**
  * Output a string to the user.  This method is really only meant to be used to
  * output last-ditch error messages designed for developers NOT END USERS.
  *
  * @param isError
  *        Pass true to indicate severe errors.
  * @param fmt
  *        printf-style format string followed by arguments.
@@ -3013,16 +3033,21 @@ public:
  */
 int
 XREMain::XRE_mainInit(bool* aExitFlag)
 {
   if (!aExitFlag)
     return 1;
   *aExitFlag = false;
 
+  atexit(UnexpectedExit);
+  auto expectedShutdown = mozilla::MakeScopeExit([&] {
+    MozExpectedExit();
+  });
+
   StartupTimeline::Record(StartupTimeline::MAIN);
 
   if (PR_GetEnv("MOZ_CHAOSMODE")) {
     ChaosFeature feature = ChaosFeature::Any;
     long featureInt = strtol(PR_GetEnv("MOZ_CHAOSMODE"), nullptr, 16);
     if (featureInt) {
       // NOTE: MOZ_CHAOSMODE=0 or a non-hex value maps to Any feature.
       feature = static_cast<ChaosFeature>(featureInt);
--- a/toolkit/xre/nsAppRunner.h
+++ b/toolkit/xre/nsAppRunner.h
@@ -92,16 +92,23 @@ NS_LockProfilePath(nsIFile* aPath, nsIFi
                    nsIProfileUnlocker* *aUnlocker, nsIProfileLock* *aResult);
 
 void
 WriteConsoleLog();
 
 void
 OverrideDefaultLocaleIfNeeded();
 
+/**
+ * Allow exit() calls to complete. This should be done from a proper Gecko
+ * shutdown path. Otherwise we aim to catch improper shutdowns.
+ */
+void
+MozExpectedExit();
+
 #ifdef XP_WIN
 void
 UseParentConsole();
 
 BOOL
 WinLaunchChild(const wchar_t *exePath, int argc,
                char **argv, HANDLE userToken = nullptr,
                HANDLE *hProcess = nullptr);
--- a/toolkit/xre/nsNativeAppSupportUnix.cpp
+++ b/toolkit/xre/nsNativeAppSupportUnix.cpp
@@ -467,16 +467,17 @@ nsNativeAppSupportUnix::Start(bool *aRet
                      GTK_BUTTONS_OK,
                      UNSUPPORTED_GTK_MSG,
                      gtk_major_version,
                      gtk_minor_version,
                      MIN_GTK_MAJOR_VERSION,
                      MIN_GTK_MINOR_VERSION);
     gtk_dialog_run(GTK_DIALOG(versionErrDialog));
     gtk_widget_destroy(versionErrDialog);
+    MozExpectedExit();
     exit(0);
   }
 #endif
 
   *aRetVal = true;
 
 #ifdef MOZ_X11
   gboolean sm_disable = FALSE;