summaryrefslogtreecommitdiff
path: root/scope.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2012-04-11 13:37:09 +0100
committerDavid Mitchell <davem@iabyn.com>2012-04-11 14:20:53 +0100
commit2653c1e3b10f71430de1ab8ab0417ca5b048ab19 (patch)
tree6bd9a1c4a68d9cc5a551584aa3255afd35a3f952 /scope.c
parent629e8f5e3a9b318b663e6fbb0025a6b0c03deffe (diff)
downloadperl-2653c1e3b10f71430de1ab8ab0417ca5b048ab19.tar.gz
stop %^H pointing to being-freed hash; #112326
The leave_scope() action SAVEt_HINTS does the following to GvHV(PL_hintgv): first it SvREFCNT_dec()'s it, then sets it to NULL. If the current %^H contains a destructor, then that will be executed while %^H still points to the hash being freed. This can cause bad things to happen, like iterating over the hash being freed. Instead, setGvHV(PL_hintgv) to NULL first, *then* free the hash.
Diffstat (limited to 'scope.c')
-rw-r--r--scope.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/scope.c b/scope.c
index cc207c089c..1bf79e0227 100644
--- a/scope.c
+++ b/scope.c
@@ -1024,8 +1024,9 @@ Perl_leave_scope(pTHX_ I32 base)
break;
case SAVEt_HINTS:
if ((PL_hints & HINT_LOCALIZE_HH) && GvHV(PL_hintgv)) {
- SvREFCNT_dec(MUTABLE_SV(GvHV(PL_hintgv)));
+ HV *hv = GvHV(PL_hintgv);
GvHV(PL_hintgv) = NULL;
+ SvREFCNT_dec(MUTABLE_SV(hv));
}
cophh_free(CopHINTHASH_get(&PL_compiling));
CopHINTHASH_set(&PL_compiling, (COPHH*)SSPOPPTR);
@@ -1033,8 +1034,8 @@ Perl_leave_scope(pTHX_ I32 base)
if (PL_hints & HINT_LOCALIZE_HH) {
SvREFCNT_dec(MUTABLE_SV(GvHV(PL_hintgv)));
GvHV(PL_hintgv) = MUTABLE_HV(SSPOPPTR);
- assert(GvHV(PL_hintgv));
- } else if (!GvHV(PL_hintgv)) {
+ }
+ if (!GvHV(PL_hintgv)) {
/* Need to add a new one manually, else gv_fetchpv() can
add one in this code: