diff options
author | Father Chrysostomos <sprout@cpan.org> | 2012-04-15 22:01:26 -0700 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2012-04-16 10:44:50 -0700 |
commit | 3607ca02d65ff63a9322effaf09e60361984e109 (patch) | |
tree | 0bff084aed0f65e993ed4204dd4f2f639862625e /scope.c | |
parent | 8376a7bfebc88cd8955782fa2c6b6ce3a54a7cb0 (diff) | |
download | perl-3607ca02d65ff63a9322effaf09e60361984e109.tar.gz |
[perl #112444] Don’t leak %^H autovivified by destructor
More precisely, don’t let a hint hash autovivified by a destructor
during scope exit leak to outer scopes.
GvHV(PL_hintgv) (aka *^H{HASH}) must be set to null before the hash in
it is freed on scope exit. Otherwise destructors will see %^H with a
refcount of zero, and might try to iterate over a hash that is in the
process of being freed. Bad things then happen. Commit 2653c1e3b1
took care of this.
Now, if GvHV(PL_hintgv) is null when destructors are called, those
destructors might end up autovivifying it. The code in scope.c that
handles hints when a scope is left (SAVEt_HINTS in Perl_leave_scope)
would then end up leaving that new autovivified %^H in place when the
scope exited, if the outer scope did not have HINT_LOCALIZE_HH set
(meaning %^H was unused).
That in itself would not be so much of a problem, if it were not for
the fact that %^H is magicalised by the scope-handling code, not when
it is autovivified (see also bug #112458). Hence, subsequent changes
to %^H would not magically set the HINT_LOCALIZE_HH hint bit, which
bit is checked all over the place to see whether %^H is in use. This,
in turn, would cause hints subsequently added to %^H to leak to
outer scopes.
This commit fixes that by repeatedly freeing GvHV(PL_hintgv). If a
destructor autovivifies it again, it just causes another iteration of
the while loop. This does mean a destructor could autovivify %^H and
cause the new %^H itself to trigger a destructor, resulting in infi-
nite loops. But then that is that own code’s fault.
This originally came up because commit 2653c1e3b1 also caused des-
tructors that try to add new free magic to %^H to add it to a new
autovivified %^H instead of the existing %^H that was being freed.
This caused the nextgen module to fail its tests, because it uses
B::Hooks::EndOfScope to register a sub to be called on scope exit, and
it does this from a destructor itself called during scope exit. If
the autovivified %^H leaks to an outer scope, the second destructor is
not called.
Diffstat (limited to 'scope.c')
-rw-r--r-- | scope.c | 4 |
1 files changed, 3 insertions, 1 deletions
@@ -1023,10 +1023,12 @@ Perl_leave_scope(pTHX_ I32 base) PL_op = (OP*)SSPOPPTR; break; case SAVEt_HINTS: - if ((PL_hints & HINT_LOCALIZE_HH) && GvHV(PL_hintgv)) { + if ((PL_hints & HINT_LOCALIZE_HH)) { + while (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); |