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).
This commit is contained in:
sobolevn 2024-10-29 18:42:48 +03:00 committed by GitHub
parent 0bbbe15f56
commit b2eaa75b17
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 34 additions and 20 deletions

View File

@ -84,6 +84,23 @@ class AST_Tests(unittest.TestCase):
# "ast.AST constructor takes 0 positional arguments" # "ast.AST constructor takes 0 positional arguments"
ast.AST(2) 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): def test_AST_garbage_collection(self):
class X: class X:
pass pass

View File

@ -0,0 +1 @@
Fix a crash in :mod:`ast` when the :attr:`ast.AST._fields` attribute is deleted.

View File

@ -884,19 +884,17 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
Py_ssize_t i, numfields = 0; Py_ssize_t i, numfields = 0;
int res = -1; int res = -1;
PyObject *key, *value, *fields, *attributes = NULL, *remaining_fields = NULL; 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; goto cleanup;
} }
if (fields) {
numfields = PySequence_Size(fields); numfields = PySequence_Size(fields);
if (numfields == -1) { if (numfields == -1) {
goto cleanup; goto cleanup;
}
remaining_fields = PySet_New(fields);
}
else {
remaining_fields = PySet_New(NULL);
} }
remaining_fields = PySet_New(fields);
if (remaining_fields == NULL) { if (remaining_fields == NULL) {
goto cleanup; goto cleanup;
} }

18
Python/Python-ast.c generated
View File

@ -5083,19 +5083,17 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
Py_ssize_t i, numfields = 0; Py_ssize_t i, numfields = 0;
int res = -1; int res = -1;
PyObject *key, *value, *fields, *attributes = NULL, *remaining_fields = NULL; 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; goto cleanup;
} }
if (fields) {
numfields = PySequence_Size(fields); numfields = PySequence_Size(fields);
if (numfields == -1) { if (numfields == -1) {
goto cleanup; goto cleanup;
}
remaining_fields = PySet_New(fields);
}
else {
remaining_fields = PySet_New(NULL);
} }
remaining_fields = PySet_New(fields);
if (remaining_fields == NULL) { if (remaining_fields == NULL) {
goto cleanup; goto cleanup;
} }