summaryrefslogtreecommitdiff
path: root/toke.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2015-02-04 22:11:06 -0800
committerFather Chrysostomos <sprout@cpan.org>2015-02-05 09:15:16 -0800
commit67c71cbbd62a75ff2b913421806f6ea0f0b33558 (patch)
treee48b2d8f3a50e1d84c1eeef007d8e07c3e38a51f /toke.c
parentd9a13252ba5aad7b3eaaff069b56472cfb651a40 (diff)
downloadperl-67c71cbbd62a75ff2b913421806f6ea0f0b33558.tar.gz
Fix double free with const overload after errors
The PL_lex_stuff variable in the parser struct is reference-counted. Yet, in toke.c:S_sublex_start we pass the value to S_tokeq, which may pass it to S_new_constant, which takes ownership of the reference count (possibly freeing or mortalising the SV), and then relinquishes its ownership of the returned SV (incrementing the reference count if it is the same SV passed to it). If S_new_constant croaks, then it will have mortalised the SV passed to it while PL_lex_stuff still points to it. This example makes S_new_constant croak indirectly, by causing its yyerror call to croak because of the number of errors: $ perl5.20.1 -e 'BEGIN { $^H|=0x8000} undef(1,2); undef(1,2); undef(1,2); undef(1,2); undef(1,2); undef(1,2); undef(1,2); undef(1,2); undef(1,2); "a"' Too many arguments for undef operator at -e line 1, near "2)" Too many arguments for undef operator at -e line 1, near "2)" Too many arguments for undef operator at -e line 1, near "2)" Too many arguments for undef operator at -e line 1, near "2)" Too many arguments for undef operator at -e line 1, near "2)" Too many arguments for undef operator at -e line 1, near "2)" Too many arguments for undef operator at -e line 1, near "2)" Too many arguments for undef operator at -e line 1, near "2)" Too many arguments for undef operator at -e line 1, near "2)" Constant(q) unknown at -e line 1, near ";"a"" -e has too many errors. Attempt to free unreferenced scalar: SV 0x7fb49882fae8 at -e line 1.
Diffstat (limited to 'toke.c')
-rw-r--r--toke.c5
1 files changed, 3 insertions, 2 deletions
diff --git a/toke.c b/toke.c
index c0a5b3123f..b67ca0d60e 100644
--- a/toke.c
+++ b/toke.c
@@ -2276,7 +2276,9 @@ S_sublex_start(pTHX)
return THING;
}
if (op_type == OP_CONST) {
- SV *sv = tokeq(PL_lex_stuff);
+ SV *sv = PL_lex_stuff;
+ PL_lex_stuff = NULL;
+ sv = tokeq(sv);
if (SvTYPE(sv) == SVt_PVIV) {
/* Overloaded constants, nothing fancy: Convert to SVt_PV: */
@@ -2287,7 +2289,6 @@ S_sublex_start(pTHX)
sv = nsv;
}
pl_yylval.opval = (OP*)newSVOP(op_type, 0, sv);
- PL_lex_stuff = NULL;
return THING;
}