From 42e9b60980bb8e29e76629e14c6aa945194c0647 Mon Sep 17 00:00:00 2001 From: Hugo van der Sanden Date: Wed, 5 Oct 2016 02:20:26 +0100 Subject: [PATCH] [perl #129061] CURLYX nodes can be studied more than once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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]. Signed-off-by: Petr Písař --- regcomp.c | 12 +++++++++--- t/re/pat.t | 1 - 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/regcomp.c b/regcomp.c index 850a6c1..48c8d8d 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++; diff --git a/t/re/pat.t b/t/re/pat.t index ecd3af1..16bfc8e 100644 --- a/t/re/pat.t +++ b/t/re/pat.t @@ -1909,7 +1909,6 @@ EOP } { # [perl #129281] buffer write overflow, detected by ASAN, valgrind - local $::TODO = "whilem_c bumped too much"; fresh_perl_is('/0(?0)|^*0(?0)|^*(^*())0|/', '', {}, "don't bump whilem_c too much"); } } # End of sub run_tests -- 2.7.4