In perl.git, the branch blead has been updated

<http://perl5.git.perl.org/perl.git/commitdiff/95c0a761e6d0916fd6abd02af5a344be7de9ecdb?hp=2799b159a376d29e518b47c469185f745cb3c97f>

- Log -----------------------------------------------------------------
commit 95c0a761e6d0916fd6abd02af5a344be7de9ecdb
Author: Father Chrysostomos <spr...@cpan.org>
Date:   Sat Sep 10 07:27:43 2016 -0700

    pad.c:pad_fixup_inner_anons: Add assertions
    
    These would have made it easier to track down the bug fixed by
    the previous commit.

M       pad.c

commit 6da13066b6bcab52b33b8891e90130d243b7faa1
Author: Father Chrysostomos <spr...@cpan.org>
Date:   Sat Sep 10 07:24:41 2016 -0700

    [perl #129090] Crash with sub c{sub c}
    
    The crash in the bug report was caused by v5.21.7-215-g307cbb9, which
    added the code in question in order to fix another crash.  It exposed
    an existing problem caused by v5.21.6-386-ga70f21d.
    
    Some background:
    
    When parsing ‘sub c{’, perl creates a new CV.  The CV gets installed
    in the symbol table when the final ‘}’ is reached.
    
    If there is already an undefined CV at that point, it gets reused and
    the contents of the new CV are transferred to the existing one.  That
    means that any subs defined within now have their CvOUTSIDE pointer
    pointing to a stub that is about to be freed, so pad_fix_inner_anons
    gets called to update those CvOUTSIDE pointers accordingly.
    
    Formats were not getting their CvOUTSIDE pointers updated, so commit
    v5.11.2-160-g421f30e added formats to the containing sub’s pad to
    allow the CvOUTSIDE fix-up to apply to them, too.
    
    That caused a crash, as explained in the commit message for
    v5.17.1-213-ge09ac07, that the cited commit fixed by putting a weak RV
    in the pad, not a direct pointer to the format, and giving the format
    a strong CvOUTSIDE pointer.
    
    Problem:
    
    Commit v5.21.6-386-ga70f21d¹ fixed a problem with named subs not cor-
    rectly referencing outer state vars (because of bad CvOUTSIDE point-
    ers hiding the lexical vars).  It did so by extending the mechanism
    already used for formats to apply to named subs as well.
    
    The one mistake that that commit made was to add a pad entry for the
    sub even if it was just a stub declaration.  That caused a sub with a
    stub declaration inside it to a loop if they have the same name:
    
    $ ./perl -Ilib -le '%c; sub c { sub c; eval q|$x| } c'
    
    This happens because the ‘sub c;’ inserts a stub into the symbol table
    and inserts a reference to that stub also into the pad of the sub cur-
    rently being compiled.  The final CvOUTSIDE fix-up sets the CvOUTSIDE
    of the erstwhile stub (that has just become the newly defined sub) to
    the sub itself.  (The %c in the example is necessary to vivify the
    typeglob; otherwise perl will cheat and the stub declaration won’t
    actually create a CV.)
    
    In addition, a crash can occur in this one-liner (reduced from the
    original bug report):
    
    $ ./miniperl -e '$a="a$a";my sub b;%c;sub c{sub b;sub c}'
    
    The fix-up code iterates through the pad backwards, starting from the
    last entry, so the CvOUTSIDE(c) -> c loop is set up before the lexical
    &b entry is encountered.  When it is encountered, CvOUTSIDE pointers
    are followed to find the outer pad where b is defined, but the
    PARENT_PAD_INDEX stored in the &b padname is wrong for c’s own pad,
    which is what we end up looking at due to the CvOUTSIDE loop.  The
    ‘outer’ entry may then turn out be an RV, not a CV, or just about any-
    thing.  Crashes ensue.
    
    Another, perhaps clearer, way to make it crash is to give the lexical
    sub pad entry an outer offset far beyond the end of the directly-
    enclosing sub:
    
    $ ./perl -Ilib -lE '%c; my 
($a,$b,$c,$d,$e,$f,$g,$h,$i,$j,$k,$l,$m,$n,$o,$p,$q,$r,$s,$t,$u); state sub b; 
sub c { sub b {} sub c }'
    Segmentation fault: 11
    
    Solution:
    
    The fix is to stop package stubs from creating pad entries.
    
    ¹ Which I found by bisecting like this, in case anyone is interested:
        ../perl.git/Porting/bisect.pl --expect-fail  --start=v5.20.0 
--end=v5.22.0  -e '%c; sub c{sub c}; use B; print 
B::svref_2object(\&c)->PADLIST->ARRAYelt(0)->ARRAYelt(1)->PV'

M       op.c
M       t/op/sub.t

commit bbd6d871a56f710514d051bb71c3909085b11daf
Author: Father Chrysostomos <spr...@cpan.org>
Date:   Thu Sep 8 22:17:34 2016 -0700

    op.c: Avoid string cmp when unnecessary

M       op.c

commit 9c426bfddbdd904fc37d276cc68e6f2ec04251f4
Author: Father Chrysostomos <spr...@cpan.org>
Date:   Thu Sep 8 14:25:09 2016 -0700

    toke.c: Correct comment

M       toke.c
-----------------------------------------------------------------------

Summary of changes:
 op.c       |  4 ++--
 pad.c      |  2 ++
 t/op/sub.t | 14 ++++++++++++++
 toke.c     |  3 ++-
 4 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/op.c b/op.c
index 10a6db1..66cac9b 100644
--- a/op.c
+++ b/op.c
@@ -8686,7 +8686,7 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP 
*attrs,
     }
 
     /* don't copy new BEGIN CV to old BEGIN CV - RT #129099 */
-    if (name && *name == 'B' && strEQ(name, "BEGIN"))
+    if (name && cv && *name == 'B' && strEQ(name, "BEGIN"))
         cv = NULL;
 
     if (cv) {                          /* must reuse cv if autoloaded */
@@ -8875,7 +8875,7 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP 
*attrs,
     if (slab)
        Slab_to_ro(slab);
 #endif
-    if (cv && name && CvOUTSIDE(cv) && !CvEVAL(CvOUTSIDE(cv)))
+    if (cv && name && block && CvOUTSIDE(cv) && !CvEVAL(CvOUTSIDE(cv)))
        pad_add_weakref(cv);
     }
     return cv;
diff --git a/pad.c b/pad.c
index a41d2c7..7cf1fe3 100644
--- a/pad.c
+++ b/pad.c
@@ -2376,6 +2376,7 @@ Perl_pad_fixup_inner_anons(pTHX_ PADLIST *padlist, CV 
*old_cv, CV *new_cv)
            PADNAME **names = namepad;
            PADOFFSET i = ix;
            while (PadnameOUTER(name)) {
+               assert(SvTYPE(cv) == SVt_PVCV);
                cv = CvOUTSIDE(cv);
                names = PadlistNAMESARRAY(CvPADLIST(cv));
                i = PARENT_PAD_INDEX(name);
@@ -2406,6 +2407,7 @@ Perl_pad_fixup_inner_anons(pTHX_ PADLIST *padlist, CV 
*old_cv, CV *new_cv)
            assert(SvWEAKREF(rv));
            innercv = (CV *)SvRV(rv);
            assert(!CvWEAKOUTSIDE(innercv));
+           assert(CvOUTSIDE(innercv) == old_cv);
            SvREFCNT_dec(CvOUTSIDE(innercv));
            CvOUTSIDE(innercv) = (CV *)SvREFCNT_inc_simple_NN(new_cv);
          }
diff --git a/t/op/sub.t b/t/op/sub.t
index 05fd018..07fa033 100644
--- a/t/op/sub.t
+++ b/t/op/sub.t
@@ -415,3 +415,17 @@ sub curpm {
 }
 "a" =~ /(.)/;
 is(curpm(), 'c', 'return and PL_curpm');
+
+# [perl #129090] Crashes and hangs
+watchdog 10;
+{ no warnings;
+  eval '$a=qq|a$a|;my sub b;%c;sub c{sub b;sub c}';
+}
+eval '
+   ()= %d;
+   {my ($a,$b,$c,$d,$e,$f,$g,$h,$i,$j,$k,$l,$m,$n,$o,$p,$q,$r,$s,$t,$u);}
+   {my ($a,$b,$c,$d,$e,$f,$g,$h,$i,$j,$k,$l,$m,$n,$o,$p,$q,$r,$s,$t,$u);}
+   {my ($a,$b,$c,$d,$e,$f,$g,$h,$i,$j,$k,$l,$m,$n,$o,$p,$q,$r,$s,$t,$u);}
+   CORE::state sub b; sub d { sub b {} sub d }
+ ';
+eval '()=%e; sub e { sub e; eval q|$x| } e;';
diff --git a/toke.c b/toke.c
index c56b632..5fed84d 100644
--- a/toke.c
+++ b/toke.c
@@ -9812,7 +9812,8 @@ S_scan_heredoc(pTHX_ char *s)
 
 /* scan_inputsymbol
    takes: position of first '<' in input buffer
-   returns: position of first char following the last '>' in input buffer
+   returns: position of first char following the matching '>' in
+           input buffer
    side-effects: pl_yylval and lex_op are set.
 
    This code handles:

--
Perl5 Master Repository

Reply via email to