Skip to content

Commit b2eaa75

Browse files
authored
gh-126105: Fix crash in ast module, when ._fields is deleted (#126115)
Previously, if the `ast.AST._fields` attribute was deleted, attempts to create a new `as`t node would crash due to the assumption that `_fields` always had a non-NULL value. Now it has been fixed by adding an extra check to ensure that `_fields` does not have a NULL value (this can happen when you manually remove `_fields` attribute).
1 parent 0bbbe15 commit b2eaa75

File tree

4 files changed

+34
-20
lines changed

4 files changed

+34
-20
lines changed

Lib/test/test_ast/test_ast.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,23 @@ def test_AST_objects(self):
8484
# "ast.AST constructor takes 0 positional arguments"
8585
ast.AST(2)
8686

87+
def test_AST_fields_NULL_check(self):
88+
# See: https://github.com/python/cpython/issues/126105
89+
old_value = ast.AST._fields
90+
91+
def cleanup():
92+
ast.AST._fields = old_value
93+
self.addCleanup(cleanup)
94+
95+
del ast.AST._fields
96+
97+
msg = "type object 'ast.AST' has no attribute '_fields'"
98+
# Both examples used to crash:
99+
with self.assertRaisesRegex(AttributeError, msg):
100+
ast.AST(arg1=123)
101+
with self.assertRaisesRegex(AttributeError, msg):
102+
ast.AST()
103+
87104
def test_AST_garbage_collection(self):
88105
class X:
89106
pass
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a crash in :mod:`ast` when the :attr:`ast.AST._fields` attribute is deleted.

Parser/asdl_c.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -884,19 +884,17 @@ def visitModule(self, mod):
884884
Py_ssize_t i, numfields = 0;
885885
int res = -1;
886886
PyObject *key, *value, *fields, *attributes = NULL, *remaining_fields = NULL;
887-
if (PyObject_GetOptionalAttr((PyObject*)Py_TYPE(self), state->_fields, &fields) < 0) {
887+
888+
fields = PyObject_GetAttr((PyObject*)Py_TYPE(self), state->_fields);
889+
if (fields == NULL) {
888890
goto cleanup;
889891
}
890-
if (fields) {
891-
numfields = PySequence_Size(fields);
892-
if (numfields == -1) {
893-
goto cleanup;
894-
}
895-
remaining_fields = PySet_New(fields);
896-
}
897-
else {
898-
remaining_fields = PySet_New(NULL);
892+
893+
numfields = PySequence_Size(fields);
894+
if (numfields == -1) {
895+
goto cleanup;
899896
}
897+
remaining_fields = PySet_New(fields);
900898
if (remaining_fields == NULL) {
901899
goto cleanup;
902900
}

Python/Python-ast.c

Lines changed: 8 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)