Skip to content

Commit 059a773

Browse files
leonerdkhwilliamson
authored andcommitted
Initial hack at restoring iter var value after refaliased foreach
1 parent f3270e3 commit 059a773

File tree

3 files changed

+89
-3
lines changed

3 files changed

+89
-3
lines changed

inline.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4152,6 +4152,48 @@ Perl_cx_poploop(pTHX_ PERL_CONTEXT *cx)
41524152
cx->blk_loop.itersave = NULL;
41534153
SvREFCNT_dec(cursv);
41544154
}
4155+
if (cx->cx_type & CXp_FOR_LVREF) {
4156+
SV *itervar = (SV *)(cx)->blk_loop.itervar_u.gv;
4157+
SV *origval = (cx)->blk_loop.itersave;
4158+
assert(SvTYPE(itervar) == SVt_PVMG);
4159+
MAGIC *mg = SvMAGIC(itervar);
4160+
assert(mg);
4161+
assert(mg->mg_type == PERL_MAGIC_lvref);
4162+
if (!mg->mg_obj) {
4163+
// LV ref around a lexical, mg_len gives its pad index
4164+
SV **padslot = &PAD_SVl(mg->mg_len);
4165+
SV *oldsv = *padslot;
4166+
*padslot = origval;
4167+
SvREFCNT_dec(oldsv);
4168+
}
4169+
else {
4170+
// LV ref around a package lexical, mg_obj gives its GV
4171+
GV *gv = (GV *)mg->mg_obj;
4172+
SV *oldsv;
4173+
switch(mg->mg_private & OPpLVREF_TYPE) {
4174+
case OPpLVREF_SV:
4175+
oldsv = GvSVn(gv);
4176+
GvSVn(gv) = origval;
4177+
break;
4178+
4179+
case OPpLVREF_AV:
4180+
oldsv = (SV *)GvAV(gv);
4181+
GvAV(gv) = (AV *)origval;
4182+
break;
4183+
4184+
case OPpLVREF_HV:
4185+
oldsv = (SV *)GvHV(gv);
4186+
GvHV(gv) = (HV *)origval;
4187+
break;
4188+
4189+
case OPpLVREF_CV:
4190+
oldsv = (SV *)GvCV(gv);
4191+
GvCV_set(gv, (CV *)origval);
4192+
break;
4193+
}
4194+
SvREFCNT_dec(oldsv);
4195+
}
4196+
}
41554197
if (cx->cx_type & (CXp_FOR_GV|CXp_FOR_LVREF))
41564198
SvREFCNT_dec(cx->blk_loop.itervar_u.svp);
41574199
}

pp_ctl.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2622,9 +2622,26 @@ PP(pp_enteriter)
26222622
}
26232623
else { /* LV ref: for \$foo (...) */
26242624
assert(SvTYPE(sv) == SVt_PVMG);
2625-
assert(SvMAGIC(sv));
2626-
assert(SvMAGIC(sv)->mg_type == PERL_MAGIC_lvref);
26272625
itersave = NULL;
2626+
MAGIC *mg = SvMAGIC(sv);
2627+
assert(mg);
2628+
assert(mg->mg_type == PERL_MAGIC_lvref);
2629+
if (!mg->mg_obj) {
2630+
// LV ref around a lexical, mg_len gives its pad index
2631+
itersave = SvREFCNT_inc_NN(PAD_SV(mg->mg_len));
2632+
}
2633+
else {
2634+
// LV ref around a package lexical, mg_obj gives its GV
2635+
GV *gv = (GV *)mg->mg_obj;
2636+
assert(SvTYPE(gv) == SVt_PVGV);
2637+
switch(mg->mg_private & OPpLVREF_TYPE) {
2638+
case OPpLVREF_SV: itersave = GvSVn(gv); break;
2639+
case OPpLVREF_AV: itersave = (SV *)GvAV(gv); break;
2640+
case OPpLVREF_HV: itersave = (SV *)GvHV(gv); break;
2641+
case OPpLVREF_CV: itersave = (SV *)GvCV(gv); break;
2642+
}
2643+
SvREFCNT_inc_void(itersave);
2644+
}
26282645
cxflags = CXp_FOR_LVREF;
26292646
}
26302647
/* we transfer ownership of 1 ref count of itervarp from the stack

t/op/decl-refs.t

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ BEGIN {
44
set_up_inc('../lib');
55
}
66

7-
plan 402;
7+
plan 408;
88

99
for my $decl (qw< my CORE::state our local >) {
1010
for my $funny (qw< $ @ % >) {
@@ -120,3 +120,30 @@ ENE
120120
$code =~ s/is ?no?t/is/g if $decl eq 'our';
121121
eval $code or die $@;
122122
}}
123+
124+
# GH#24028
125+
{
126+
my $slexical = 42;
127+
for \$slexical ( \1, \2, \3 ) { }
128+
is $slexical, 42, 'scalar lexical restored after foreach-refalias';
129+
130+
my @alexical = (42);
131+
for \@alexical ( [1], [2], [3] ) { }
132+
is $alexical[0], 42, 'array lexical restored after foreach-refalias';
133+
134+
my %hlexical = (k => 42);
135+
for \%hlexical ( {k => 1}, {k => 2}, {k => 3} ) { }
136+
is $hlexical{k}, 42, 'hash lexical restored after foreach-refalias';
137+
138+
our $spkgvar = 84;
139+
for \$spkgvar ( \1, \2, \3 ) { }
140+
is $spkgvar, 84, 'scalar pkgvar restored after foreach-refalias';
141+
142+
our @apkgvar = (84);
143+
for \@apkgvar ( [1], [2], [3] ) { }
144+
is $apkgvar[0], 84, 'array pkgvar restored after foreach-refalias';
145+
146+
our %hpkgvar = (k => 84);
147+
for \%hpkgvar ( {k => 1}, {k => 2}, {k => 3} ) { }
148+
is $hpkgvar{k}, 84, 'hash pkgvar restored after foreach-refalias';
149+
}

0 commit comments

Comments
 (0)