bug 514188 - fix nsProfileLock to use SA_SIGINFO style signal handler, so it can chain to Breakpad's signal handler properly. r=bsmedberg
authorTed Mielczarek <ted.mielczarek@gmail.com>
Mon, 14 Dec 2009 06:44:27 -0500
changeset 36831 3975716a6eb4c61d535a340b4656cce1e7ceb3d6
parent 36830 a9addb7dc548e3a7593cbf4ecec872762619ee6b
child 36832 5e311ec4e77572dc8ffb9622792520c1d64ac2df
push idunknown
push userunknown
push dateunknown
reviewersbsmedberg
bugs514188
milestone1.9.3a1pre
bug 514188 - fix nsProfileLock to use SA_SIGINFO style signal handler, so it can chain to Breakpad's signal handler properly. r=bsmedberg
profile/dirserviceprovider/src/nsProfileLock.cpp
profile/dirserviceprovider/src/nsProfileLock.h
toolkit/crashreporter/test/nsITestCrasher.idl
toolkit/crashreporter/test/nsTestCrasher.cpp
toolkit/crashreporter/test/unit/test_crashreporter_crash_profile_lock.js
--- a/profile/dirserviceprovider/src/nsProfileLock.cpp
+++ b/profile/dirserviceprovider/src/nsProfileLock.cpp
@@ -154,17 +154,18 @@ void nsProfileLock::RemovePidLockFiles()
 static struct sigaction SIGHUP_oldact;
 static struct sigaction SIGINT_oldact;
 static struct sigaction SIGQUIT_oldact;
 static struct sigaction SIGILL_oldact;
 static struct sigaction SIGABRT_oldact;
 static struct sigaction SIGSEGV_oldact;
 static struct sigaction SIGTERM_oldact;
 
-void nsProfileLock::FatalSignalHandler(int signo)
+void nsProfileLock::FatalSignalHandler(int signo, siginfo_t *info,
+                                       void *context)
 {
     // Remove any locks still held.
     RemovePidLockFiles();
 
     // Chain to the old handler, which may exit.
     struct sigaction *oldact = nsnull;
 
     switch (signo) {
@@ -206,16 +207,20 @@ void nsProfileLock::FatalSignalHandler(i
             sigset_t unblock_sigs;
             sigemptyset(&unblock_sigs);
             sigaddset(&unblock_sigs, signo);
 
             sigprocmask(SIG_UNBLOCK, &unblock_sigs, NULL);
 
             raise(signo);
         }
+        else if (oldact->sa_sigaction &&
+                 (oldact->sa_flags & SA_SIGINFO) == SA_SIGINFO) {
+            oldact->sa_sigaction(signo, info, context);
+        }
         else if (oldact->sa_handler && oldact->sa_handler != SIG_IGN)
         {
             oldact->sa_handler(signo);
         }
     }
 
     // Backstop exit call, just in case.
     _exit(signo);
@@ -382,18 +387,18 @@ nsresult nsProfileLock::LockWithSymlink(
                 // Clean up on normal termination.
                 atexit(RemovePidLockFiles);
 
                 // Clean up on abnormal termination, using POSIX sigaction.
                 // Don't arm a handler if the signal is being ignored, e.g.,
                 // because mozilla is run via nohup.
                 if (!sDisableSignalHandling) {
                     struct sigaction act, oldact;
-                    act.sa_handler = FatalSignalHandler;
-                    act.sa_flags = 0;
+                    act.sa_sigaction = FatalSignalHandler;
+                    act.sa_flags = SA_SIGINFO;
                     sigfillset(&act.sa_mask);
 
 #define CATCH_SIGNAL(signame)                                           \
 PR_BEGIN_MACRO                                                          \
   if (sigaction(signame, NULL, &oldact) == 0 &&                         \
       oldact.sa_handler != SIG_IGN)                                     \
   {                                                                     \
       sigaction(signame, &act, &signame##_oldact);                      \
--- a/profile/dirserviceprovider/src/nsProfileLock.h
+++ b/profile/dirserviceprovider/src/nsProfileLock.h
@@ -50,16 +50,17 @@ class nsIProfileUnlocker;
 
 #if defined (XP_OS2)
 #define INCL_DOSERRORS
 #define INCL_DOSFILEMGR
 #include <os2.h>
 #endif
 
 #if defined (XP_UNIX)
+#include <signal.h>
 #include "prclist.h"
 #endif
 
 class nsProfileLock
 #if defined (XP_UNIX)
   : public PRCList
 #endif
 {
@@ -87,17 +88,18 @@ private:
     PRPackedBool            mHaveLock;
 
 #if defined (XP_WIN)
     HANDLE                  mLockFileHandle;
 #elif defined (XP_OS2)
     LHANDLE                 mLockFileHandle;
 #elif defined (XP_UNIX)
     static void             RemovePidLockFiles();
-    static void             FatalSignalHandler(int signo);
+    static void             FatalSignalHandler(int signo, siginfo_t *info,
+                                               void *context);
     static PRCList          mPidLockList;
 
     nsresult                LockWithFcntl(const nsACString& lockFilePath);
 
     /**
      * @param aHaveFcntlLock if true, we've already acquired an fcntl lock so this
      * lock is merely an "obsolete" lock to keep out old Firefoxes
      */
--- a/toolkit/crashreporter/test/nsITestCrasher.idl
+++ b/toolkit/crashreporter/test/nsITestCrasher.idl
@@ -1,7 +1,17 @@
 #include "nsISupports.idl"
 
+interface nsILocalFile;
+
 [scriptable, uuid(95464a04-6949-46cb-b621-d167790704a0)]
 interface nsITestCrasher : nsISupports
 {
   void crash();
+
+  /**
+   * Lock a directory using XRE_LockProfileDirectory.
+   * 
+   * @param directory The directory to lock
+   * @return          An opaque lock object.
+   */
+  nsISupports lockDir(in nsILocalFile directory);
 };
--- a/toolkit/crashreporter/test/nsTestCrasher.cpp
+++ b/toolkit/crashreporter/test/nsTestCrasher.cpp
@@ -1,12 +1,13 @@
 #include "nsServiceManagerUtils.h"
 #include "nsIComponentManager.h"
 #include "nsIGenericFactory.h"
 #include "nsITestCrasher.h"
+#include "nsXULAppAPI.h"
 
 class nsTestCrasher : public nsITestCrasher
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSITESTCRASHER
 
   nsTestCrasher() {}
@@ -22,16 +23,23 @@ NS_IMPL_ISUPPORTS1(nsTestCrasher, nsITes
 NS_IMETHODIMP nsTestCrasher::Crash()
 {
   volatile int* foo = (int*)0x42;
   *foo = 0;
   // not reached
   return NS_OK;
 }
 
+/* nsISupports LockDir (in nsILocalFile directory); */
+NS_IMETHODIMP nsTestCrasher::LockDir(nsILocalFile *directory,
+                                     nsISupports **_retval NS_OUTPARAM)
+{
+  return XRE_LockProfileDirectory(directory, _retval);
+}
+
 // 54afce51-38d7-4df0-9750-2f90f9ffbca2
 #define NS_TESTCRASHER_CID \
 { 0x54afce51, 0x38d7, 0x4df0, {0x97, 0x50, 0x2f, 0x90, 0xf9, 0xff, 0xbc, 0xa2} }
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsTestCrasher)
 
 static const nsModuleComponentInfo components[] = {
     { "Test Crasher",
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/test/unit/test_crashreporter_crash_profile_lock.js
@@ -0,0 +1,27 @@
+function run_test()
+{
+  if (!("@mozilla.org/toolkit/crash-reporter;1" in Components.classes)) {
+    dump("INFO | test_crashreporter.js | Can't test crashreporter in a non-libxul build.\n");
+    return;
+  }
+
+  // lock a profile directory, crash, and ensure that
+  // the profile lock signal handler doesn't interfere with
+  // writing a minidump
+  do_crash(function() {
+             let env = Components.classes["@mozilla.org/process/environment;1"]
+               .getService(Components.interfaces.nsIEnvironment);
+             // the python harness sets this in the environment for us
+             let profd = env.get("XPCSHELL_TEST_PROFILE_DIR");
+             let dir = Components.classes["@mozilla.org/file/local;1"]
+               .createInstance(Components.interfaces.nsILocalFile);
+             dir.initWithPath(profd);
+             let mycrasher = Components.classes["@mozilla.org/testcrasher;1"].createInstance(Components.interfaces.nsITestCrasher);
+             let lock = mycrasher.lockDir(dir);
+             // when we crash, the lock file should be cleaned up
+           },
+           function(mdump, extra) {
+             // if we got here, we have a minidump, so that's all we wanted
+             do_check_true(true);
+           });
+}