CVE-2026-15534, upstream commit
54cf3d44cbbedd17d774e9a37921963e8fd5d0cb.

diff --git a/regexec.c b/regexec.c
index 29aa73c13cb9..66e0c0924059 100644
--- a/regexec.c
+++ b/regexec.c
@@ -9202,22 +9202,27 @@ NULL
                 if (!reginfo->poscache_maxiter) {
                     /* start the countdown: Postpone detection until we
                      * know the match is not *that* much linear. */
-                    reginfo->poscache_maxiter
-                        =    (reginfo->strend - reginfo->strbeg + 1)
-                           * (FLAGS(scan)>>4);
-                    /* possible overflow for long strings and many CURLYX's */
-                    if (reginfo->poscache_maxiter < 0)
-                        reginfo->poscache_maxiter = I32_MAX;
-                    reginfo->poscache_iter = reginfo->poscache_maxiter;
+                    STRLEN len = reginfo->strend - reginfo->strbeg;
+                    /* number of participating WHILEMs */
+                    U8 n = (FLAGS(scan)>>4);
+
+                    /* Only do the calculations and enable the cache if it
+                     * won't overflow. This test is equivalent to:
+                     *    ((len + 1) * n  + 7) <= max(STRLEN)
+                     */
+                    if (len < ((~(STRLEN)0) - 7)/n) {
+                        reginfo->poscache_maxiter = (len + 1) * n;
+                        reginfo->poscache_iter = reginfo->poscache_maxiter;
+                    }
                 }
 
                 if (reginfo->poscache_iter == 1) {
                     reginfo->poscache_iter--;
                     /* initialise cache */
-                    const SSize_t size = (reginfo->poscache_maxiter + 7)/8;
+                    const STRLEN size = (reginfo->poscache_maxiter + 7)/8;
                     regmatch_info_aux *const aux = reginfo->info_aux;
                     if (aux->poscache) {
-                        if ((SSize_t)reginfo->poscache_size < size) {
+                        if (reginfo->poscache_size < size) {
                             Renew(aux->poscache, size, char);
                             reginfo->poscache_size = size;
                         }
diff --git a/regexp.h b/regexp.h
index 057d9ac5011b..d5d40e0a5618 100644
--- a/regexp.h
+++ b/regexp.h
@@ -839,8 +839,8 @@ typedef struct {
     char *cutpoint;      /* (*COMMIT) position (if any) */
     regmatch_info_aux      *info_aux; /* extra fields that need cleanup */
     regmatch_info_aux_eval *info_aux_eval; /* extra saved state for (?{}) */
-    I32  poscache_maxiter; /* how many whilems todo before S-L cache kicks in */
-    I32  poscache_iter;    /* current countdown from _maxiter to zero */
+    STRLEN poscache_maxiter; /* how many whilems todo before S-L cache kicks in */
+    STRLEN poscache_iter;    /* current countdown from _maxiter to zero */
     STRLEN poscache_size;  /* size of regmatch_info_aux.poscache */
     bool intuit;    /* re_intuit_start() is the top-level caller */
     bool is_utf8_pat;    /* regex is utf8 */
