Skip to content

Commit 23355e7

Browse files
committed
gh-160316: Make re.Pattern.match() return None when pos > endpos
Pattern.match(), prefixmatch(), fullmatch() and the scanner match() ran the engine with the start position past the end position, which could return an empty match or read past the end of the string.
1 parent 3b3c692 commit 23355e7

3 files changed

Lines changed: 28 additions & 0 deletions

File tree

‎Lib/test/test_re.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2427,6 +2427,25 @@ def test_keyword_parameters(self):
24272427
pat.scanner(string='abracadabra', pos=3, endpos=10).search().span(),
24282428
(7, 9))
24292429

2430+
def test_pos_greater_than_endpos(self):
2431+
# If endpos is less than pos, no match will be found.
2432+
for pattern in ['', r'$', r'^$', r'\b$', r'(?:x|$)']:
2433+
for string in ['abc\n', b'abc\n', bytearray(b'abc\n')]:
2434+
with self.subTest(pattern=pattern, string=string):
2435+
if isinstance(string, str):
2436+
p = re.compile(pattern, re.MULTILINE)
2437+
else:
2438+
p = re.compile(pattern.encode(), re.MULTILINE)
2439+
for pos, endpos in [(3, 0), (4, 0), (4, 3), (2, 1)]:
2440+
self.assertIsNone(p.match(string, pos, endpos))
2441+
self.assertIsNone(p.fullmatch(string, pos, endpos))
2442+
self.assertIsNone(p.search(string, pos, endpos))
2443+
self.assertIsNone(
2444+
p.scanner(string, pos, endpos).match())
2445+
self.assertIsNone(
2446+
p.scanner(string, pos, endpos).search())
2447+
self.assertEqual(p.findall(string, pos, endpos), [])
2448+
24302449
def test_bug_20998(self):
24312450
# Issue #20998: Fullmatch of repeated single character pattern
24322451
# with ignore case.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Fix :meth:`re.Pattern.match`, :meth:`re.Pattern.prefixmatch`,
2+
:meth:`re.Pattern.fullmatch` and the ``match()`` and ``prefixmatch()`` methods
3+
of scanner objects returning an empty match, or reading past the end of the
4+
string, when *pos* is greater than *endpos*. They now return ``None``, as
5+
documented.

‎Modules/_sre/sre.c‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,10 @@ pattern_dealloc(PyObject *self)
899899
LOCAL(Py_ssize_t)
900900
sre_match(SRE_STATE* state, SRE_CODE* pattern)
901901
{
902+
/* No match if pos > endpos. */
903+
if (state->ptr > state->end) {
904+
return 0;
905+
}
902906
if (state->charsize == 1)
903907
return sre_ucs1_match(state, pattern, 1);
904908
if (state->charsize == 2)

0 commit comments

Comments
 (0)