summaryrefslogtreecommitdiff
path: root/scope.c
diff options
context:
space:
mode:
authorPaul "LeoNerd" Evans <leonerd@leonerd.org.uk>2020-06-27 16:09:49 +0100
committerPaul Evans <leonerd@leonerd.org.uk>2020-07-20 15:40:42 +0100
commitae955d3a183337a4770d39640a21da146cf97bc7 (patch)
tree989e9fabb2b3f451857b67831ca453b85a334841 /scope.c
parentc1d551e18b0505f4fadf5d7cd6b07de35589bd42 (diff)
downloadperl-ae955d3a183337a4770d39640a21da146cf97bc7.tar.gz
Ensure stack is in consistent state while restoring SAVEt_HINTS
SAVEt_HINTS has a non-constant savestack structure. If the HINT_LOCALIZE_HH flag was set it pushes an additional pointer. In some complex code scenarios it is possible reënter Perl code while destroying nested PL_hintgv hashes (for example, if any stored objects contain `free` magic). Because of this, it is important that we pop the extra value from the save stack before any other code can be invoked, so if they need to inspect or alter the save stack, they can do so in a consistent manner. See also https://github.com/Perl/perl5/issues/17895
Diffstat (limited to 'scope.c')
-rw-r--r--scope.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/scope.c b/scope.c
index a948a7b4f2..df2e3c7194 100644
--- a/scope.c
+++ b/scope.c
@@ -1348,7 +1348,12 @@ Perl_leave_scope(pTHX_ I32 base)
break;
case SAVEt_HINTS:
+ {
+ HV *was_hinthv;
a0 = ap[0]; a1 = ap[1];
+ if (a0.any_i32 & HINT_LOCALIZE_HH) {
+ was_hinthv = MUTABLE_HV(SSPOPPTR);
+ }
if ((PL_hints & HINT_LOCALIZE_HH)) {
while (GvHV(PL_hintgv)) {
HV *hv = GvHV(PL_hintgv);
@@ -1361,7 +1366,7 @@ Perl_leave_scope(pTHX_ I32 base)
*(I32*)&PL_hints = a0.any_i32;
if (PL_hints & HINT_LOCALIZE_HH) {
SvREFCNT_dec(MUTABLE_SV(GvHV(PL_hintgv)));
- GvHV(PL_hintgv) = MUTABLE_HV(SSPOPPTR);
+ GvHV(PL_hintgv) = was_hinthv;
}
if (!GvHV(PL_hintgv)) {
/* Need to add a new one manually, else rv2hv can
@@ -1372,6 +1377,7 @@ Perl_leave_scope(pTHX_ I32 base)
}
assert(GvHV(PL_hintgv));
break;
+ }
case SAVEt_COMPPAD:
a0 = ap[0];