summaryrefslogtreecommitdiff
path: root/sv.c
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 /sv.c
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.
Diffstat (limited to 'sv.c')
-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