summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mg.c13
-rw-r--r--sv.c26
2 files changed, 23 insertions, 16 deletions
diff --git a/mg.c b/mg.c
index 63de61249f..299d1bbb11 100644
--- a/mg.c
+++ b/mg.c
@@ -359,8 +359,17 @@ Perl_mg_free(pTHX_ SV *sv)
else if (mg->mg_len == HEf_SVKEY)
SvREFCNT_dec((SV*)mg->mg_ptr);
}
- if (mg->mg_flags & MGf_REFCOUNTED)
- SvREFCNT_dec(mg->mg_obj);
+ if (mg->mg_flags & MGf_REFCOUNTED) {
+ SV *obj = mg->mg_obj;
+ if (mg->mg_type == PERL_MAGIC_tiedscalar && SvROK(obj) &&
+ (SvRV(obj) == sv || GvIO(SvRV(obj)) == (IO *) sv)) {
+ /* We are already free'ing the self-tied thing
+ so SvREFCNT_dec must not.
+ */
+ SvROK_off(obj);
+ }
+ SvREFCNT_dec(obj);
+ }
Safefree(mg);
}
SvMAGIC(sv) = 0;
diff --git a/sv.c b/sv.c
index dd35da7c1f..7d51f322ba 100644
--- a/sv.c
+++ b/sv.c
@@ -4479,6 +4479,15 @@ Perl_sv_magicext(pTHX_ SV* sv, SV* obj, int how, MGVTBL *vtable,
else {
mg->mg_obj = SvREFCNT_inc(obj);
mg->mg_flags |= MGf_REFCOUNTED;
+
+ /* Break self-tie loops */
+ if (how == PERL_MAGIC_tiedscalar && SvROK(obj) &&
+ (SvRV(obj) == sv || GvIO(SvRV(obj)) == (IO *) sv)) {
+ /* We have to have a REFCNT to obj, so drop REFCNT
+ of what if references instead
+ */
+ SvREFCNT_dec(SvRV(obj));
+ }
}
mg->mg_type = how;
mg->mg_len = namlen;
@@ -5172,20 +5181,9 @@ Perl_sv_free(pTHX_ SV *sv)
}
ATOMIC_DEC_AND_TEST(refcount_is_zero, SvREFCNT(sv));
if (!refcount_is_zero) {
- if (SvREFCNT(sv) == 1) {
- /* Break self-tie loops */
- MAGIC *mg = 0;
- SV *obj;
- if (SvTYPE(sv) == SVt_PVGV)
- sv = (SV *)GvIO(sv);
- if (!sv || !SvMAGICAL(sv) || SvTYPE(sv) < SVt_PVMG)
- return;
- mg = SvTIED_mg(sv, PERL_MAGIC_tiedscalar);
- if (mg && (obj = mg->mg_obj) && SvROK(obj) &&
- (SvRV(obj) == sv || GvIO(SvRV(obj)) == (IO *) sv)) {
- sv_unmagic(sv, PERL_MAGIC_tiedscalar);
- }
- }
+ /* Do not be tempted to test SvMAGIC here till scope.c
+ stops sharing MAGIC * between SVs
+ */
return;
}
#ifdef DEBUGGING