summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2024-11-18 09:53:45 (GMT)
committerGitHub <noreply@github.com>2024-11-18 09:53:45 (GMT)
commit7538e7f5696408fa0aa02fce8a413a7dfac76a04 (patch)
tree80987d19e109f6f6f544972cfdfd415b3248372b /Lib
parent3938fd60c0c88891b213097380aeea91a45bcd77 (diff)
downloadcpython-7538e7f5696408fa0aa02fce8a413a7dfac76a04.zip
cpython-7538e7f5696408fa0aa02fce8a413a7dfac76a04.tar.gz
cpython-7538e7f5696408fa0aa02fce8a413a7dfac76a04.tar.bz2
gh-67877: Fix memory leaks in terminated RE matching (GH-126840)
If SRE(match) function terminates abruptly, either because of a signal or because memory allocation fails, allocated SRE_REPEAT blocks might be never released. Co-authored-by: <wjssz@users.noreply.github.com>
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_re.py23
1 files changed, 23 insertions, 0 deletions
diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py
index 7bc702e..1612fc7 100644
--- a/Lib/test/test_re.py
+++ b/Lib/test/test_re.py
@@ -2681,6 +2681,29 @@ class ReTests(unittest.TestCase):
self.assertIsNone(re.search(p, s))
self.assertIsNone(re.search('(?s:.)' + p, s))
+ def check_interrupt(self, pattern, string, maxcount):
+ class Interrupt(Exception):
+ pass
+ p = re.compile(pattern)
+ for n in range(maxcount):
+ try:
+ p._fail_after(n, Interrupt)
+ p.match(string)
+ return n
+ except Interrupt:
+ pass
+ finally:
+ p._fail_after(-1, None)
+
+ @unittest.skipUnless(hasattr(re.Pattern, '_fail_after'), 'requires debug build')
+ def test_memory_leaks(self):
+ self.check_interrupt(r'(.)*:', 'abc:', 100)
+ self.check_interrupt(r'([^:])*?:', 'abc:', 100)
+ self.check_interrupt(r'([^:])*+:', 'abc:', 100)
+ self.check_interrupt(r'(.){2,4}:', 'abc:', 100)
+ self.check_interrupt(r'([^:]){2,4}?:', 'abc:', 100)
+ self.check_interrupt(r'([^:]){2,4}+:', 'abc:', 100)
+
def get_debug_out(pat):
with captured_stdout() as out: