In perl.git, the branch blead has been updated <http://perl5.git.perl.org/perl.git/commitdiff/c82de78e3ba0184f85b5b49245e5da32d1cb3fcc?hp=e487ff5ee8f0cde894977f61d319c0c4e44aa0bd>
- Log ----------------------------------------------------------------- commit c82de78e3ba0184f85b5b49245e5da32d1cb3fcc Author: Father Chrysostomos <spr...@cpan.org> Date: Mon Aug 15 18:09:17 2016 -0700 [perl #126482] Fix assert fail âa_const a_constâ Mentioning a constant twice in a row results in an assertion failure: $ ./miniperl -e 'sub ub(){0} ub ub' Assertion failed: (SvTYPE(cv) == SVt_PVCV || SvTYPE(cv) == SVt_PVFM), function Perl_cv_const_sv_or_av, file op.c, line 7926. Abort trap: 6 A bisect points to 2eaf799e7, but I donât understand why that commit introduced it. I suspect it was failing an assertion for a slightly different reason back then, but am too lazy to check. In any case, it fails now because, while âub ubâ is being compiled, when the sub is looked up initially (in toke.c:yylex), we call rv2cv_op_cv with the RV2GVOPCV_RETURN_STUB flag, which allows a bare constant ref to be returned. So the âcvâ variable contains an RV (\0): cv = lex ? isGV(gv) ? GvCV(gv) : SvROK(gv) && SvTYPE(SvRV(gv)) == SVt_PVCV ? (CV *)SvRV(gv) : ((CV *)gv) : rv2cv_op_cv(rv2cv_op, RV2CVOPCV_RETURN_STUB); (âubâ here is a constant 0, which is stored in the symbol table as \0; i.e., âsub ub(){0}â is equivalent to âBEGIN { $::{ub} = \0 }â.) Then if we see a word immediately following it (the second âubâ) we check a little further down to see whether it might be a method call. That entails calling intuit_method, which does this: indirgv = gv_fetchpvn_flags(tmpbuf, len, ( UTF ? SVf_UTF8 : 0 ), SVt_PVCV); if (indirgv && GvCVu(indirgv)) return 0; So we are looking to see whether the second word refers to a sub and deciding this is not an indirect method call if there is a sub. But calling gv_fetchpvn_flags like that has the effect of upgrading the symbol table entry to a full GV. Since the âcvâ variable in yylex points to that symbol table entry, it ends up pointing to a GV, which certain code later on does not expect to happen. So we should pass the GV_NOADD_NOINIT flag to gv_fetchpvn_flags to prevent lookup of the second bareword from upgrading the entry (we already do that earlier in intuit_method for the first bareword). We only check the GV to see whether it has a sub or io thingy in it any- way, so we donât actually need a full GV. (As a bonus, GvIO will already work on a non-GV and return NULL, so that part of the code remains unchanged.) ----------------------------------------------------------------------- Summary of changes: t/op/method.t | 6 +++++- toke.c | 7 +++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/t/op/method.t b/t/op/method.t index a9666bb..596f869 100644 --- a/t/op/method.t +++ b/t/op/method.t @@ -13,7 +13,7 @@ BEGIN { use strict; no warnings 'once'; -plan(tests => 150); +plan(tests => 151); @A::ISA = 'B'; @B::ISA = 'C'; @@ -704,6 +704,10 @@ SKIP: { "check unknown import() methods don't corrupt the stack"); } +like runperl(prog => 'sub ub(){0} ub ub', stderr=>1), qr/Bareword found/, + '[perl #126482] Assert failure when mentioning a constant twice in a row'; + + __END__ #FF9900 #F78C08 diff --git a/toke.c b/toke.c index 5e11253..b0e3736 100644 --- a/toke.c +++ b/toke.c @@ -4096,8 +4096,11 @@ S_intuit_method(pTHX_ char *start, SV *ioname, CV *cv) tmpbuf[len] = '\0'; goto bare_package; } - indirgv = gv_fetchpvn_flags(tmpbuf, len, ( UTF ? SVf_UTF8 : 0 ), SVt_PVCV); - if (indirgv && GvCVu(indirgv)) + indirgv = gv_fetchpvn_flags(tmpbuf, len, + GV_NOADD_NOINIT|( UTF ? SVf_UTF8 : 0 ), + SVt_PVCV); + if (indirgv && SvTYPE(indirgv) != SVt_NULL + && (!isGV(indirgv) || GvCVu(indirgv))) return 0; /* filehandle or package name makes it a method */ if (!cv || GvIO(indirgv) || gv_stashpvn(tmpbuf, len, UTF ? SVf_UTF8 : 0)) { -- Perl5 Master Repository