Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5893b5d

Browse files
authored
gh-93351: Ensure the position information in AST nodes created by the parser is always consistent (GH-93352)
1 parent 8136606 commit 5893b5d

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

Lib/test/test_ast.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,33 @@ def test_ast_validation(self):
335335
for snippet in snippets_to_validate:
336336
tree = ast.parse(snippet)
337337
compile(tree, '<string>', 'exec')
338+
339+
def test_invalid_position_information(self):
340+
invalid_linenos = [
341+
(10, 1), (-10, -11), (10, -11), (-5, -2), (-5, 1)
342+
]
343+
344+
for lineno, end_lineno in invalid_linenos:
345+
with self.subTest(f"Check invalid linenos {lineno}:{end_lineno}"):
346+
snippet = "a = 1"
347+
tree = ast.parse(snippet)
348+
tree.body[0].lineno = lineno
349+
tree.body[0].end_lineno = end_lineno
350+
with self.assertRaises(ValueError):
351+
compile(tree, '<string>', 'exec')
352+
353+
invalid_col_offsets = [
354+
(10, 1), (-10, -11), (10, -11), (-5, -2), (-5, 1)
355+
]
356+
for col_offset, end_col_offset in invalid_col_offsets:
357+
with self.subTest(f"Check invalid col_offset {col_offset}:{end_col_offset}"):
358+
snippet = "a = 1"
359+
tree = ast.parse(snippet)
360+
tree.body[0].col_offset = col_offset
361+
tree.body[0].end_col_offset = end_col_offset
362+
with self.assertRaises(ValueError):
363+
compile(tree, '<string>', 'exec')
364+
338365

339366
def test_slice(self):
340367
slc = ast.parse("x[::]").body[0].value.slice

Python/ast.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,27 @@ static int validate_stmt(struct validator *, stmt_ty);
2222
static int validate_expr(struct validator *, expr_ty, expr_context_ty);
2323
static int validate_pattern(struct validator *, pattern_ty, int);
2424

25+
#define VALIDATE_POSITIONS(node) \
26+
if (node->lineno > node->end_lineno) { \
27+
PyErr_Format(PyExc_ValueError, \
28+
"line %d-%d is not a valid range", \
29+
node->lineno, node->end_lineno); \
30+
return 0; \
31+
} \
32+
if ((node->lineno < 0 && node->end_lineno != node->lineno) || \
33+
(node->col_offset < 0 && node->col_offset != node->end_col_offset)) { \
34+
PyErr_Format(PyExc_ValueError, \
35+
"line %d-%d, column %d-%d is not a valid range", \
36+
node->lineno, node->end_lineno, node->col_offset, node->end_col_offset); \
37+
return 0; \
38+
} \
39+
if (node->lineno == node->end_lineno && node->col_offset > node->end_col_offset) { \
40+
PyErr_Format(PyExc_ValueError, \
41+
"line %d, column %d-%d is not a valid range", \
42+
node->lineno, node->col_offset, node->end_col_offset); \
43+
return 0; \
44+
}
45+
2546
static int
2647
validate_name(PyObject *name)
2748
{
@@ -75,6 +96,7 @@ validate_args(struct validator *state, asdl_arg_seq *args)
7596
Py_ssize_t i;
7697
for (i = 0; i < asdl_seq_LEN(args); i++) {
7798
arg_ty arg = asdl_seq_GET(args, i);
99+
VALIDATE_POSITIONS(arg);
78100
if (arg->annotation && !validate_expr(state, arg->annotation, Load))
79101
return 0;
80102
}
@@ -183,6 +205,7 @@ validate_constant(struct validator *state, PyObject *value)
183205
static int
184206
validate_expr(struct validator *state, expr_ty exp, expr_context_ty ctx)
185207
{
208+
VALIDATE_POSITIONS(exp);
186209
int ret = -1;
187210
if (++state->recursion_depth > state->recursion_limit) {
188211
PyErr_SetString(PyExc_RecursionError,
@@ -505,6 +528,7 @@ validate_capture(PyObject *name)
505528
static int
506529
validate_pattern(struct validator *state, pattern_ty p, int star_ok)
507530
{
531+
VALIDATE_POSITIONS(p);
508532
int ret = -1;
509533
if (++state->recursion_depth > state->recursion_limit) {
510534
PyErr_SetString(PyExc_RecursionError,
@@ -674,6 +698,7 @@ validate_body(struct validator *state, asdl_stmt_seq *body, const char *owner)
674698
static int
675699
validate_stmt(struct validator *state, stmt_ty stmt)
676700
{
701+
VALIDATE_POSITIONS(stmt);
677702
int ret = -1;
678703
Py_ssize_t i;
679704
if (++state->recursion_depth > state->recursion_limit) {
@@ -807,6 +832,7 @@ validate_stmt(struct validator *state, stmt_ty stmt)
807832
}
808833
for (i = 0; i < asdl_seq_LEN(stmt->v.Try.handlers); i++) {
809834
excepthandler_ty handler = asdl_seq_GET(stmt->v.Try.handlers, i);
835+
VALIDATE_POSITIONS(handler);
810836
if ((handler->v.ExceptHandler.type &&
811837
!validate_expr(state, handler->v.ExceptHandler.type, Load)) ||
812838
!validate_body(state, handler->v.ExceptHandler.body, "ExceptHandler"))

0 commit comments

Comments
 (0)