mirror of https://github.com/python/cpython
gh-91616: re module, fix .fullmatch() mismatch when using Atomic Grouping or Possessive Quantifiers (GH-91681)
These jumps should use DO_JUMP0() instead of DO_JUMP(): - JUMP_POSS_REPEAT_1 - JUMP_POSS_REPEAT_2 - JUMP_ATOMIC_GROUP
This commit is contained in:
parent
061a8bf77c
commit
e4e8895ae3
|
@ -1388,6 +1388,7 @@ class _BasePathTest(object):
|
|||
# | |-- dirD
|
||||
# | | `-- fileD
|
||||
# | `-- fileC
|
||||
# | `-- novel.txt
|
||||
# |-- dirE # No permissions
|
||||
# |-- fileA
|
||||
# |-- linkA -> fileA
|
||||
|
@ -1412,6 +1413,8 @@ class _BasePathTest(object):
|
|||
f.write(b"this is file B\n")
|
||||
with open(join('dirC', 'fileC'), 'wb') as f:
|
||||
f.write(b"this is file C\n")
|
||||
with open(join('dirC', 'novel.txt'), 'wb') as f:
|
||||
f.write(b"this is a novel\n")
|
||||
with open(join('dirC', 'dirD', 'fileD'), 'wb') as f:
|
||||
f.write(b"this is file D\n")
|
||||
os.chmod(join('dirE'), 0)
|
||||
|
@ -1679,6 +1682,9 @@ class _BasePathTest(object):
|
|||
p = P(BASE, "dirC")
|
||||
_check(p.rglob("file*"), ["dirC/fileC", "dirC/dirD/fileD"])
|
||||
_check(p.rglob("*/*"), ["dirC/dirD/fileD"])
|
||||
# gh-91616, a re module regression
|
||||
_check(p.rglob("*.txt"), ["dirC/novel.txt"])
|
||||
_check(p.rglob("*.*"), ["dirC/novel.txt"])
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
def test_rglob_symlink_loop(self):
|
||||
|
@ -1689,7 +1695,8 @@ class _BasePathTest(object):
|
|||
expect = {'brokenLink',
|
||||
'dirA', 'dirA/linkC',
|
||||
'dirB', 'dirB/fileB', 'dirB/linkD',
|
||||
'dirC', 'dirC/dirD', 'dirC/dirD/fileD', 'dirC/fileC',
|
||||
'dirC', 'dirC/dirD', 'dirC/dirD/fileD',
|
||||
'dirC/fileC', 'dirC/novel.txt',
|
||||
'dirE',
|
||||
'fileA',
|
||||
'linkA',
|
||||
|
|
|
@ -2242,6 +2242,10 @@ class ReTests(unittest.TestCase):
|
|||
self.assertIsNone(re.fullmatch(r'a*+', 'ab'))
|
||||
self.assertIsNone(re.fullmatch(r'a?+', 'ab'))
|
||||
self.assertIsNone(re.fullmatch(r'a{1,3}+', 'ab'))
|
||||
self.assertTrue(re.fullmatch(r'a++b', 'ab'))
|
||||
self.assertTrue(re.fullmatch(r'a*+b', 'ab'))
|
||||
self.assertTrue(re.fullmatch(r'a?+b', 'ab'))
|
||||
self.assertTrue(re.fullmatch(r'a{1,3}+b', 'ab'))
|
||||
|
||||
self.assertTrue(re.fullmatch(r'(?:ab)++', 'ab'))
|
||||
self.assertTrue(re.fullmatch(r'(?:ab)*+', 'ab'))
|
||||
|
@ -2251,6 +2255,10 @@ class ReTests(unittest.TestCase):
|
|||
self.assertIsNone(re.fullmatch(r'(?:ab)*+', 'abc'))
|
||||
self.assertIsNone(re.fullmatch(r'(?:ab)?+', 'abc'))
|
||||
self.assertIsNone(re.fullmatch(r'(?:ab){1,3}+', 'abc'))
|
||||
self.assertTrue(re.fullmatch(r'(?:ab)++c', 'abc'))
|
||||
self.assertTrue(re.fullmatch(r'(?:ab)*+c', 'abc'))
|
||||
self.assertTrue(re.fullmatch(r'(?:ab)?+c', 'abc'))
|
||||
self.assertTrue(re.fullmatch(r'(?:ab){1,3}+c', 'abc'))
|
||||
|
||||
def test_findall_possessive_quantifiers(self):
|
||||
self.assertEqual(re.findall(r'a++', 'aab'), ['aa'])
|
||||
|
@ -2286,6 +2294,10 @@ class ReTests(unittest.TestCase):
|
|||
self.assertIsNone(re.fullmatch(r'(?>a*)', 'ab'))
|
||||
self.assertIsNone(re.fullmatch(r'(?>a?)', 'ab'))
|
||||
self.assertIsNone(re.fullmatch(r'(?>a{1,3})', 'ab'))
|
||||
self.assertTrue(re.fullmatch(r'(?>a+)b', 'ab'))
|
||||
self.assertTrue(re.fullmatch(r'(?>a*)b', 'ab'))
|
||||
self.assertTrue(re.fullmatch(r'(?>a?)b', 'ab'))
|
||||
self.assertTrue(re.fullmatch(r'(?>a{1,3})b', 'ab'))
|
||||
|
||||
self.assertTrue(re.fullmatch(r'(?>(?:ab)+)', 'ab'))
|
||||
self.assertTrue(re.fullmatch(r'(?>(?:ab)*)', 'ab'))
|
||||
|
@ -2295,6 +2307,10 @@ class ReTests(unittest.TestCase):
|
|||
self.assertIsNone(re.fullmatch(r'(?>(?:ab)*)', 'abc'))
|
||||
self.assertIsNone(re.fullmatch(r'(?>(?:ab)?)', 'abc'))
|
||||
self.assertIsNone(re.fullmatch(r'(?>(?:ab){1,3})', 'abc'))
|
||||
self.assertTrue(re.fullmatch(r'(?>(?:ab)+)c', 'abc'))
|
||||
self.assertTrue(re.fullmatch(r'(?>(?:ab)*)c', 'abc'))
|
||||
self.assertTrue(re.fullmatch(r'(?>(?:ab)?)c', 'abc'))
|
||||
self.assertTrue(re.fullmatch(r'(?>(?:ab){1,3})c', 'abc'))
|
||||
|
||||
def test_findall_atomic_grouping(self):
|
||||
self.assertEqual(re.findall(r'(?>a+)', 'aab'), ['aa'])
|
||||
|
@ -2307,6 +2323,10 @@ class ReTests(unittest.TestCase):
|
|||
self.assertEqual(re.findall(r'(?>(?:ab)?)', 'ababc'), ['ab', 'ab', '', ''])
|
||||
self.assertEqual(re.findall(r'(?>(?:ab){1,3})', 'ababc'), ['abab'])
|
||||
|
||||
def test_bug_gh91616(self):
|
||||
self.assertTrue(re.fullmatch(r'(?s:(?>.*?\.).*)\Z', "a.txt")) # reproducer
|
||||
self.assertTrue(re.fullmatch(r'(?s:(?=(?P<g0>.*?\.))(?P=g0).*)\Z', "a.txt"))
|
||||
|
||||
|
||||
def get_debug_out(pat):
|
||||
with captured_stdout() as out:
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
:mod:`re` module, fix :meth:`~re.Pattern.fullmatch` mismatch when using Atomic
|
||||
Grouping or Possessive Quantifiers.
|
|
@ -1259,8 +1259,8 @@ dispatch:
|
|||
/* Check for minimum required matches. */
|
||||
while (ctx->count < (Py_ssize_t)pattern[1]) {
|
||||
/* not enough matches */
|
||||
DO_JUMP(JUMP_POSS_REPEAT_1, jump_poss_repeat_1,
|
||||
&pattern[3]);
|
||||
DO_JUMP0(JUMP_POSS_REPEAT_1, jump_poss_repeat_1,
|
||||
&pattern[3]);
|
||||
if (ret) {
|
||||
RETURN_ON_ERROR(ret);
|
||||
ctx->count++;
|
||||
|
@ -1306,8 +1306,8 @@ dispatch:
|
|||
|
||||
/* We have not reached the maximin matches, so try to
|
||||
match once more. */
|
||||
DO_JUMP(JUMP_POSS_REPEAT_2, jump_poss_repeat_2,
|
||||
&pattern[3]);
|
||||
DO_JUMP0(JUMP_POSS_REPEAT_2, jump_poss_repeat_2,
|
||||
&pattern[3]);
|
||||
|
||||
/* Check to see if the last attempted match
|
||||
succeeded. */
|
||||
|
@ -1348,15 +1348,15 @@ dispatch:
|
|||
TRACE(("|%p|%p|ATOMIC_GROUP\n", pattern, ptr));
|
||||
|
||||
/* Set the global Input pointer to this context's Input
|
||||
pointer */
|
||||
pointer */
|
||||
state->ptr = ptr;
|
||||
|
||||
/* Evaluate the Atomic Group in a new context, terminating
|
||||
when the end of the group, represented by a SUCCESS op
|
||||
code, is reached. */
|
||||
/* Group Pattern begins at an offset of 1 code. */
|
||||
DO_JUMP(JUMP_ATOMIC_GROUP, jump_atomic_group,
|
||||
&pattern[1]);
|
||||
DO_JUMP0(JUMP_ATOMIC_GROUP, jump_atomic_group,
|
||||
&pattern[1]);
|
||||
|
||||
/* Test Exit Condition */
|
||||
RETURN_ON_ERROR(ret);
|
||||
|
|
Loading…
Reference in New Issue