Don't enqueue pending signals during global destruction
Lubomir Rintel [Thu, 25 Jun 2009 20:57:46 +0000 (22:57 +0200)]
Global destruction is not signal-safe. PL_psig_pend may already
be gone when the signal handler is called (with destruct_level > 0).
NULL it before freeing it to prevent a race condition.

mg.c
perl.c

diff --git a/mg.c b/mg.c
index e9e4214..05a5092 100644 (file)
--- a/mg.c
+++ b/mg.c
@@ -1316,13 +1316,14 @@ Perl_csighandler(int sig)
 #endif
           (PL_signals & PERL_SIGNALS_UNSAFE_FLAG))
        /* Call the perl level handler now--
-        * with risk we may be in malloc() etc. */
+        * with risk we may be in malloc() or being destructed etc. */
 #if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
        (*PL_sighandlerp)(sig, NULL, NULL);
 #else
        (*PL_sighandlerp)(sig);
 #endif
     else {
+       if (!PL_psig_pend) return;
        /* Set a flag to say this signal is pending, that is awaiting delivery after
         * the current Perl opcode completes */
        PL_psig_pend[sig]++;
diff --git a/perl.c b/perl.c
index e70bf7e..d9ebaca 100644 (file)
--- a/perl.c
+++ b/perl.c
@@ -1233,6 +1233,13 @@ perl_destruct(pTHXx)
     PL_psig_ptr = (SV**)NULL;
     Safefree(PL_psig_pend);
     PL_psig_pend = (int*)NULL;
+    {
+       /* We need to NULL PL_psig_pend first, so that
+          signal handlers know not to use it */
+       int *psig_save = PL_psig_pend;
+       PL_psig_pend = (int*)NULL;
+       Safefree(psig_save);
+    }
     PL_formfeed = NULL;
     nuke_stacks();
     PL_tainting = FALSE;