[Python-checkins] gh-92597: Ensure that AST nodes without explicit end positions can be compiled (GH-93359)

pablogsal webhook-mailer at python.org
Tue May 31 19:00:57 EDT 2022


https://github.com/python/cpython/commit/705eaec28f7bee530b1c1635ba385a49a1feaf32
commit: 705eaec28f7bee530b1c1635ba385a49a1feaf32
branch: main
author: Pablo Galindo Salgado <Pablogsal at gmail.com>
committer: pablogsal <Pablogsal at gmail.com>
date: 2022-06-01T00:00:47+01:00
summary:

gh-92597: Ensure that AST nodes without explicit end positions can be compiled (GH-93359)

files:
A Misc/NEWS.d/next/Core and Builtins/2022-05-30-19-00-38.gh-issue-93359.zXV3A0.rst
M Lib/test/test_ast.py
M Parser/asdl_c.py
M Python/Python-ast.c

diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index 896eb5bedd7f3..33df22cb35a9e 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -362,6 +362,14 @@ def test_invalid_position_information(self):
                 with self.assertRaises(ValueError):
                     compile(tree, '<string>', 'exec')
 
+    def test_compilation_of_ast_nodes_with_default_end_position_values(self):
+        tree = ast.Module(body=[
+            ast.Import(names=[ast.alias(name='builtins', lineno=1, col_offset=0)], lineno=1, col_offset=0), 
+            ast.Import(names=[ast.alias(name='traceback', lineno=0, col_offset=0)], lineno=0, col_offset=1)
+        ], type_ignores=[])
+
+        # Check that compilation doesn't crash. Note: this may crash explicitly only on debug mode.
+        compile(tree, "<string>", "exec")
 
     def test_slice(self):
         slc = ast.parse("x[::]").body[0].value.slice
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-30-19-00-38.gh-issue-93359.zXV3A0.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-30-19-00-38.gh-issue-93359.zXV3A0.rst
new file mode 100644
index 0000000000000..36e5e52390d7b
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-05-30-19-00-38.gh-issue-93359.zXV3A0.rst	
@@ -0,0 +1,2 @@
+Ensure that custom :mod:`ast` nodes without explicit end positions can be
+compiled. Patch by Pablo Galindo.
diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py
index 3bfe320fe3b70..1101a3593dfe2 100755
--- a/Parser/asdl_c.py
+++ b/Parser/asdl_c.py
@@ -488,6 +488,12 @@ def visitProduct(self, prod, name):
 
 
 class Obj2ModVisitor(PickleVisitor):
+
+    attribute_special_defaults = {
+        "end_lineno": "lineno",
+        "end_col_offset": "col_offset",
+    }
+
     @contextmanager
     def recursive_call(self, node, level):
         self.emit('if (_Py_EnterRecursiveCall(" while traversing \'%s\' node")) {' % node, level, reflow=False)
@@ -637,7 +643,13 @@ def visitField(self, field, name, sum=None, prod=None, depth=0):
             self.emit("if (tmp == NULL || tmp == Py_None) {", depth)
             self.emit("Py_CLEAR(tmp);", depth+1)
             if self.isNumeric(field):
-                self.emit("%s = 0;" % field.name, depth+1)
+                if field.name in self.attribute_special_defaults:
+                    self.emit(
+                        "%s = %s;" % (field.name, self.attribute_special_defaults[field.name]),
+                        depth+1,
+                    )
+                else:
+                    self.emit("%s = 0;" % field.name, depth+1)
             elif not self.isSimpleType(field):
                 self.emit("%s = NULL;" % field.name, depth+1)
             else:
diff --git a/Python/Python-ast.c b/Python/Python-ast.c
index 3861eaf978a38..e52a72d43bcbd 100644
--- a/Python/Python-ast.c
+++ b/Python/Python-ast.c
@@ -5697,7 +5697,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena*
     }
     if (tmp == NULL || tmp == Py_None) {
         Py_CLEAR(tmp);
-        end_lineno = 0;
+        end_lineno = lineno;
     }
     else {
         int res;
@@ -5714,7 +5714,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena*
     }
     if (tmp == NULL || tmp == Py_None) {
         Py_CLEAR(tmp);
-        end_col_offset = 0;
+        end_col_offset = col_offset;
     }
     else {
         int res;
@@ -8114,7 +8114,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena*
     }
     if (tmp == NULL || tmp == Py_None) {
         Py_CLEAR(tmp);
-        end_lineno = 0;
+        end_lineno = lineno;
     }
     else {
         int res;
@@ -8131,7 +8131,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena*
     }
     if (tmp == NULL || tmp == Py_None) {
         Py_CLEAR(tmp);
-        end_col_offset = 0;
+        end_col_offset = col_offset;
     }
     else {
         int res;
@@ -10291,7 +10291,7 @@ obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty*
     }
     if (tmp == NULL || tmp == Py_None) {
         Py_CLEAR(tmp);
-        end_lineno = 0;
+        end_lineno = lineno;
     }
     else {
         int res;
@@ -10308,7 +10308,7 @@ obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty*
     }
     if (tmp == NULL || tmp == Py_None) {
         Py_CLEAR(tmp);
-        end_col_offset = 0;
+        end_col_offset = col_offset;
     }
     else {
         int res;
@@ -10755,7 +10755,7 @@ obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena)
     }
     if (tmp == NULL || tmp == Py_None) {
         Py_CLEAR(tmp);
-        end_lineno = 0;
+        end_lineno = lineno;
     }
     else {
         int res;
@@ -10772,7 +10772,7 @@ obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena)
     }
     if (tmp == NULL || tmp == Py_None) {
         Py_CLEAR(tmp);
-        end_col_offset = 0;
+        end_col_offset = col_offset;
     }
     else {
         int res;
@@ -10877,7 +10877,7 @@ obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out,
     }
     if (tmp == NULL || tmp == Py_None) {
         Py_CLEAR(tmp);
-        end_lineno = 0;
+        end_lineno = lineno;
     }
     else {
         int res;
@@ -10894,7 +10894,7 @@ obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out,
     }
     if (tmp == NULL || tmp == Py_None) {
         Py_CLEAR(tmp);
-        end_col_offset = 0;
+        end_col_offset = col_offset;
     }
     else {
         int res;
@@ -10999,7 +10999,7 @@ obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena*
     }
     if (tmp == NULL || tmp == Py_None) {
         Py_CLEAR(tmp);
-        end_lineno = 0;
+        end_lineno = lineno;
     }
     else {
         int res;
@@ -11016,7 +11016,7 @@ obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena*
     }
     if (tmp == NULL || tmp == Py_None) {
         Py_CLEAR(tmp);
-        end_col_offset = 0;
+        end_col_offset = col_offset;
     }
     else {
         int res;



More information about the Python-checkins mailing list