summaryrefslogtreecommitdiff
path: root/regcomp.c
diff options
context:
space:
mode:
authorHugo van der Sanden <hv@crypt.org>2016-10-05 02:20:26 +0100
committerHugo van der Sanden <hv@crypt.org>2017-02-06 15:15:31 +0000
commit42e9b60980bb8e29e76629e14c6aa945194c0647 (patch)
treecfb768f339b21150739e7140f7080d05ee124e3e /regcomp.c
parentd2ba660af00f1bf2e7012741615eff7c19f29707 (diff)
downloadperl-42e9b60980bb8e29e76629e14c6aa945194c0647.tar.gz
[perl #129061] CURLYX nodes can be studied more than once
study_chunk() for CURLYX is used to set flags on the linked WHILEM node to say it is the whilem_c'th of whilem_seen. However it assumes each CURLYX can be studied only once, which is not the case - there are various cases such as GOSUB which call study_chunk() recursively on already-visited parts of the program. Storing the wrong index can cause the super-linear cache handling in regmatch() to read/write the byte after the end of poscache. Also reported in [perl #129281].
Diffstat (limited to 'regcomp.c')
-rw-r--r--regcomp.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/regcomp.c b/regcomp.c
index 850a6c1544..48c8d8da04 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -5218,15 +5218,21 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
However, this time it's not a subexpression
we care about, but the expression itself. */
&& (maxcount == REG_INFTY)
- && data && ++data->whilem_c < 16) {
+ && data) {
/* This stays as CURLYX, we can put the count/of pair. */
/* Find WHILEM (as in regexec.c) */
regnode *nxt = oscan + NEXT_OFF(oscan);
if (OP(PREVOPER(nxt)) == NOTHING) /* LONGJMP */
nxt += ARG(nxt);
- PREVOPER(nxt)->flags = (U8)(data->whilem_c
- | (RExC_whilem_seen << 4)); /* On WHILEM */
+ nxt = PREVOPER(nxt);
+ if (nxt->flags & 0xf) {
+ /* we've already set whilem count on this node */
+ } else if (++data->whilem_c < 16) {
+ assert(data->whilem_c <= RExC_whilem_seen);
+ nxt->flags = (U8)(data->whilem_c
+ | (RExC_whilem_seen << 4)); /* On WHILEM */
+ }
}
if (data && fl & (SF_HAS_PAR|SF_IN_PAR))
pars++;