Skip to content

Commit e52de15

Browse files
author
Father Chrysostomos
committed
Fix CvOUTSIDE assert/refcnt bugs with sub redefinition
my $sub = sub { 4 }; *foo = $sub; *bar = *foo; undef &$sub; eval "sub bar { 3 }"; undef *foo; undef *bar; As of 5.8.4, this script produces: Attempt to free unreferenced scalar: SV 0x8002c4. As of 5.14.0: panic: del_backref. Or, undef debugging builds: Assertion failed: (!CvWEAKOUTSIDE(cv)), function Perl_newATTRSUB_flags, file op.c, line 7045. Commit 5c41a5f (backported to 5.8.4 in commit 7a565e5) caused the first bug: commit 5c41a5f Author: Dave Mitchell <[email protected]> Date: Sun Jan 25 02:04:23 2004 +0000 Remove small memory leak in newATTRSUB that manifested as a leaking scalar after the interpeter was cloned p4raw-id: //depot/perl@22209 diff --git a/op.c b/op.c index b902fed..5fd21bf 100644 --- a/op.c +++ b/op.c @@ -4165,6 +4165,8 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block) /* transfer PL_compcv to cv */ cv_undef(cv); CvFLAGS(cv) = CvFLAGS(PL_compcv); + if (!CvWEAKOUTSIDE(cv)) + SvREFCNT_dec(CvOUTSIDE(cv)); CvOUTSIDE(cv) = CvOUTSIDE(PL_compcv); CvOUTSIDE_SEQ(cv) = CvOUTSIDE_SEQ(PL_compcv); CvOUTSIDE(PL_compcv) = 0; Checking the flags right after clobbering them can’t be a good idea. Commit 437388a caused the panics and assertion failures. See com- mit f6894bc for detail. Commit f6894bc fixed the panics and assertion failures involving CvGV. One remaining assertion (!CvWEAKOUTSIDE) added by 437388a is still incorrect. It’s not true that CvWEAKOUTSIDE is never set on a re- used stub. In both cases (5c41a5f’s code and 437388a’s code), the weakness of CvOUTSIDE is ignored and the outside sub (the eval) is freed prematurely. It could be that this type of redefinition should be disallowed (des- pite its usefulness), but that is a separate issue. This used to work. And pure-Perl code should not be triggering assertion failures or freeing scalars twice.
1 parent f6894bc commit e52de15

File tree

2 files changed

+18
-6
lines changed

2 files changed

+18
-6
lines changed

op.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7039,11 +7039,10 @@ Perl_newATTRSUB_flags(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
70397039
cv_flags_t existing_builtin_attrs = CvFLAGS(cv) & CVf_BUILTIN_ATTRS;
70407040
AV *const temp_av = CvPADLIST(cv);
70417041
CV *const temp_cv = CvOUTSIDE(cv);
7042-
const cv_flags_t slabbed = CvSLABBED(cv);
7042+
const cv_flags_t other_flags =
7043+
CvFLAGS(cv) & (CVf_SLABBED|CVf_WEAKOUTSIDE);
70437044
OP * const cvstart = CvSTART(cv);
70447045

7045-
assert(!CvWEAKOUTSIDE(cv));
7046-
70477046
CvGV_set(cv,gv);
70487047
assert(!CvCVGV_RC(cv));
70497048
assert(CvGV(cv) == gv);
@@ -7057,8 +7056,8 @@ Perl_newATTRSUB_flags(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
70577056
CvPADLIST(PL_compcv) = temp_av;
70587057
CvSTART(cv) = CvSTART(PL_compcv);
70597058
CvSTART(PL_compcv) = cvstart;
7060-
if (slabbed) CvSLABBED_on(PL_compcv);
7061-
else CvSLABBED_off(PL_compcv);
7059+
CvFLAGS(PL_compcv) &= ~(CVf_SLABBED|CVf_WEAKOUTSIDE);
7060+
CvFLAGS(PL_compcv) |= other_flags;
70627061

70637062
if (CvFILE(cv) && CvDYNFILE(cv)) {
70647063
Safefree(CvFILE(cv));

t/op/sub.t

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ BEGIN {
66
require './test.pl';
77
}
88

9-
plan( tests => 15 );
9+
plan( tests => 16 );
1010

1111
sub empty_sub {}
1212

@@ -72,3 +72,16 @@ fresh_perl_is
7272
eval 'sub bar { print +(caller 0)[3], "\n" }';
7373
bar();
7474
end
75+
76+
fresh_perl_is
77+
<<'end', "main::foo\nok\n", {}, 'no double free redefining anon stub';
78+
my $sub = sub { 4 };
79+
*foo = $sub;
80+
*bar = *foo;
81+
undef &$sub;
82+
eval 'sub bar { print +(caller 0)[3], "\n" }';
83+
&$sub;
84+
undef *foo;
85+
undef *bar;
86+
print "ok\n";
87+
end

0 commit comments

Comments
 (0)