[3.14] gh-144169: Fix three crashes in AST objects with non-str kwargs (GH-144178) (#144227)

gh-144169: Fix three crashes in AST objects with non-str kwargs (GH-144178)
(cherry picked from commit 639c1ad4f1ef5c2409a62fa8ed16e6aa3a6f9ab8)

Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
Miss Islington (bot) 2026-01-26 13:14:39 +01:00 committed by GitHub
parent ca6142dae9
commit 7ae9a479cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 36 additions and 6 deletions

View File

@ -1419,6 +1419,13 @@ class CopyTests(unittest.TestCase):
self.assertIs(node.ctx, context)
self.assertRaises(AttributeError, getattr, node, 'unknown')
def test_replace_non_str_kwarg(self):
node = ast.Name(id="x")
errmsg = "got an unexpected keyword argument <object object"
with self.assertRaisesRegex(TypeError, errmsg):
node.__replace__(**{object(): "y"})
class ASTHelpers_Test(unittest.TestCase):
maxDiff = None
@ -3281,6 +3288,27 @@ class ASTConstructorTests(unittest.TestCase):
self.assertIs(obj.a, None)
self.assertEqual(obj.b, [])
def test_non_str_kwarg(self):
warn_msg = "got an unexpected keyword argument <object object"
with (
self.assertRaises(TypeError),
self.assertWarnsRegex(DeprecationWarning, warn_msg),
):
ast.Name(**{object(): 'y'})
class FakeStr:
def __init__(self, value):
self.value = value
def __hash__(self):
return hash(self.value)
def __eq__(self, other):
return isinstance(other, str) and self.value == other
with self.assertRaisesRegex(TypeError, "got multiple values for argument"):
ast.Name("x", **{FakeStr('id'): 'y'})
@support.cpython_only
class ModuleStateTests(unittest.TestCase):

View File

@ -0,0 +1,2 @@
Fix three crashes when non-string keyword arguments are supplied to objects
in the :mod:`ast` module.

View File

@ -942,7 +942,7 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
}
if (p == 0) {
PyErr_Format(PyExc_TypeError,
"%.400s got multiple values for argument '%U'",
"%.400s got multiple values for argument %R",
Py_TYPE(self)->tp_name, key);
res = -1;
goto cleanup;
@ -965,7 +965,7 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
else if (contains == 0) {
if (PyErr_WarnFormat(
PyExc_DeprecationWarning, 1,
"%.400s.__init__ got an unexpected keyword argument '%U'. "
"%.400s.__init__ got an unexpected keyword argument %R. "
"Support for arbitrary keyword arguments is deprecated "
"and will be removed in Python 3.15.",
Py_TYPE(self)->tp_name, key
@ -1207,7 +1207,7 @@ ast_type_replace_check(PyObject *self,
if (rc == 0) {
PyErr_Format(PyExc_TypeError,
"%.400s.__replace__ got an unexpected keyword "
"argument '%U'.", Py_TYPE(self)->tp_name, key);
"argument %R.", Py_TYPE(self)->tp_name, key);
Py_DECREF(expecting);
return -1;
}

6
Python/Python-ast.c generated
View File

@ -5226,7 +5226,7 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
}
if (p == 0) {
PyErr_Format(PyExc_TypeError,
"%.400s got multiple values for argument '%U'",
"%.400s got multiple values for argument %R",
Py_TYPE(self)->tp_name, key);
res = -1;
goto cleanup;
@ -5249,7 +5249,7 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw)
else if (contains == 0) {
if (PyErr_WarnFormat(
PyExc_DeprecationWarning, 1,
"%.400s.__init__ got an unexpected keyword argument '%U'. "
"%.400s.__init__ got an unexpected keyword argument %R. "
"Support for arbitrary keyword arguments is deprecated "
"and will be removed in Python 3.15.",
Py_TYPE(self)->tp_name, key
@ -5491,7 +5491,7 @@ ast_type_replace_check(PyObject *self,
if (rc == 0) {
PyErr_Format(PyExc_TypeError,
"%.400s.__replace__ got an unexpected keyword "
"argument '%U'.", Py_TYPE(self)->tp_name, key);
"argument %R.", Py_TYPE(self)->tp_name, key);
Py_DECREF(expecting);
return -1;
}