Skip to content

Commit d70b579

Browse files
miss-islingtonYangSiJun528blurb-it[bot]
authored
[3.14] gh-158095: Fix reference cycles in re scanners (GH-158100) (#161245)
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 8c3b566) Co-authored-by: sijun-yang <yangsijun5528@gmail.com> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
1 parent e875c0a commit d70b579

3 files changed

Lines changed: 30 additions & 1 deletion

File tree

‎Lib/test/test_re.py‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import sys
99
import unittest
1010
import warnings
11+
import weakref
1112
from re import Scanner
1213
from weakref import proxy
1314

@@ -1705,6 +1706,27 @@ def test_finditer(self):
17051706
self.assertEqual([item.group(0) for item in iter],
17061707
["::", "::"])
17071708

1709+
def test_finditer_gc(self):
1710+
class Text(str):
1711+
pass
1712+
1713+
class Buffer(bytearray):
1714+
pass
1715+
1716+
text = Text('a')
1717+
text.iterator = re.finditer('a', text)
1718+
ref = weakref.ref(text)
1719+
del text
1720+
gc_collect()
1721+
self.assertIsNone(ref())
1722+
1723+
buffer = Buffer(b'a')
1724+
buffer.iterator = re.finditer(b'a', buffer)
1725+
ref = weakref.ref(buffer)
1726+
del buffer
1727+
gc_collect()
1728+
self.assertIsNone(ref())
1729+
17081730
def test_bug_926075(self):
17091731
self.assertIsNot(re.compile('bug_926075'),
17101732
re.compile(b'bug_926075'))
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix a memory leak in :func:`re.finditer` and regular expression scanners when
2+
their input participates in a reference cycle.

‎Modules/_sre/sre.c‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2813,14 +2813,19 @@ scanner_traverse(PyObject *op, visitproc visit, void *arg)
28132813
ScannerObject *self = _ScannerObject_CAST(op);
28142814
Py_VISIT(Py_TYPE(self));
28152815
Py_VISIT(self->pattern);
2816+
Py_VISIT(self->state.string);
2817+
Py_VISIT(self->state.buffer.obj);
28162818
return 0;
28172819
}
28182820

28192821
static int
28202822
scanner_clear(PyObject *op)
28212823
{
28222824
ScannerObject *self = _ScannerObject_CAST(op);
2825+
self->state.start = NULL;
28232826
Py_CLEAR(self->pattern);
2827+
Py_CLEAR(self->state.string);
2828+
PyBuffer_Release(&self->state.buffer);
28242829
return 0;
28252830
}
28262831

@@ -2830,8 +2835,8 @@ scanner_dealloc(PyObject *self)
28302835
PyTypeObject *tp = Py_TYPE(self);
28312836
PyObject_GC_UnTrack(self);
28322837
ScannerObject *scanner = _ScannerObject_CAST(self);
2833-
state_fini(&scanner->state);
28342838
(void)scanner_clear(self);
2839+
state_fini(&scanner->state);
28352840
tp->tp_free(self);
28362841
Py_DECREF(tp);
28372842
}

0 commit comments

Comments
 (0)