This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Ensure stack is in consistent state while restoring SAVEt_HINTS
authorPaul "LeoNerd" Evans <leonerd@leonerd.org.uk>
Sat, 27 Jun 2020 15:09:49 +0000 (16:09 +0100)
committerPaul Evans <leonerd@leonerd.org.uk>
Mon, 20 Jul 2020 14:40:42 +0000 (15:40 +0100)
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

scope.c

diff --git a/scope.c b/scope.c
index a948a7b..df2e3c7 100644 (file)
--- a/scope.c
+++ b/scope.c
@@ -1348,7 +1348,12 @@ Perl_leave_scope(pTHX_ I32 base)
            break;
 
        case SAVEt_HINTS:
            break;
 
        case SAVEt_HINTS:
+        {
+           HV *was_hinthv;
             a0 = ap[0]; a1 = ap[1];
             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);
            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)));
            *(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
            }
            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;
            }
            assert(GvHV(PL_hintgv));
            break;
+        }
 
        case SAVEt_COMPPAD:
             a0 = ap[0];
 
        case SAVEt_COMPPAD:
             a0 = ap[0];