diff --git a/Lib/test/test_ast/test_ast.py b/Lib/test/test_ast/test_ast.py index 92ef9c633e1d47e..a70b970cae5ea92 100644 --- a/Lib/test/test_ast/test_ast.py +++ b/Lib/test/test_ast/test_ast.py @@ -1165,6 +1165,20 @@ def test_repr_large_input_crash(self): r"Exceeds the limit \(\d+ digits\)"): repr(ast.Constant(value=eval(source))) + def test_repr_missing_fields_crash(self): + class FieldsMissingMeta(type): + def __getattribute__(self, name): + if name == "_fields": + raise AttributeError + return super().__getattribute__(name) + + class FieldsMissing(ast.AST, metaclass=FieldsMissingMeta): + def __init__(self): + pass + + node = FieldsMissing() + self.assertEqual(repr(node), "FieldsMissing()") + def test_tstring(self): # Test AST structure for simple t-string tree = ast.parse('t"Hello"') diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-11-11-34-02.gh-issue-156909.2Hgszb.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-11-11-34-02.gh-issue-156909.2Hgszb.rst new file mode 100644 index 000000000000000..716753b391a4d45 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-11-11-34-02.gh-issue-156909.2Hgszb.rst @@ -0,0 +1,2 @@ +Fix a crash in :func:`repr` of AST nodes when the AST node's type lacks the +``_fields`` attribute. Patched by Shamil Abdulaev. diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index b2581e48810b893..8f22c1ff7b838f9 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -1498,6 +1498,11 @@ def visitModule(self, mod): return NULL; } + if (fields == NULL) { + Py_ReprLeave((PyObject *)self); + return PyUnicode_FromFormat("%s()", Py_TYPE(self)->tp_name); + } + Py_ssize_t numfields = PySequence_Size(fields); if (numfields < 0) { Py_ReprLeave((PyObject *)self); diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 383384fc1706b47..f9a1bdd960eeb10 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -5810,6 +5810,11 @@ ast_repr_max_depth(AST_object *self, int depth) return NULL; } + if (fields == NULL) { + Py_ReprLeave((PyObject *)self); + return PyUnicode_FromFormat("%s()", Py_TYPE(self)->tp_name); + } + Py_ssize_t numfields = PySequence_Size(fields); if (numfields < 0) { Py_ReprLeave((PyObject *)self);