Skip to content
Snippets Groups Projects
Unverified Commit 5893b5db authored by Pablo Galindo Salgado's avatar Pablo Galindo Salgado Committed by GitHub
Browse files

gh-93351: Ensure the position information in AST nodes created by the parser...

gh-93351: Ensure the position information in AST nodes created by the parser is always consistent (GH-93352)
parent 81366067
No related branches found
No related tags found
No related merge requests found
...@@ -336,6 +336,33 @@ def test_ast_validation(self): ...@@ -336,6 +336,33 @@ def test_ast_validation(self):
tree = ast.parse(snippet) tree = ast.parse(snippet)
compile(tree, '<string>', 'exec') compile(tree, '<string>', 'exec')
def test_invalid_position_information(self):
invalid_linenos = [
(10, 1), (-10, -11), (10, -11), (-5, -2), (-5, 1)
]
for lineno, end_lineno in invalid_linenos:
with self.subTest(f"Check invalid linenos {lineno}:{end_lineno}"):
snippet = "a = 1"
tree = ast.parse(snippet)
tree.body[0].lineno = lineno
tree.body[0].end_lineno = end_lineno
with self.assertRaises(ValueError):
compile(tree, '<string>', 'exec')
invalid_col_offsets = [
(10, 1), (-10, -11), (10, -11), (-5, -2), (-5, 1)
]
for col_offset, end_col_offset in invalid_col_offsets:
with self.subTest(f"Check invalid col_offset {col_offset}:{end_col_offset}"):
snippet = "a = 1"
tree = ast.parse(snippet)
tree.body[0].col_offset = col_offset
tree.body[0].end_col_offset = end_col_offset
with self.assertRaises(ValueError):
compile(tree, '<string>', 'exec')
def test_slice(self): def test_slice(self):
slc = ast.parse("x[::]").body[0].value.slice slc = ast.parse("x[::]").body[0].value.slice
self.assertIsNone(slc.upper) self.assertIsNone(slc.upper)
......
...@@ -22,6 +22,27 @@ static int validate_stmt(struct validator *, stmt_ty); ...@@ -22,6 +22,27 @@ static int validate_stmt(struct validator *, stmt_ty);
static int validate_expr(struct validator *, expr_ty, expr_context_ty); static int validate_expr(struct validator *, expr_ty, expr_context_ty);
static int validate_pattern(struct validator *, pattern_ty, int); static int validate_pattern(struct validator *, pattern_ty, int);
#define VALIDATE_POSITIONS(node) \
if (node->lineno > node->end_lineno) { \
PyErr_Format(PyExc_ValueError, \
"line %d-%d is not a valid range", \
node->lineno, node->end_lineno); \
return 0; \
} \
if ((node->lineno < 0 && node->end_lineno != node->lineno) || \
(node->col_offset < 0 && node->col_offset != node->end_col_offset)) { \
PyErr_Format(PyExc_ValueError, \
"line %d-%d, column %d-%d is not a valid range", \
node->lineno, node->end_lineno, node->col_offset, node->end_col_offset); \
return 0; \
} \
if (node->lineno == node->end_lineno && node->col_offset > node->end_col_offset) { \
PyErr_Format(PyExc_ValueError, \
"line %d, column %d-%d is not a valid range", \
node->lineno, node->col_offset, node->end_col_offset); \
return 0; \
}
static int static int
validate_name(PyObject *name) validate_name(PyObject *name)
{ {
...@@ -75,6 +96,7 @@ validate_args(struct validator *state, asdl_arg_seq *args) ...@@ -75,6 +96,7 @@ validate_args(struct validator *state, asdl_arg_seq *args)
Py_ssize_t i; Py_ssize_t i;
for (i = 0; i < asdl_seq_LEN(args); i++) { for (i = 0; i < asdl_seq_LEN(args); i++) {
arg_ty arg = asdl_seq_GET(args, i); arg_ty arg = asdl_seq_GET(args, i);
VALIDATE_POSITIONS(arg);
if (arg->annotation && !validate_expr(state, arg->annotation, Load)) if (arg->annotation && !validate_expr(state, arg->annotation, Load))
return 0; return 0;
} }
...@@ -183,6 +205,7 @@ validate_constant(struct validator *state, PyObject *value) ...@@ -183,6 +205,7 @@ validate_constant(struct validator *state, PyObject *value)
static int static int
validate_expr(struct validator *state, expr_ty exp, expr_context_ty ctx) validate_expr(struct validator *state, expr_ty exp, expr_context_ty ctx)
{ {
VALIDATE_POSITIONS(exp);
int ret = -1; int ret = -1;
if (++state->recursion_depth > state->recursion_limit) { if (++state->recursion_depth > state->recursion_limit) {
PyErr_SetString(PyExc_RecursionError, PyErr_SetString(PyExc_RecursionError,
...@@ -505,6 +528,7 @@ validate_capture(PyObject *name) ...@@ -505,6 +528,7 @@ validate_capture(PyObject *name)
static int static int
validate_pattern(struct validator *state, pattern_ty p, int star_ok) validate_pattern(struct validator *state, pattern_ty p, int star_ok)
{ {
VALIDATE_POSITIONS(p);
int ret = -1; int ret = -1;
if (++state->recursion_depth > state->recursion_limit) { if (++state->recursion_depth > state->recursion_limit) {
PyErr_SetString(PyExc_RecursionError, PyErr_SetString(PyExc_RecursionError,
...@@ -674,6 +698,7 @@ validate_body(struct validator *state, asdl_stmt_seq *body, const char *owner) ...@@ -674,6 +698,7 @@ validate_body(struct validator *state, asdl_stmt_seq *body, const char *owner)
static int static int
validate_stmt(struct validator *state, stmt_ty stmt) validate_stmt(struct validator *state, stmt_ty stmt)
{ {
VALIDATE_POSITIONS(stmt);
int ret = -1; int ret = -1;
Py_ssize_t i; Py_ssize_t i;
if (++state->recursion_depth > state->recursion_limit) { if (++state->recursion_depth > state->recursion_limit) {
...@@ -807,6 +832,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) ...@@ -807,6 +832,7 @@ validate_stmt(struct validator *state, stmt_ty stmt)
} }
for (i = 0; i < asdl_seq_LEN(stmt->v.Try.handlers); i++) { for (i = 0; i < asdl_seq_LEN(stmt->v.Try.handlers); i++) {
excepthandler_ty handler = asdl_seq_GET(stmt->v.Try.handlers, i); excepthandler_ty handler = asdl_seq_GET(stmt->v.Try.handlers, i);
VALIDATE_POSITIONS(handler);
if ((handler->v.ExceptHandler.type && if ((handler->v.ExceptHandler.type &&
!validate_expr(state, handler->v.ExceptHandler.type, Load)) || !validate_expr(state, handler->v.ExceptHandler.type, Load)) ||
!validate_body(state, handler->v.ExceptHandler.body, "ExceptHandler")) !validate_body(state, handler->v.ExceptHandler.body, "ExceptHandler"))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment