From 568e6fd238867bb9e99fa3f47cba3169009239e0 Mon Sep 17 00:00:00 2001 From: David Mitchell Date: Tue, 30 Jun 2026 11:19:45 +0100 Subject: [PATCH] regex super-linear cache: make countdown unsigned The super-linear cache is a block of flag bits malloc()ed during regex execution for patterns such as: ((aaa)+)+ which can go exponential in run time. The idea is that after the pattern has been executing for a while, the cache is malloced(), and subsequent failed iterations set a flag in the cache indicating a fail at this position, so that it can be failed quickly if a similar point is reached again after backtracking. The "executing for a while" bit is determined by setting a counter to a largish value, then counting down each time a WHILEM node is executed. When the count reaches zero, the cache is malloc()ed. When the count reaches -1, the cache becomes active, and no more decrements are done. This commit changes it so that the zero and -1 above become 1 and 0. This will allow the counter be made unsigned. This commit's only side effect is that the SLC will become active one iteration earlier than it did before. This isn't really an issue, as the current count start value is an extremely vague heuristic: the value used at the moment is (string length) x (the number of WHILEM nodes which can participate in the SLC). Actually changing the counter's type to unsigned will be done in the next commit. --- regexec.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/regexec.c b/regexec.c index 35a727459c4a..29aa73c13cb9 100644 --- a/regexec.c +++ b/regexec.c @@ -9211,7 +9211,8 @@ NULL reginfo->poscache_iter = reginfo->poscache_maxiter; } - if (reginfo->poscache_iter-- == 0) { + if (reginfo->poscache_iter == 1) { + reginfo->poscache_iter--; /* initialise cache */ const SSize_t size = (reginfo->poscache_maxiter + 7)/8; regmatch_info_aux *const aux = reginfo->info_aux; @@ -9232,11 +9233,10 @@ NULL ); } - if (reginfo->poscache_iter < 0) { + if (reginfo->poscache_iter == 0) { /* have we already failed at this position? */ SSize_t offset, mask; - reginfo->poscache_iter = -1; /* stop eventual underflow */ offset = (FLAGS(scan) & 0xf) - 1 + (locinput - reginfo->strbeg) * (FLAGS(scan)>>4); @@ -9252,6 +9252,8 @@ NULL ST.cache_offset = offset; ST.cache_mask = mask; } + else + reginfo->poscache_iter--; } /* Prefer B over A for minimal matching. */