This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #113872] Fix leavewrite’s stack handling
authorFather Chrysostomos <sprout@cpan.org>
Thu, 26 Jul 2012 07:16:00 +0000 (00:16 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Thu, 26 Jul 2012 07:23:12 +0000 (00:23 -0700)
This commit fixes Scope::Escape compatibility by restoring the old
stack pointer stored on the context stack when exiting a write.

I don’t really understand why this fixes Scope::Escape, or rather, how
Scope::Escape ends up leaving some number of items on the stack other
than 1.  But I *do* know this is the correct approach, as it mirrors
what pp_leavesub does in scalar context, but pops the stack back
to the old value (SP = newsp), rather than the old value+1 (see
pp_hot.c:pp_leavesub: MARK = newsp + 1; and later SP = MARK;).  Then
the code that follows takes care of pushing write’s own return value.

pp_sys.c

index a17227d..549256b 100644 (file)
--- a/pp_sys.c
+++ b/pp_sys.c
@@ -1394,12 +1394,6 @@ PP(pp_leavewrite)
     register PERL_CONTEXT *cx;
     OP *retop;
 
-    /* I'm not sure why, but executing the format leaves an extra value on the
-     * stack. There's probably a better place to be handling this (probably
-     * by avoiding pushing it in the first place!) but I don't quite know
-     * where to look. -doy */
-    (void)POPs;
-
     if (!io || !(ofp = IoOFP(io)))
         goto forget_top;
 
@@ -1469,13 +1463,14 @@ PP(pp_leavewrite)
            gv_efullname4(sv, fgv, NULL, FALSE);
            DIE(aTHX_ "Undefined top format \"%"SVf"\" called", SVfARG(sv));
        }
-       RETURNOP(doform(cv, gv, PL_op));
+       return doform(cv, gv, PL_op);
     }
 
   forget_top:
     POPBLOCK(cx,PL_curpm);
     POPFORMAT(cx);
     retop = cx->blk_sub.retop;
+    SP = newsp; /* ignore retval of formline */
     LEAVE;
 
     fp = IoOFP(io);
@@ -1503,7 +1498,6 @@ PP(pp_leavewrite)
     }
     /* bad_ofp: */
     PL_formtarget = PL_bodytarget;
-    PERL_UNUSED_VAR(newsp);
     PERL_UNUSED_VAR(gimme);
     RETURNOP(retop);
 }