Skip to content

Commit 59b7881

Browse files
committed
cv_undef_flags: there's nothing to clean up for our subs in cloned pads
Fixes #21067 When an instance of a closure is created, the pad entries for the cloned sub are copied (S_clone_sv_pad()) from either the prototype sub (for lexicals belonging to the sub) or from the context (for lexicals from outside the sub). This doesn't happen for our variables, instead the cloned sub has these pad entries set to NULL. This isn't an issue at runtime since references to lexical our sub/variables are compiled into GV or GVSV ops. cv_undef_flags() assumed this these entries were non-NULL for all lexical subs. Fix by checking if the entry is an our sub and the CV being freed is a clone, if so, skip the accesses to the NULL pad entry. Added an assert to the new branch to ensure any changes in the above results in an early failure here and hopefully a fix.
1 parent 3a3155d commit 59b7881

File tree

2 files changed

+16
-4
lines changed

2 files changed

+16
-4
lines changed

pad.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -401,9 +401,12 @@ Perl_cv_undef_flags(pTHX_ CV *cv, U32 flags)
401401
SV ** const curpad = AvARRAY(comppad);
402402
for (ix = PadnamelistMAX(comppad_name); ix > 0; ix--) {
403403
PADNAME * const name = namepad[ix];
404-
if (name && PadnamePV(name) && *PadnamePV(name) == '&')
405-
{
406-
CV * const innercv = MUTABLE_CV(curpad[ix]);
404+
if (name && PadnamePV(name) && *PadnamePV(name) == '&') {
405+
CV * const innercv = MUTABLE_CV(curpad[ix]);
406+
if (PadnameIsOUR(name) && CvCLONED(&cvbody)) {
407+
assert(!innercv);
408+
}
409+
else {
407410
U32 inner_rc;
408411
assert(innercv);
409412
assert(SvTYPE(innercv) != SVt_PVFM);
@@ -433,6 +436,7 @@ Perl_cv_undef_flags(pTHX_ CV *cv, U32 flags)
433436
}
434437
}
435438
}
439+
}
436440
}
437441
}
438442

t/op/lexsub.t

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ BEGIN {
77
*bar::is = *is;
88
*bar::like = *like;
99
}
10-
plan 151;
10+
plan 152;
1111

1212
# -------------------- our -------------------- #
1313

@@ -106,6 +106,14 @@ sub bar::_cmp { $b cmp $a }
106106
is join(" ", sort _cmp split //, 'oursub'), 'u u s r o b', 'sort our_sub'
107107
}
108108

109+
# https://github.com/Perl/perl5/issues/21067
110+
# this would crash/assert
111+
fresh_perl_is(<<'PROG', "ok", { }, "pad cleanup for a closure referring to an our sub");
112+
our sub foo;
113+
0 if sub { eval "" if 0; \&foo if 0; };
114+
print "ok";
115+
PROG
116+
109117
# -------------------- state -------------------- #
110118

111119
use feature 'state'; # state

0 commit comments

Comments
 (0)