mirror of
https://github.com/python/cpython.git
synced 2025-08-01 07:33:08 +00:00
[3.13] gh-67877: Fix memory leaks in terminated RE matching (GH-126840) (GH-126960)
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>
(cherry picked from commit 7538e7f569
)
This commit is contained in:
parent
2b2ad244c0
commit
885386b4a2
6 changed files with 248 additions and 14 deletions
|
@ -2664,6 +2664,47 @@ class ReTests(unittest.TestCase):
|
|||
def test_fail(self):
|
||||
self.assertEqual(re.search(r'12(?!)|3', '123')[0], '3')
|
||||
|
||||
def test_character_set_any(self):
|
||||
# The union of complementary character sets matches any character
|
||||
# and is equivalent to "(?s:.)".
|
||||
s = '1x\n'
|
||||
for p in r'[\s\S]', r'[\d\D]', r'[\w\W]', r'[\S\s]', r'\s|\S':
|
||||
with self.subTest(pattern=p):
|
||||
self.assertEqual(re.findall(p, s), list(s))
|
||||
self.assertEqual(re.fullmatch('(?:' + p + ')+', s).group(), s)
|
||||
|
||||
def test_character_set_none(self):
|
||||
# Negation of the union of complementary character sets does not match
|
||||
# any character.
|
||||
s = '1x\n'
|
||||
for p in r'[^\s\S]', r'[^\d\D]', r'[^\w\W]', r'[^\S\s]':
|
||||
with self.subTest(pattern=p):
|
||||
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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue