summaryrefslogtreecommitdiff
path: root/sv.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2011-04-13 14:35:09 +0100
committerDavid Mitchell <davem@iabyn.com>2011-04-13 14:49:09 +0100
commitda0c0b273c42c8a3f17664cdbe99318311f652af (patch)
tree40f4900feb7b7dbdccc797da339825eb9970aeae /sv.c
parent673d8593b7ef274dadbfff97fd641e3c563fc716 (diff)
downloadperl-da0c0b273c42c8a3f17664cdbe99318311f652af.tar.gz
handle freed backref array in global cleanup
[perl #88330] If a thinggy is heavily leaked, so that it takes multiple passes through Perl_sv_clean_all to get its refcount to zero, then if it has weak refs to it, its backref array may get freed before it. We already set the refcount of the array to 2 to preserve it across one pass of Perl_sv_clean_all, but I can't think of a way of protecting it more generally (short of using a private array structure rather than an AV). In the past, this caused a scary assertion failure. Now instead, just skip if we're in global cleanup and the array is freed. This isn't ideal, but its reasonably robust, as we don't reuse freed SVs once in global cleanup (so the freed AV hangs around to be identified as such).
Diffstat (limited to 'sv.c')
-rw-r--r--sv.c11
1 files changed, 11 insertions, 0 deletions
diff --git a/sv.c b/sv.c
index 447c2bc5ef..69cdfa9b55 100644
--- a/sv.c
+++ b/sv.c
@@ -5719,6 +5719,17 @@ Perl_sv_kill_backrefs(pTHX_ SV *const sv, AV *const av)
if (!av)
return;
+ /* after multiple passes through Perl_sv_clean_all() for a thinngy
+ * that has badly leaked, the backref array may have gotten freed,
+ * since we only protect it against 1 round of cleanup */
+ if (SvIS_FREED(av)) {
+ if (PL_in_clean_all) /* All is fair */
+ return;
+ Perl_croak(aTHX_
+ "panic: magic_killbackrefs (freed backref AV/SV)");
+ }
+
+
is_array = (SvTYPE(av) == SVt_PVAV);
if (is_array) {
assert(!SvIS_FREED(av));