Don’t double-free hint hash if copying dies
authorFather Chrysostomos <sprout@cpan.org>
Fri, 23 Dec 2011 17:40:52 +0000 (09:40 -0800)
committerFather Chrysostomos <sprout@cpan.org>
Fri, 23 Dec 2011 20:58:22 +0000 (12:58 -0800)
commit52c7aca67283e2d012cedda5e24ec7effb0dd0aa
tree4ccee90f64fe6b7b8223367e08237269384901bd
parent74cd21baf7fc29801914a3767824113a904fad8f
Don’t double-free hint hash if copying dies

In this horrendous piece of code, the attempt to clone GvHV(PL_hintgv)
in save_hints dies because the NEXTKEY method cannot be found.  But
that happens while GvHV(PL_hintgv) still points to the old value.  So
the old hash gets freed in the new scope (when it unwinds due to the
error in trying to find NEXTKEY) and then gets freed in the outer
scope, too, resulting in the dreaded ‘Attempt to free unrefer-
enced scalar’.

    package namespace::clean::_TieHintHash;

    sub TIEHASH  { bless[] }
    sub STORE    { $_[0][0]{$_[1]} = $_[2] }
    sub FETCH    { $_[0][0]{$_[1]} }
    sub FIRSTKEY { my $a = scalar keys %{$_[0][0]}; each %{$_[0][0]} }
  # Intentionally commented out:
  #  sub NEXTKEY  { each %{$_[0][0]} }

    package main;

    BEGIN {
$^H{foo} = "bar"; # activate localisation magic
tie( %^H, 'namespace::clean::_TieHintHash' ); # sabotage %^H
$^H{foo} = "bar"; # create an element in the tied hash
    }
    { ; } # clone the tied hint hash

The solution is to set GvHV(PL_hintgv) to NULL when copying it.
scope.c
t/comp/hints.t