Skip to content

Commit 265bc19

Browse files
[3.13] gh-126105: Fix crash in ast module, when ._fields is deleted (GH-126115) (#126130)
gh-126105: Fix crash in `ast` module, when `._fields` is deleted (GH-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). (cherry picked from commit b2eaa75) Co-authored-by: sobolevn <[email protected]>
1 parent e2c1884 commit 265bc19

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
@@ -72,6 +72,23 @@ def test_AST_objects(self):
7272
# "ast.AST constructor takes 0 positional arguments"
7373
ast.AST(2)
7474

75+
def test_AST_fields_NULL_check(self):
76+
# See: https://github.com/python/cpython/issues/126105
77+
old_value = ast.AST._fields
78+
79+
def cleanup():
80+
ast.AST._fields = old_value
81+
self.addCleanup(cleanup)
82+
83+
del ast.AST._fields
84+
85+
msg = "type object 'ast.AST' has no attribute '_fields'"
86+
# Both examples used to crash:
87+
with self.assertRaisesRegex(AttributeError, msg):
88+
ast.AST(arg1=123)
89+
with self.assertRaisesRegex(AttributeError, msg):
90+
ast.AST()
91+
7592
def test_AST_garbage_collection(self):
7693
class X:
7794
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
@@ -881,19 +881,17 @@ def visitModule(self, mod):
881881
Py_ssize_t i, numfields = 0;
882882
int res = -1;
883883
PyObject *key, *value, *fields, *attributes = NULL, *remaining_fields = NULL;
884-
if (PyObject_GetOptionalAttr((PyObject*)Py_TYPE(self), state->_fields, &fields) < 0) {
884+
885+
fields = PyObject_GetAttr((PyObject*)Py_TYPE(self), state->_fields);
886+
if (fields == NULL) {
885887
goto cleanup;
886888
}
887-
if (fields) {
888-
numfields = PySequence_Size(fields);
889-
if (numfields == -1) {
890-
goto cleanup;
891-
}
892-
remaining_fields = PySet_New(fields);
893-
}
894-
else {
895-
remaining_fields = PySet_New(NULL);
889+
890+
numfields = PySequence_Size(fields);
891+
if (numfields == -1) {
892+
goto cleanup;
896893
}
894+
remaining_fields = PySet_New(fields);
897895
if (remaining_fields == NULL) {
898896
goto cleanup;
899897
}

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)