Skip to content

Commit

Permalink
gh-126105: Fix crash in ast module, when ._fields is deleted (#12…
Browse files Browse the repository at this point in the history
…6115)

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).
  • Loading branch information
sobolevn authored Oct 29, 2024
1 parent 0bbbe15 commit b2eaa75
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 20 deletions.
17 changes: 17 additions & 0 deletions Lib/test/test_ast/test_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,23 @@ def test_AST_objects(self):
# "ast.AST constructor takes 0 positional arguments"
ast.AST(2)

def test_AST_fields_NULL_check(self):
# See: https://github.com/python/cpython/issues/126105
old_value = ast.AST._fields

def cleanup():
ast.AST._fields = old_value
self.addCleanup(cleanup)

del ast.AST._fields

msg = "type object 'ast.AST' has no attribute '_fields'"
# Both examples used to crash:
with self.assertRaisesRegex(AttributeError, msg):
ast.AST(arg1=123)
with self.assertRaisesRegex(AttributeError, msg):
ast.AST()

def test_AST_garbage_collection(self):
class X:
pass
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix a crash in :mod:`ast` when the :attr:`ast.AST._fields` attribute is deleted.
18 changes: 8 additions & 10 deletions Parser/asdl_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -884,19 +884,17 @@ def visitModule(self, mod):
Py_ssize_t i, numfields = 0;
int res = -1;
PyObject *key, *value, *fields, *attributes = NULL, *remaining_fields = NULL;
if (PyObject_GetOptionalAttr((PyObject*)Py_TYPE(self), state->_fields, &fields) < 0) {
fields = PyObject_GetAttr((PyObject*)Py_TYPE(self), state->_fields);
if (fields == NULL) {
goto cleanup;
}
if (fields) {
numfields = PySequence_Size(fields);
if (numfields == -1) {
goto cleanup;
}
remaining_fields = PySet_New(fields);
}
else {
remaining_fields = PySet_New(NULL);
numfields = PySequence_Size(fields);
if (numfields == -1) {
goto cleanup;
}
remaining_fields = PySet_New(fields);
if (remaining_fields == NULL) {
goto cleanup;
}
Expand Down
18 changes: 8 additions & 10 deletions Python/Python-ast.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b2eaa75

Please sign in to comment.