[3.9] bpo-42218: Correctly handle errors in left-recursive rules (GH-23065) (GH-23066)
Left-recursive rules need to check for errors explicitly, since
even if the rule returns NULL, the parsing might continue and lead
to long-distance failures.
Co-authored-by: Pablo Galindo <Pablogsal@gmail.com>
(cherry picked from commit 02cdfc93f8
)
Automerge-Triggered-By: GH:lysnikolaou
This commit is contained in:
parent
dbaa07db67
commit
cfcb952e30
|
@ -964,6 +964,14 @@ def func2():
|
||||||
"""
|
"""
|
||||||
self._check_error(code, "invalid syntax")
|
self._check_error(code, "invalid syntax")
|
||||||
|
|
||||||
|
def test_invalid_line_continuation_left_recursive(self):
|
||||||
|
# Check bpo-42218: SyntaxErrors following left-recursive rules
|
||||||
|
# (t_primary_raw in this case) need to be tested explicitly
|
||||||
|
self._check_error("A.\u018a\\ ",
|
||||||
|
"unexpected character after line continuation character")
|
||||||
|
self._check_error("A.\u03bc\\\n",
|
||||||
|
"unexpected EOF while parsing")
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
support.run_unittest(SyntaxTestCase)
|
support.run_unittest(SyntaxTestCase)
|
||||||
from test import test_syntax
|
from test import test_syntax
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Fixed a bug in the PEG parser that was causing crashes in debug mode. Now errors are checked
|
||||||
|
in left-recursive rules to avoid cases where such errors do not get handled in time and appear
|
||||||
|
as long-distance crashes in other places.
|
|
@ -3460,6 +3460,8 @@ dotted_name_rule(Parser *p)
|
||||||
}
|
}
|
||||||
p->mark = _mark;
|
p->mark = _mark;
|
||||||
void *_raw = dotted_name_raw(p);
|
void *_raw = dotted_name_raw(p);
|
||||||
|
if (p->error_indicator)
|
||||||
|
return NULL;
|
||||||
if (_raw == NULL || p->mark <= _resmark)
|
if (_raw == NULL || p->mark <= _resmark)
|
||||||
break;
|
break;
|
||||||
_resmark = p->mark;
|
_resmark = p->mark;
|
||||||
|
@ -9044,6 +9046,8 @@ bitwise_or_rule(Parser *p)
|
||||||
}
|
}
|
||||||
p->mark = _mark;
|
p->mark = _mark;
|
||||||
void *_raw = bitwise_or_raw(p);
|
void *_raw = bitwise_or_raw(p);
|
||||||
|
if (p->error_indicator)
|
||||||
|
return NULL;
|
||||||
if (_raw == NULL || p->mark <= _resmark)
|
if (_raw == NULL || p->mark <= _resmark)
|
||||||
break;
|
break;
|
||||||
_resmark = p->mark;
|
_resmark = p->mark;
|
||||||
|
@ -9158,6 +9162,8 @@ bitwise_xor_rule(Parser *p)
|
||||||
}
|
}
|
||||||
p->mark = _mark;
|
p->mark = _mark;
|
||||||
void *_raw = bitwise_xor_raw(p);
|
void *_raw = bitwise_xor_raw(p);
|
||||||
|
if (p->error_indicator)
|
||||||
|
return NULL;
|
||||||
if (_raw == NULL || p->mark <= _resmark)
|
if (_raw == NULL || p->mark <= _resmark)
|
||||||
break;
|
break;
|
||||||
_resmark = p->mark;
|
_resmark = p->mark;
|
||||||
|
@ -9272,6 +9278,8 @@ bitwise_and_rule(Parser *p)
|
||||||
}
|
}
|
||||||
p->mark = _mark;
|
p->mark = _mark;
|
||||||
void *_raw = bitwise_and_raw(p);
|
void *_raw = bitwise_and_raw(p);
|
||||||
|
if (p->error_indicator)
|
||||||
|
return NULL;
|
||||||
if (_raw == NULL || p->mark <= _resmark)
|
if (_raw == NULL || p->mark <= _resmark)
|
||||||
break;
|
break;
|
||||||
_resmark = p->mark;
|
_resmark = p->mark;
|
||||||
|
@ -9386,6 +9394,8 @@ shift_expr_rule(Parser *p)
|
||||||
}
|
}
|
||||||
p->mark = _mark;
|
p->mark = _mark;
|
||||||
void *_raw = shift_expr_raw(p);
|
void *_raw = shift_expr_raw(p);
|
||||||
|
if (p->error_indicator)
|
||||||
|
return NULL;
|
||||||
if (_raw == NULL || p->mark <= _resmark)
|
if (_raw == NULL || p->mark <= _resmark)
|
||||||
break;
|
break;
|
||||||
_resmark = p->mark;
|
_resmark = p->mark;
|
||||||
|
@ -9539,6 +9549,8 @@ sum_rule(Parser *p)
|
||||||
}
|
}
|
||||||
p->mark = _mark;
|
p->mark = _mark;
|
||||||
void *_raw = sum_raw(p);
|
void *_raw = sum_raw(p);
|
||||||
|
if (p->error_indicator)
|
||||||
|
return NULL;
|
||||||
if (_raw == NULL || p->mark <= _resmark)
|
if (_raw == NULL || p->mark <= _resmark)
|
||||||
break;
|
break;
|
||||||
_resmark = p->mark;
|
_resmark = p->mark;
|
||||||
|
@ -9698,6 +9710,8 @@ term_rule(Parser *p)
|
||||||
}
|
}
|
||||||
p->mark = _mark;
|
p->mark = _mark;
|
||||||
void *_raw = term_raw(p);
|
void *_raw = term_raw(p);
|
||||||
|
if (p->error_indicator)
|
||||||
|
return NULL;
|
||||||
if (_raw == NULL || p->mark <= _resmark)
|
if (_raw == NULL || p->mark <= _resmark)
|
||||||
break;
|
break;
|
||||||
_resmark = p->mark;
|
_resmark = p->mark;
|
||||||
|
@ -10302,6 +10316,8 @@ primary_rule(Parser *p)
|
||||||
}
|
}
|
||||||
p->mark = _mark;
|
p->mark = _mark;
|
||||||
void *_raw = primary_raw(p);
|
void *_raw = primary_raw(p);
|
||||||
|
if (p->error_indicator)
|
||||||
|
return NULL;
|
||||||
if (_raw == NULL || p->mark <= _resmark)
|
if (_raw == NULL || p->mark <= _resmark)
|
||||||
break;
|
break;
|
||||||
_resmark = p->mark;
|
_resmark = p->mark;
|
||||||
|
@ -13962,6 +13978,8 @@ t_primary_rule(Parser *p)
|
||||||
}
|
}
|
||||||
p->mark = _mark;
|
p->mark = _mark;
|
||||||
void *_raw = t_primary_raw(p);
|
void *_raw = t_primary_raw(p);
|
||||||
|
if (p->error_indicator)
|
||||||
|
return NULL;
|
||||||
if (_raw == NULL || p->mark <= _resmark)
|
if (_raw == NULL || p->mark <= _resmark)
|
||||||
break;
|
break;
|
||||||
_resmark = p->mark;
|
_resmark = p->mark;
|
||||||
|
|
|
@ -496,6 +496,9 @@ class CParserGenerator(ParserGenerator, GrammarVisitor):
|
||||||
)
|
)
|
||||||
self.print("p->mark = _mark;")
|
self.print("p->mark = _mark;")
|
||||||
self.print(f"void *_raw = {node.name}_raw(p);")
|
self.print(f"void *_raw = {node.name}_raw(p);")
|
||||||
|
self.print("if (p->error_indicator)")
|
||||||
|
with self.indent():
|
||||||
|
self.print("return NULL;")
|
||||||
self.print("if (_raw == NULL || p->mark <= _resmark)")
|
self.print("if (_raw == NULL || p->mark <= _resmark)")
|
||||||
with self.indent():
|
with self.indent():
|
||||||
self.print("break;")
|
self.print("break;")
|
||||||
|
|
Loading…
Reference in New Issue