Skip to content

Commit 8c3b566

Browse files
gh-158095: Fix reference cycles in re scanners (#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 --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
1 parent e9c9a33 commit 8c3b566

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
@@ -9,6 +9,7 @@
99
import sys
1010
import unittest
1111
import warnings
12+
import weakref
1213
from re import Scanner
1314
from weakref import proxy
1415

@@ -1940,6 +1941,27 @@ def test_finditer(self):
19401941
self.assertEqual([item.group(0) for item in iter],
19411942
["::", "::"])
19421943

1944+
def test_finditer_gc(self):
1945+
class Text(str):
1946+
pass
1947+
1948+
class Buffer(bytearray):
1949+
pass
1950+
1951+
text = Text('a')
1952+
text.iterator = re.finditer('a', text)
1953+
ref = weakref.ref(text)
1954+
del text
1955+
gc_collect()
1956+
self.assertIsNone(ref())
1957+
1958+
buffer = Buffer(b'a')
1959+
buffer.iterator = re.finditer(b'a', buffer)
1960+
ref = weakref.ref(buffer)
1961+
del buffer
1962+
gc_collect()
1963+
self.assertIsNone(ref())
1964+
19431965
def test_bug_926075(self):
19441966
self.assertIsNot(re.compile('bug_926075'),
19451967
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
@@ -3023,14 +3023,19 @@ scanner_traverse(PyObject *op, visitproc visit, void *arg)
30233023
ScannerObject *self = _ScannerObject_CAST(op);
30243024
Py_VISIT(Py_TYPE(self));
30253025
Py_VISIT(self->pattern);
3026+
Py_VISIT(self->state.string);
3027+
Py_VISIT(self->state.buffer.obj);
30263028
return 0;
30273029
}
30283030

30293031
static int
30303032
scanner_clear(PyObject *op)
30313033
{
30323034
ScannerObject *self = _ScannerObject_CAST(op);
3035+
self->state.start = NULL;
30333036
Py_CLEAR(self->pattern);
3037+
Py_CLEAR(self->state.string);
3038+
PyBuffer_Release(&self->state.buffer);
30343039
return 0;
30353040
}
30363041

@@ -3040,8 +3045,8 @@ scanner_dealloc(PyObject *self)
30403045
PyTypeObject *tp = Py_TYPE(self);
30413046
PyObject_GC_UnTrack(self);
30423047
ScannerObject *scanner = _ScannerObject_CAST(self);
3043-
state_fini(&scanner->state);
30443048
(void)scanner_clear(self);
3049+
state_fini(&scanner->state);
30453050
tp->tp_free(self);
30463051
Py_DECREF(tp);
30473052
}

0 commit comments

Comments
Β (0)