summaryrefslogtreecommitdiff
path: root/regexec.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2013-07-20 16:16:10 +0100
committerDavid Mitchell <davem@iabyn.com>2013-07-28 10:33:40 +0100
commit5411a0e56ca69f51e1eeaf89ee0a73dcbcf05fb9 (patch)
tree2db7c978f7f6723602d17d520328a013a8e7de89 /regexec.c
parent63a3746a9fd4390177c052a5873163bc11fa8f69 (diff)
downloadperl-5411a0e56ca69f51e1eeaf89ee0a73dcbcf05fb9.tar.gz
fix COW match capture optimisation
When an SV matches, a new SV is created which is a COW copy of the original SV, and stored in prog->saved_copy, then prog->subbeg is set to point to the (shared) PVX buffer. Earlier in this branch I introduced an optimisation that skipped freeing the old saved_copy and creating a new COW SV each time, if the old saved_copy SV was already a shared copy of the SV being matched. So far so good, except that I implemented it wrongly: if non-COW matches (which malloc() subbeg) are interspersed with COW matches, then the subbeg of the COW and the malloced subbeg get mixed up and AddressSanitizer throws a wobbly. The fix is simple: in the optimised branch, we still need to free subbeg if RXp_MATCH_COPIED is true, then reassign it.
Diffstat (limited to 'regexec.c')
-rw-r--r--regexec.c28
1 files changed, 19 insertions, 9 deletions
diff --git a/regexec.c b/regexec.c
index 35851f66e6..9015f7d38a 100644
--- a/regexec.c
+++ b/regexec.c
@@ -2068,19 +2068,29 @@ S_reg_set_capture_string(pTHX_ REGEXP * const rx,
"Copy on write: regexp capture, type %d\n",
(int) SvTYPE(sv));
}
- /* skip creating new COW SV if a valid one already exists */
- if (! ( prog->saved_copy
- && SvIsCOW(sv)
- && SvPOKp(sv)
- && SvIsCOW(prog->saved_copy)
- && SvPOKp(prog->saved_copy)
- && SvPVX(sv) == SvPVX(prog->saved_copy)))
+ /* Create a new COW SV to share the match string and store
+ * in saved_copy, unless the current COW SV in saved_copy
+ * is valid and suitable for our purpose */
+ if (( prog->saved_copy
+ && SvIsCOW(prog->saved_copy)
+ && SvPOKp(prog->saved_copy)
+ && SvIsCOW(sv)
+ && SvPOKp(sv)
+ && SvPVX(sv) == SvPVX(prog->saved_copy)))
{
+ /* just reuse saved_copy SV */
+ if (RXp_MATCH_COPIED(prog)) {
+ Safefree(prog->subbeg);
+ RXp_MATCH_COPIED_off(prog);
+ }
+ }
+ else {
+ /* create new COW SV to share string */
RX_MATCH_COPY_FREE(rx);
prog->saved_copy = sv_setsv_cow(prog->saved_copy, sv);
- prog->subbeg = (char *)SvPVX_const(prog->saved_copy);
- assert (SvPOKp(prog->saved_copy));
}
+ prog->subbeg = (char *)SvPVX_const(prog->saved_copy);
+ assert (SvPOKp(prog->saved_copy));
prog->sublen = strend - strbeg;
prog->suboffset = 0;
prog->subcoffset = 0;