develooper Front page | perl.perl5.porters | Postings from November 2009

Re: [perl #69852] Regexp::DESTROY doesn't trigger with first class regexps

Thread Previous | Thread Next
From:
Nicholas Clark
Date:
November 30, 2009 12:17
Subject:
Re: [perl #69852] Regexp::DESTROY doesn't trigger with first class regexps
Message ID:
20091130201654.GB28490@plum.flirble.org
On Sun, Oct 18, 2009 at 02:32:51PM +0100, Nicholas Clark wrote:
> On Sun, Oct 18, 2009 at 03:22:21PM +0200, demerphq wrote:
> > 2009/10/17 Nicholas Clark <perlbug-followup@perl.org>:
> 
> > > I don't think that there's actually a ticket associated with the TODO tests in
> > > t/re/qr_gc.t
> > 
> > Why should it? Why are we persisting with the Regexp class at all?
> > Afaik it was never really useful.
> 
> It's not the class specifically. It's that the reference count on a regexp
> object (whatever its class) starts out as 2, not 1. Which seems wrong.

Whilst t/re/qr_gc.t notes that change 32751 first displayed the symptoms, this
is actually a bit of a red herring. Regexp::DESTROY isn't called, because that
change stopped (automatically) blessing (now first class) regexps into a class.

If you explicitly bless your regexp into 'Regexp', then Regexp::DESTROY is
called on it at the time you expect.

The real culprit is 288b8c02c5ee89a2978a1b9e56ed255c53beb793

    Make struct regexp the body of SVt_REGEXP SVs, REGEXPs become SVs,
    and regexp reference counting is via the regular SV reference counting.
    This was not as easy at it looks.
    
    p4raw-id: //depot/perl@32804


In particular, this part with the helpful comment:

diff --git a/pp_hot.c b/pp_hot.c
index e686b2a..9099c88 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -1194,11 +1194,21 @@ PP(pp_qr)
     REGEXP * rx = PM_GETRE(pm);
     SV * const pkg = CALLREG_PACKAGE(rx);
     SV * const rv = sv_newmortal();
-    SV * const sv = newSVrv(rv, pkg ? SvPV_nolen(pkg) : NULL);
+
+    SvUPGRADE(rv, SVt_IV);
+    /* This RV is about to own a reference to the regexp. (In addition to the
+       reference already owned by the PMOP.  */
+    ReREFCNT_inc(rx);
+    SvRV_set(rv, rx);
+    SvROK_on(rv);
+
+    if (pkg) {
+	HV* const stash = gv_stashpv(SvPV_nolen(pkg), GV_ADD);
+	(void)sv_bless(rv, stash);
+    }
+
     if (RX_EXTFLAGS(rx) & RXf_TAINTED)
         SvTAINTED_on(rv);
-    sv_upgrade(sv, SVt_REGEXP);
-    ((struct xregexp *)SvANY(sv))->xrx_regexp = ReREFCNT_inc(rx);
     XPUSHs(rv);
     RETURN;
 }


Before that change:

$ ./miniperl -le 'sub Foo::DESTROY {warn "DESTROY called"}; { my $a = bless qr//, "Foo"}; END {warn "END"}'
DESTROY called at -e line 1.
END at -e line 1.

After that change:

$ ./miniperl -le 'sub Foo::DESTROY {warn "DESTROY called"}; { my $a = bless qr//, "Foo"}; END {warn "END"}'
END at -e line 1.
DESTROY called at -e line 1.

There is no actual leak. Just a failure to stop existing until global
destruction.


This is actually a problem.

Before:

$ ./miniperl -le 'sub r{ qr//; } print ref r(); print ref r(); bless r(); print ref r()'
Regexp
Regexp
Regexp

After:

$ ./miniperl -le 'sub r{ qr//; } print ref r(); print ref r(); bless r(); print ref r()'
Regexp
Regexp
main

And with the addition of the ability to dereference and assign to regexps
(which at the time I wasn't sure about, but didn't comment on):

$ ./perl -le 'sub r {qr/Pie Good/}; $a = r(); print $a; ${r()} = "Whoops"; print r(); print $a'
(?-xism:Pie Good)
Whoops
Whoops


Yes. You can change the regexp that is somewhere else, because qr// doesn't
actually create you a new regexp, but instead simply returns you a reference
to the same (first class) object in the optree.

We're going to need to fix all of this.

Nicholas Clark

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About