summaryrefslogtreecommitdiff
path: root/regcomp.c
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2007-03-25 23:34:58 +0000
committerNicholas Clark <nick@ccl4.org>2007-03-25 23:34:58 +0000
commit32cd70f676ffca4ff7975bb5df57d2566f8443d3 (patch)
treece3426d00d2712406b8132843d48d2f57ce4bf5d /regcomp.c
parent6ab65676f4b64ac4ffc49ad69632426c17c23b72 (diff)
downloadperl-32cd70f676ffca4ff7975bb5df57d2566f8443d3.tar.gz
Looks like re_dup has been leaking references on 2 SVs for most regexps
since dot (only to be recovered for certain at thread exit). p4raw-id: //depot/perl@30755
Diffstat (limited to 'regcomp.c')
-rw-r--r--regcomp.c42
1 files changed, 27 insertions, 15 deletions
diff --git a/regcomp.c b/regcomp.c
index 4a019e1f28..0bead353b2 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -8882,12 +8882,11 @@ Perl_regfree_internal(pTHX_ struct regexp *r)
#define SAVEPVN(p,n) ((p) ? savepvn(p,n) : NULL)
/*
- regdupe - duplicate a regexp.
-
- This routine is called by sv.c's re_dup and is expected to clone a
- given regexp structure. It is a no-op when not under USE_ITHREADS.
- (Originally this *was* re_dup() for change history see sv.c)
+ re_dup - duplicate a regexp.
+ This routine is expected to clone a given regexp structure. It is not
+ compiler under USE_ITHREADS.
+
After all of the core data stored in struct regexp is duplicated
the regexp_engine.dupe method is used to copy any private data
stored in the *pprivate pointer. This allows extensions to handle
@@ -8926,20 +8925,33 @@ Perl_re_dup(pTHX_ const regexp *r, CLONE_PARAMS *param)
}
if (r->substrs) {
- struct reg_substr_datum *s;
- const struct reg_substr_datum *s_end;
-
+ /* Do it this way to avoid reading from *r after the StructCopy().
+ That way, if any of the sv_dup_inc()s dislodge *r from the L1
+ cache, it doesn't matter. */
+ const bool anchored = r->check_substr == r->anchored_substr;
Newx(ret->substrs, 1, struct reg_substr_data);
StructCopy(r->substrs, ret->substrs, struct reg_substr_data);
- s = ret->substrs->data;
- s_end
- = s + sizeof(ret->substrs->data) / sizeof(struct reg_substr_datum);
+ ret->anchored_substr = sv_dup_inc(ret->anchored_substr, param);
+ ret->anchored_utf8 = sv_dup_inc(ret->anchored_utf8, param);
+ ret->float_substr = sv_dup_inc(ret->float_substr, param);
+ ret->float_utf8 = sv_dup_inc(ret->float_utf8, param);
- do {
- s->substr = sv_dup_inc(s->substr, param);
- s->utf8_substr = sv_dup_inc(s->utf8_substr, param);
- } while (++s < s_end);
+ /* check_substr and check_utf8, if non-NULL, point to either their
+ anchored or float namesakes, and don't hold a second reference. */
+
+ if (ret->check_substr) {
+ if (anchored) {
+ assert(r->check_utf8 == r->anchored_utf8);
+ ret->check_substr = ret->anchored_substr;
+ ret->check_utf8 = ret->anchored_utf8;
+ } else {
+ assert(r->check_substr == r->float_substr);
+ assert(r->check_utf8 == r->float_utf8);
+ ret->check_substr = ret->float_substr;
+ ret->check_utf8 = ret->float_utf8;
+ }
+ }
} else
ret->substrs = NULL;