In signal handler, don't inc stack pointers
authorDavid Mitchell <davem@iabyn.com>
Sat, 19 Mar 2011 21:29:16 +0000 (21:29 +0000)
committerDavid Mitchell <davem@iabyn.com>
Sat, 19 Mar 2011 22:03:40 +0000 (22:03 +0000)
In Perl_sighandler, we currently increment PL_markstack_ptr and
PL_scopestack_ix.

This was added back in 1997 in the era of unsafe signals, to make them
slightly less unsafe. The idea presumably was to stop signal handlers
inadvertently corrupting the top element of each stack. However, given that
the normal method of pushing something onto those stacks is to increment
the pointer before pushing the value, I don't see how that can happen.

The downside of this is that an uninitialised or stale value can be left
in the 'hole' left on these stacks. When exiting from a signal handler via
exit(), these holes can be read and corruption occur, while stack
unwinding is taking place. The ordering of things means we can't use
SAVEDESTRUCTOR_X to undo the damage.

This commit leaves the 'PL_savestack_ix += 5', because in this case, with
unsafe signals, it *is* possible to interrupt halfway through a new set of
save data being pushed onto the stack, and it *is* possible for this to be
undone via SAVEDESTRUCTOR_X. (But it's still unsafe and half-baked.)

This fixes [perl #85206].

mg.c

diff --git a/mg.c b/mg.c
index 7b5fdf5..447d86c 100644 (file)
--- a/mg.c
+++ b/mg.c
@@ -3035,14 +3035,6 @@ Perl_sighandler(int sig)
        PL_savestack_ix += 5;           /* Protect save in progress. */
        SAVEDESTRUCTOR_X(S_unwind_handler_stack, NULL);
     }
-    if (PL_markstack_ptr < PL_markstack_max - 2) {
-       flags |= 2;
-       PL_markstack_ptr++;             /* Protect mark. */
-    }
-    if (PL_scopestack_ix < PL_scopestack_max - 3) {
-       flags |= 4;
-       PL_scopestack_ix++;
-    }
     /* sv_2cv is too complicated, try a simpler variant first: */
     if (!SvROK(PL_psig_ptr[sig]) || !(cv = MUTABLE_CV(SvRV(PL_psig_ptr[sig])))
        || SvTYPE(cv) != SVt_PVCV) {
@@ -3132,10 +3124,6 @@ Perl_sighandler(int sig)
 cleanup:
     /* pop any of SAVEFREESV, SAVEDESTRUCTOR_X and "save in progress" */
     PL_savestack_ix = old_ss_ix;
-    if (flags & 2)
-       PL_markstack_ptr--;
-    if (flags & 4)
-       PL_scopestack_ix -= 1;
     if (flags & 8)
        SvREFCNT_dec(sv);
     PL_op = myop;                      /* Apparently not needed... */
@@ -3221,8 +3209,7 @@ S_restore_magic(pTHX_ const void *p)
 /* clean up the mess created by Perl_sighandler().
  * Note that this is only called during an exit in a signal handler;
  * a die is trapped by the call_sv() and the SAVEDESTRUCTOR_X manually
- * skipped over. This is why we don't need to fix up the markstack and
- * scopestack - they're going to be set to 0 anyway */
+ * skipped over. */
 
 static void
 S_unwind_handler_stack(pTHX_ const void *p)