summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2012-01-12 23:07:20 +0100
committerNicholas Clark <nick@ccl4.org>2012-01-13 12:20:49 +0100
commit9e6704a9c88bca9a5eec456e14f7afa3a21f2181 (patch)
tree5a422b4915b5109172854b6416d119acd34e3433
parentc6c5075ef3e86920cd3c1ec231855d7ef40fecd1 (diff)
downloadperl-9e6704a9c88bca9a5eec456e14f7afa3a21f2181.tar.gz
In Perl_sv_del_backref(), don't panic if svp is NULL during global destruction.
It's possible that the referencing SV is being freed partway through the freeing of reference target. If this happens, the backreferences array of the target has already been freed, and so svp will be NULL. If this is the case, do nothing and return. Previously, this condition was not recognised and the code would panic.
-rw-r--r--sv.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/sv.c b/sv.c
index 8f623db95f..1f9f78774a 100644
--- a/sv.c
+++ b/sv.c
@@ -5564,9 +5564,18 @@ Perl_sv_del_backref(pTHX_ SV *const tsv, SV *const sv)
svp = mg ? &(mg->mg_obj) : NULL;
}
- if (!svp || !*svp)
- Perl_croak(aTHX_ "panic: del_backref, svp=%p, *svp=%p",
- svp, svp ? *svp : NULL);
+ if (!svp)
+ Perl_croak(aTHX_ "panic: del_backref, svp=0");
+ if (!*svp) {
+ /* It's possible that sv is being freed recursively part way through the
+ freeing of tsv. If this happens, the backreferences array of tsv has
+ already been freed, and so svp will be NULL. If this is the case,
+ we should not panic. Instead, nothing needs doing, so return. */
+ if (PL_phase == PERL_PHASE_DESTRUCT && SvREFCNT(tsv) == 0)
+ return;
+ Perl_croak(aTHX_ "panic: del_backref, *svp=%p phase=%s refcnt=%" UVuf,
+ *svp, PL_phase_names[PL_phase], SvREFCNT(tsv));
+ }
if (SvTYPE(*svp) == SVt_PVAV) {
#ifdef DEBUGGING