Skip to content

Commit b71dc71

Browse files
authored
bpo-46707: Avoid potential exponential backtracking in some syntax errors (pythonGH-31241)
1 parent cb68788 commit b71dc71

File tree

4 files changed

+1064
-1047
lines changed

4 files changed

+1064
-1047
lines changed

Grammar/python.gram

+3-1
Original file line numberDiff line numberDiff line change
@@ -1095,13 +1095,15 @@ invalid_expression:
10951095
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Perhaps you forgot a comma?") }
10961096
| a=disjunction 'if' b=disjunction !('else'|':') { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "expected 'else' after 'if' expression") }
10971097

1098+
invalid_left_assignment_prefixes(memo): list|tuple|genexp|'True'|'None'|'False'
1099+
10981100
invalid_named_expression:
10991101
| a=expression ':=' expression {
11001102
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
11011103
a, "cannot use assignment expressions with %s", _PyPegen_get_expr_name(a)) }
11021104
| a=NAME '=' b=bitwise_or !('='|':=') {
11031105
p->in_raw_rule ? NULL : RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Maybe you meant '==' or ':=' instead of '='?") }
1104-
| !(list|tuple|genexp|'True'|'None'|'False') a=bitwise_or b='=' bitwise_or !('='|':=') {
1106+
| !invalid_left_assignment_prefixes a=bitwise_or b='=' bitwise_or !('='|':=') {
11051107
p->in_raw_rule ? NULL : RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot assign to %s here. Maybe you meant '==' instead of '='?",
11061108
_PyPegen_get_expr_name(a)) }
11071109

Lib/test/test_syntax.py

+8
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,14 @@ def test_error_on_parser_stack_overflow(self):
17701770
with self.assertRaises(MemoryError):
17711771
compile(source, "<string>", mode)
17721772

1773+
@support.cpython_only
1774+
def test_deep_invalid_rule(self):
1775+
# Check that a very deep invalid rule in the PEG
1776+
# parser doesn't have exponential backtracking.
1777+
source = "d{{{{{{{{{{{{{{{{{{{{{{{{{```{{{{{{{ef f():y"
1778+
with self.assertRaises(SyntaxError):
1779+
compile(source, "<string>", "exec")
1780+
17731781

17741782
def load_tests(loader, tests, pattern):
17751783
tests.addTest(doctest.DocTestSuite())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Avoid potential exponential backtracking when producing some syntax errors
2+
involving lots of brackets. Patch by Pablo Galindo.

0 commit comments

Comments
 (0)