RT #118213: handle $r=qr/.../; /$r/p properly
authorDavid Mitchell <davem@iabyn.com>
Tue, 30 Jul 2013 15:16:35 +0000 (16:16 +0100)
committerDavid Mitchell <davem@iabyn.com>
Tue, 30 Jul 2013 18:23:37 +0000 (19:23 +0100)
commit5b0e71e9d506c1ab9c6f6799139a008b4f779835
treef6e43a576acbea957f9ef328fddc0fc25c6db56c
parent36b347b9c8caf3680cadf3c3cb98018a41a92507
RT #118213: handle $r=qr/.../; /$r/p properly

In the case where a qr// regex is directly used by PMOP (rather than being
interpolated with some other stuff and a new regex created, such as
/a$r/p), then the PMf_KEEPCOPY flag will be set on the PMOP, but the
corresponding RXf_PMf_KEEPCOPY flag *won't* be set on the regex.

Since most of the regex handling for copying the string and extracting out
${^PREMATCH} etc is done based on the RXf_PMf_KEEPCOPY flag in the regex,
this is a bit of a problem.

Prior to 5.18.0 this wasn't so noticeable, since various other bugs around
//p handling meant that ${$PREMATCH} etc often accidentally got set
anyway. 5.18.0 fixed these bugs, and so as a side-effect, exposed the
PMOP verses regex flag issue. In particular, this stopped working in
5.18.0:

    my $pat = qr/a/;
    'aaaa' =~ /$pat/gp or die;
    print "MATCH=[${^MATCH}]\n";

(prints 'a' in 5.16.0, undef in 5.18.0).
The presence /g caused the engine to copy the string anyway by luck.

We can't just set the RXf_PMf_KEEPCOPY flag on the regex if we see the
PMf_KEEPCOPY flag on the PMOP, otherwise stuff like this will be wrong:

    $r = qr/..../;
    /$r/p;  # set RXf_PMf_KEEPCOPY on $r
    /$r/; # does a /p match by mistake

Since for 5.19.x onwards COW is enabled by default (and cheap copies are
always made regardless of /p), then this fix is mainly for PERL_NO_COW
builds and for backporting to 5.18.x. (Although it still applies to
strings that can't be COWed for whatever reason).

Since we can't set a flag in the rx, we fix this by:

1) when calling the regex engine (which may attempt to copy part or all of
the capture string), make sure we pass REXEC_COPY_STR, but neither of
REXEC_COPY_SKIP_PRE, REXEC_COPY_SKIP_POST when we call regexec() from
pp_match or pp_subst when the corresponding PMOP has PMf_KEEPCOPY set.

2) in Perl_reg_numbered_buff_fetch() etc, check for PMf_KEEPCOPY in
PL_curpm as well as for RXf_PMf_KEEPCOPY in the current rx before deciding
whether to process ${^PREMATCH} etc.

As well as adding new tests to t/re/reg_pmod.t, I also changed the
string to be matched against from being '12...' to '012...', to ensure that
the lengths of ${^PREMATCH}, ${^MATCH}, ${^POSTMATCH} would all be
different.
pp_hot.c
regcomp.c
t/re/reg_pmod.t