Skip to content

Commit fd105a8

Browse files
committed
gh-130775: Validate negative locations in ast
1 parent 8f11af4 commit fd105a8

File tree

4 files changed

+32
-0
lines changed

4 files changed

+32
-0
lines changed

Lib/test/test_ast/test_ast.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,27 @@ def test_compilation_of_ast_nodes_with_default_end_position_values(self):
204204
# Check that compilation doesn't crash. Note: this may crash explicitly only on debug mode.
205205
compile(tree, "<string>", "exec")
206206

207+
def test_compilation_of_ast_nodes_with_negative_position_values(self):
208+
# See https://github.com/python/cpython/issues/130775
209+
alias = ast.alias(name='traceback', lineno=0, col_offset=0)
210+
for attrs in (
211+
{'lineno': -2, 'col_offset': 0},
212+
{'lineno': 0, 'col_offset': -2},
213+
{'lineno': 0, 'col_offset': -2, 'end_col_offset': -2},
214+
{'lineno': -2, 'end_lineno': -2, 'col_offset': 0},
215+
):
216+
with self.subTest(attrs=attrs):
217+
tree = ast.Module(body=[
218+
ast.Import(names=[alias], **attrs)
219+
], type_ignores=[])
220+
221+
# It used to crash on this step:
222+
with self.assertRaisesRegex(
223+
ValueError,
224+
'AST node has invalid location',
225+
):
226+
compile(tree, "<string>", "exec")
227+
207228
def test_slice(self):
208229
slc = ast.parse("x[::]").body[0].value.slice
209230
self.assertIsNone(slc.upper)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Validate negative :mod:`ast` locations, we only allow ``-1`` as a special
2+
value.

Python/assemble.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ write_location_info_entry(struct assembler* a, location loc, int isize)
297297
int line_delta = loc.lineno - a->a_lineno;
298298
int column = loc.col_offset;
299299
int end_column = loc.end_col_offset;
300+
// Values are validated in `VALIDATE_POSITIONS` in `ast.c`:
300301
assert(column >= -1);
301302
assert(end_column >= -1);
302303
if (column < 0 || end_column < 0) {

Python/ast.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ static int validate_typeparam(type_param_ty);
4040
node->col_offset, node->end_col_offset, node->lineno, node->end_lineno); \
4141
return 0; \
4242
} \
43+
if (node->lineno < -1 || node->end_lineno < -1 || \
44+
node->col_offset < -1 || node->end_col_offset < -1) { \
45+
PyErr_Format(PyExc_ValueError, \
46+
"AST node has invalid location (%d, %d, %d, %d)", \
47+
node->lineno, node->end_lineno, \
48+
node->col_offset, node->end_col_offset); \
49+
return 0; \
50+
} \
4351
if (node->lineno == node->end_lineno && node->col_offset > node->end_col_offset) { \
4452
PyErr_Format(PyExc_ValueError, \
4553
"line %d, column %d-%d is not a valid range", \

0 commit comments

Comments
 (0)