diff options
author | David Mitchell <davem@iabyn.com> | 2012-04-11 13:37:09 +0100 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2012-04-11 14:20:53 +0100 |
commit | 2653c1e3b10f71430de1ab8ab0417ca5b048ab19 (patch) | |
tree | 6bd9a1c4a68d9cc5a551584aa3255afd35a3f952 /scope.c | |
parent | 629e8f5e3a9b318b663e6fbb0025a6b0c03deffe (diff) | |
download | perl-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.c | 7 |
1 files changed, 4 insertions, 3 deletions
@@ -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: |