summaryrefslogtreecommitdiff
path: root/toke.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2016-08-15 18:09:17 -0700
committerFather Chrysostomos <sprout@cpan.org>2016-08-16 09:25:00 -0700
commitc82de78e3ba0184f85b5b49245e5da32d1cb3fcc (patch)
tree2dc10975242a671f2438395cffe89da988dc36a2 /toke.c
parente487ff5ee8f0cde894977f61d319c0c4e44aa0bd (diff)
downloadperl-c82de78e3ba0184f85b5b49245e5da32d1cb3fcc.tar.gz
[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.)
Diffstat (limited to 'toke.c')
-rw-r--r--toke.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/toke.c b/toke.c
index 5e112533b2..b0e3736cc8 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)) {