https://github.com/python/cpython/commit/b1756212f2bcbbf24089fe52a9dcfe8c49e9d724
commit: b1756212f2bcbbf24089fe52a9dcfe8c49e9d724
branch: main
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-07-06T05:22:37Z
summary:

gh-152026: Track mark-saving contexts with a counter (GH-153160)

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 <[email protected]>

files:
M Modules/_sre/sre.c
M Modules/_sre/sre.h
M Modules/_sre/sre_lib.h

diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c
index 7d03b909226f244..e742a25e4891fce 100644
--- a/Modules/_sre/sre.c
+++ b/Modules/_sre/sre.c
@@ -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;
diff --git a/Modules/_sre/sre.h b/Modules/_sre/sre.h
index 42681c2addf3c2c..bec4ae21d1e10f9 100644
--- a/Modules/_sre/sre.h
+++ b/Modules/_sre/sre.h
@@ -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;
diff --git a/Modules/_sre/sre_lib.h b/Modules/_sre/sre_lib.h
index 6e6ae46f05a50f0..444cd39d2fed288 100644
--- a/Modules/_sre/sre_lib.h
+++ b/Modules/_sre/sre_lib.h
@@ -863,7 +863,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int 
toplevel)
             /* <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 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int 
toplevel)
                 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 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int 
toplevel)
             }
 
             LASTMARK_SAVE();
-            if (state->repeat)
+            if (state->save_marks)
                 MARK_PUSH(ctx->lastmark);
 
             if (pattern[pattern[0]] == SRE_OP_LITERAL) {
@@ -952,19 +952,19 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int 
toplevel)
                     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 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int 
toplevel)
                     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 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int 
toplevel)
             } 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 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, 
int toplevel)
                     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 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int 
toplevel)
                     ptr++;
                     ctx->count++;
                 }
-                if (state->repeat)
+                if (state->save_marks)
                     MARK_POP_DISCARD(ctx->lastmark);
             }
             RETURN_FAILURE;
@@ -1140,10 +1140,12 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, 
int toplevel)
             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 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, 
int toplevel)
             /* 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 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, 
int toplevel)
 
             /* 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 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, 
int toplevel)
                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 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int 
toplevel)
                 }
                 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 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int 
toplevel)
                 }
             }
 
-            /* 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 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, 
int toplevel)
             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();
             }

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to