diff options
author | David Mitchell <davem@iabyn.com> | 2013-07-20 16:16:10 +0100 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2013-07-28 10:33:40 +0100 |
commit | 5411a0e56ca69f51e1eeaf89ee0a73dcbcf05fb9 (patch) | |
tree | 2db7c978f7f6723602d17d520328a013a8e7de89 /regexec.c | |
parent | 63a3746a9fd4390177c052a5873163bc11fa8f69 (diff) | |
download | perl-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.c | 28 |
1 files changed, 19 insertions, 9 deletions
@@ -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; |