Fix double free with stashes blessed into each other
authorFather Chrysostomos <sprout@cpan.org>
Wed, 21 Nov 2012 16:48:41 +0000 (08:48 -0800)
committerFather Chrysostomos <sprout@cpan.org>
Wed, 21 Nov 2012 16:48:41 +0000 (08:48 -0800)
commitf6f93f805953c20dfcbe8940e84850dfe58ce0ef
tree520dc5c981992931c90d9f5bfa66d578536f81cb
parent4cc783efe0ed9495ebcbefd8494083a4b6160e6f
Fix double free with stashes blessed into each other

When I added that extra pass in 5.16 that curses any remaining blessed
objects during global destruction, I caused this bug:

$ ./miniperl -e 'warn bless \%foo::, bar::; warn bless \%bar::, foo::'
bar=HASH(0x827260) at -e line 1.
foo=HASH(0x8272b0) at -e line 1.
Attempt to free unreferenced scalar: SV 0x8272b0, Perl interpreter: 0x800000 during global destruction.

By creating a circularity between stashes, with no RVs remaining, we
cause one of the two stashes, say foo, to be cursed during global
destruction.  That causes it to lower the remaining reference count
on bar, which, when freed, lowers its reference count on foo, which
then tries to lower its reference count on bar, which has already
been freed.

The solution here is to turn off the object flag before decrementing
the stash’s reference count.  So a recursive call won’t try to curse
the already accursed object.

Turning off the flag makes SvSTASH into a DESTROY cache.  That won’t
work if the SvREFCNT_dec call tries to access that cache.  So we have
to null the field before calling SvREFCNT_dec (which we should be
doing anyway).
sv.c
t/op/ref.t