https://github.com/python/cpython/commit/84e852736861a252affd15c479538c6f992111cc
commit: 84e852736861a252affd15c479538c6f992111cc
branch: 3.15
author: Miss Islington (bot) <[email protected]>
committer: eendebakpt <[email protected]>
date: 2026-11-03T11:27:15+01:00
summary:

[3.15] gh-158095: Fix reference cycles in re scanners (GH-158100) (#161246)

gh-158095: Fix reference cycles in re scanners (GH-158100)

* Fix reference cycles in re scanners

* 📜🤖 Added by blurb_it.

* gh-158095: Normalize NEWS line endings

* gh-158095: Clear input references in re scanners

* ci: rerun checks

Assisted-by: Codex:GPT-6

---------
(cherry picked from commit 8c3b566891c4bf8a071588e3377ba933850d9501)

Co-authored-by: sijun-yang <[email protected]>
Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>

files:
A Misc/NEWS.d/next/Library/2026-09-24-14-59-08.gh-issue-158095.lcKOT4.rst
M Lib/test/test_re.py
M Modules/_sre/sre.c

diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py
index 00a4f325bc322c7..1217653fe272c79 100644
--- a/Lib/test/test_re.py
+++ b/Lib/test/test_re.py
@@ -8,6 +8,7 @@
 import sys
 import unittest
 import warnings
+import weakref
 from re import Scanner
 from weakref import proxy
 
@@ -1735,6 +1736,27 @@ def test_finditer(self):
         self.assertEqual([item.group(0) for item in iter],
                          ["::", "::"])
 
+    def test_finditer_gc(self):
+        class Text(str):
+            pass
+
+        class Buffer(bytearray):
+            pass
+
+        text = Text('a')
+        text.iterator = re.finditer('a', text)
+        ref = weakref.ref(text)
+        del text
+        gc_collect()
+        self.assertIsNone(ref())
+
+        buffer = Buffer(b'a')
+        buffer.iterator = re.finditer(b'a', buffer)
+        ref = weakref.ref(buffer)
+        del buffer
+        gc_collect()
+        self.assertIsNone(ref())
+
     def test_bug_926075(self):
         self.assertIsNot(re.compile('bug_926075'),
                          re.compile(b'bug_926075'))
diff --git 
a/Misc/NEWS.d/next/Library/2026-09-24-14-59-08.gh-issue-158095.lcKOT4.rst 
b/Misc/NEWS.d/next/Library/2026-09-24-14-59-08.gh-issue-158095.lcKOT4.rst
new file mode 100644
index 000000000000000..4fe92b8c8097d85
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-09-24-14-59-08.gh-issue-158095.lcKOT4.rst
@@ -0,0 +1,2 @@
+Fix a memory leak in :func:`re.finditer` and regular expression scanners when
+their input participates in a reference cycle.
diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c
index 1eee31b3ee48235..90d66ee81e9a08b 100644
--- a/Modules/_sre/sre.c
+++ b/Modules/_sre/sre.c
@@ -2811,6 +2811,8 @@ scanner_traverse(PyObject *op, visitproc visit, void *arg)
     ScannerObject *self = _ScannerObject_CAST(op);
     Py_VISIT(Py_TYPE(self));
     Py_VISIT(self->pattern);
+    Py_VISIT(self->state.string);
+    Py_VISIT(self->state.buffer.obj);
     return 0;
 }
 
@@ -2818,7 +2820,10 @@ static int
 scanner_clear(PyObject *op)
 {
     ScannerObject *self = _ScannerObject_CAST(op);
+    self->state.start = NULL;
     Py_CLEAR(self->pattern);
+    Py_CLEAR(self->state.string);
+    PyBuffer_Release(&self->state.buffer);
     return 0;
 }
 
@@ -2828,8 +2833,8 @@ scanner_dealloc(PyObject *self)
     PyTypeObject *tp = Py_TYPE(self);
     PyObject_GC_UnTrack(self);
     ScannerObject *scanner = _ScannerObject_CAST(self);
-    state_fini(&scanner->state);
     (void)scanner_clear(self);
+    state_fini(&scanner->state);
     tp->tp_free(self);
     Py_DECREF(tp);
 }

_______________________________________________
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