Skip to content

Commit 84e8527

Browse files
miss-islingtonYangSiJun528blurb-it[bot]
authored
[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 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 98655da commit 84e8527

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

@@ -1735,6 +1736,27 @@ def test_finditer(self):
17351736
self.assertEqual([item.group(0) for item in iter],
17361737
["::", "::"])
17371738

1739+
def test_finditer_gc(self):
1740+
class Text(str):
1741+
pass
1742+
1743+
class Buffer(bytearray):
1744+
pass
1745+
1746+
text = Text('a')
1747+
text.iterator = re.finditer('a', text)
1748+
ref = weakref.ref(text)
1749+
del text
1750+
gc_collect()
1751+
self.assertIsNone(ref())
1752+
1753+
buffer = Buffer(b'a')
1754+
buffer.iterator = re.finditer(b'a', buffer)
1755+
ref = weakref.ref(buffer)
1756+
del buffer
1757+
gc_collect()
1758+
self.assertIsNone(ref())
1759+
17381760
def test_bug_926075(self):
17391761
self.assertIsNot(re.compile('bug_926075'),
17401762
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
@@ -2811,14 +2811,19 @@ scanner_traverse(PyObject *op, visitproc visit, void *arg)
28112811
ScannerObject *self = _ScannerObject_CAST(op);
28122812
Py_VISIT(Py_TYPE(self));
28132813
Py_VISIT(self->pattern);
2814+
Py_VISIT(self->state.string);
2815+
Py_VISIT(self->state.buffer.obj);
28142816
return 0;
28152817
}
28162818

28172819
static int
28182820
scanner_clear(PyObject *op)
28192821
{
28202822
ScannerObject *self = _ScannerObject_CAST(op);
2823+
self->state.start = NULL;
28212824
Py_CLEAR(self->pattern);
2825+
Py_CLEAR(self->state.string);
2826+
PyBuffer_Release(&self->state.buffer);
28222827
return 0;
28232828
}
28242829

@@ -2828,8 +2833,8 @@ scanner_dealloc(PyObject *self)
28282833
PyTypeObject *tp = Py_TYPE(self);
28292834
PyObject_GC_UnTrack(self);
28302835
ScannerObject *scanner = _ScannerObject_CAST(self);
2831-
state_fini(&scanner->state);
28322836
(void)scanner_clear(self);
2837+
state_fini(&scanner->state);
28332838
tp->tp_free(self);
28342839
Py_DECREF(tp);
28352840
}

0 commit comments

Comments
 (0)