]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-152026: Track mark-saving contexts with a counter (GH-153160)
authorSerhiy Storchaka <storchaka@gmail.com>
Mon, 6 Jul 2026 05:22:37 +0000 (08:22 +0300)
committerGitHub <noreply@github.com>
Mon, 6 Jul 2026 05:22:37 +0000 (05:22 +0000)
Replace the state->repeat checks that guard mark saving and restoring
with an explicit save_marks counter maintained where repeat and
possessive contexts are entered and left.  Each push is now paired
with a pop decided by the same condition.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Modules/_sre/sre.c
Modules/_sre/sre.h
Modules/_sre/sre_lib.h

index 7d03b909226f2444c501a3334d65bc00dd684797..e742a25e4891fcec05f5193896593768a6cbf688 100644 (file)
@@ -738,6 +738,7 @@ state_init(SRE_STATE* state, PatternObject* pattern, PyObject* string,
     state->charsize = charsize;
     state->match_all = 0;
     state->must_advance = 0;
+    state->save_marks = 0;
     state->debug = ((pattern->flags & SRE_FLAG_DEBUG) != 0);
 
     state->beginning = ptr;
index 42681c2addf3c2ccb3d4e290c7573acf8e9d1c19..bec4ae21d1e10f99f7b78a7b4fe1a3a28a114c17 100644 (file)
@@ -97,6 +97,10 @@ typedef struct {
     int lastmark;
     int lastindex;
     const void** mark;
+    int save_marks; /* if nonzero, save and restore mark values on
+                       backtracking instead of only rewinding the lastmark
+                       index; counts enclosing repeat contexts and
+                       possessive bodies */
     /* dynamically allocated stuff */
     char* data_stack;
     size_t data_stack_size;
index 6e6ae46f05a50f08397b35a75527b7b0db1aa9b7..444cd39d2fed2881deaed84b85ffa6887e05fb03 100644 (file)
@@ -863,7 +863,7 @@ dispatch:
             /* <BRANCH> <0=skip> code <JUMP> ... <NULL> */
             TRACE(("|%p|%p|BRANCH\n", pattern, ptr));
             LASTMARK_SAVE();
-            if (state->repeat)
+            if (state->save_marks)
                 MARK_PUSH(ctx->lastmark);
             for (; pattern[0]; pattern += pattern[0]) {
                 if (pattern[1] == SRE_OP_LITERAL &&
@@ -878,16 +878,16 @@ dispatch:
                 state->ptr = ptr;
                 DO_JUMP(JUMP_BRANCH, jump_branch, pattern+1);
                 if (ret) {
-                    if (state->repeat)
+                    if (state->save_marks)
                         MARK_POP_DISCARD(ctx->lastmark);
                     RETURN_ON_ERROR(ret);
                     RETURN_SUCCESS;
                 }
-                if (state->repeat)
+                if (state->save_marks)
                     MARK_POP_KEEP(ctx->lastmark);
                 LASTMARK_RESTORE();
             }
-            if (state->repeat)
+            if (state->save_marks)
                 MARK_POP_DISCARD(ctx->lastmark);
             RETURN_FAILURE;
 
@@ -933,7 +933,7 @@ dispatch:
             }
 
             LASTMARK_SAVE();
-            if (state->repeat)
+            if (state->save_marks)
                 MARK_PUSH(ctx->lastmark);
 
             if (pattern[pattern[0]] == SRE_OP_LITERAL) {
@@ -952,19 +952,19 @@ dispatch:
                     DO_JUMP(JUMP_REPEAT_ONE_1, jump_repeat_one_1,
                             pattern+pattern[0]);
                     if (ret) {
-                        if (state->repeat)
+                        if (state->save_marks)
                             MARK_POP_DISCARD(ctx->lastmark);
                         RETURN_ON_ERROR(ret);
                         RETURN_SUCCESS;
                     }
-                    if (state->repeat)
+                    if (state->save_marks)
                         MARK_POP_KEEP(ctx->lastmark);
                     LASTMARK_RESTORE();
 
                     ptr--;
                     ctx->count--;
                 }
-                if (state->repeat)
+                if (state->save_marks)
                     MARK_POP_DISCARD(ctx->lastmark);
             } else {
                 /* general case */
@@ -973,19 +973,19 @@ dispatch:
                     DO_JUMP(JUMP_REPEAT_ONE_2, jump_repeat_one_2,
                             pattern+pattern[0]);
                     if (ret) {
-                        if (state->repeat)
+                        if (state->save_marks)
                             MARK_POP_DISCARD(ctx->lastmark);
                         RETURN_ON_ERROR(ret);
                         RETURN_SUCCESS;
                     }
-                    if (state->repeat)
+                    if (state->save_marks)
                         MARK_POP_KEEP(ctx->lastmark);
                     LASTMARK_RESTORE();
 
                     ptr--;
                     ctx->count--;
                 }
-                if (state->repeat)
+                if (state->save_marks)
                     MARK_POP_DISCARD(ctx->lastmark);
             }
             RETURN_FAILURE;
@@ -1035,7 +1035,7 @@ dispatch:
             } else {
                 /* general case */
                 LASTMARK_SAVE();
-                if (state->repeat)
+                if (state->save_marks)
                     MARK_PUSH(ctx->lastmark);
 
                 while ((Py_ssize_t)pattern[2] == SRE_MAXREPEAT
@@ -1044,12 +1044,12 @@ dispatch:
                     DO_JUMP(JUMP_MIN_REPEAT_ONE,jump_min_repeat_one,
                             pattern+pattern[0]);
                     if (ret) {
-                        if (state->repeat)
+                        if (state->save_marks)
                             MARK_POP_DISCARD(ctx->lastmark);
                         RETURN_ON_ERROR(ret);
                         RETURN_SUCCESS;
                     }
-                    if (state->repeat)
+                    if (state->save_marks)
                         MARK_POP_KEEP(ctx->lastmark);
                     LASTMARK_RESTORE();
 
@@ -1063,7 +1063,7 @@ dispatch:
                     ptr++;
                     ctx->count++;
                 }
-                if (state->repeat)
+                if (state->save_marks)
                     MARK_POP_DISCARD(ctx->lastmark);
             }
             RETURN_FAILURE;
@@ -1140,10 +1140,12 @@ dispatch:
             ctx->u.rep->prev = state->repeat;
             ctx->u.rep->last_ptr = NULL;
             state->repeat = ctx->u.rep;
+            state->save_marks++;
 
             state->ptr = ptr;
             DO_JUMP(JUMP_REPEAT, jump_repeat, pattern+pattern[0]);
             state->repeat = ctx->u.rep->prev;
+            state->save_marks--;
             repeat_pool_free(state, ctx->u.rep);
 
             if (ret) {
@@ -1212,8 +1214,10 @@ dispatch:
             /* cannot match more repeated items here.  make sure the
                tail matches */
             state->repeat = ctx->u.rep->prev;
+            state->save_marks--;
             DO_JUMP(JUMP_MAX_UNTIL_3, jump_max_until_3, pattern);
             state->repeat = ctx->u.rep; // restore repeat before return
+            state->save_marks++;
 
             RETURN_ON_SUCCESS(ret);
             state->ptr = ptr;
@@ -1250,22 +1254,26 @@ dispatch:
 
             /* see if the tail matches */
             state->repeat = ctx->u.rep->prev;
+            state->save_marks--;
 
             LASTMARK_SAVE();
-            if (state->repeat)
+            if (state->save_marks)
                 MARK_PUSH(ctx->lastmark);
 
             DO_JUMP(JUMP_MIN_UNTIL_2, jump_min_until_2, pattern);
-            SRE_REPEAT *repeat_of_tail = state->repeat;
+            /* save_marks is balanced across the jump, so this equals the
+               value tested for MARK_PUSH above */
+            int pushed = state->save_marks != 0;
             state->repeat = ctx->u.rep; // restore repeat before return
+            state->save_marks++;
 
             if (ret) {
-                if (repeat_of_tail)
+                if (pushed)
                     MARK_POP_DISCARD(ctx->lastmark);
                 RETURN_ON_ERROR(ret);
                 RETURN_SUCCESS;
             }
-            if (repeat_of_tail)
+            if (pushed)
                 MARK_POP(ctx->lastmark);
             LASTMARK_RESTORE();
 
@@ -1302,16 +1310,10 @@ dispatch:
                pointer */
             state->ptr = ptr;
 
-            /* Set state->repeat to non-NULL */
-            ctx->u.rep = repeat_pool_malloc(state);
-            if (!ctx->u.rep) {
-                RETURN_ERROR(SRE_ERROR_MEMORY);
-            }
-            ctx->u.rep->count = -1;
-            ctx->u.rep->pattern = NULL;
-            ctx->u.rep->prev = state->repeat;
-            ctx->u.rep->last_ptr = NULL;
-            state->repeat = ctx->u.rep;
+            /* Capture groups in the body can be revisited on backtracking
+               between iterations, so their marks must be saved and restored,
+               as is done inside a repeat. */
+            state->save_marks++;
 
             /* Initialize Count to 0 */
             ctx->count = 0;
@@ -1327,9 +1329,7 @@ dispatch:
                 }
                 else {
                     state->ptr = ptr;
-                    /* Restore state->repeat */
-                    state->repeat = ctx->u.rep->prev;
-                    repeat_pool_free(state, ctx->u.rep);
+                    state->save_marks--;
                     RETURN_FAILURE;
                 }
             }
@@ -1402,9 +1402,7 @@ dispatch:
                 }
             }
 
-            /* Restore state->repeat */
-            state->repeat = ctx->u.rep->prev;
-            repeat_pool_free(state, ctx->u.rep);
+            state->save_marks--;
 
             /* Evaluate Tail */
             /* Jump to end of pattern indicated by skip, and then skip
@@ -1586,17 +1584,17 @@ dispatch:
             if ((uintptr_t)(ptr - (SRE_CHAR *)state->beginning) >= pattern[1]) {
                 state->ptr = ptr - pattern[1];
                 LASTMARK_SAVE();
-                if (state->repeat)
+                if (state->save_marks)
                     MARK_PUSH(ctx->lastmark);
 
                 DO_JUMP0(JUMP_ASSERT_NOT, jump_assert_not, pattern+2);
                 if (ret) {
-                    if (state->repeat)
+                    if (state->save_marks)
                         MARK_POP_DISCARD(ctx->lastmark);
                     RETURN_ON_ERROR(ret);
                     RETURN_FAILURE;
                 }
-                if (state->repeat)
+                if (state->save_marks)
                     MARK_POP(ctx->lastmark);
                 LASTMARK_RESTORE();
             }