]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-144169: Fix three crashes in AST objects with non-str kwargs (#144178)
authorJelle Zijlstra <jelle.zijlstra@gmail.com>
Mon, 26 Jan 2026 01:28:58 +0000 (17:28 -0800)
committerGitHub <noreply@github.com>
Mon, 26 Jan 2026 01:28:58 +0000 (17:28 -0800)
Co-authored-by: Victor Stinner <vstinner@python.org>
Lib/test/test_ast/test_ast.py
Misc/NEWS.d/next/Library/2026-01-23-06-43-21.gh-issue-144169.LFy9yi.rst [new file with mode: 0644]
Parser/asdl_c.py
Python/Python-ast.c

index 3917407fb37d9e1fe04750ff3541daa3cc49eaab..c5f42cb7888c085685f76768e9e50ba15a407913 100644 (file)
@@ -1443,6 +1443,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
 
@@ -3304,6 +3311,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):
diff --git a/Misc/NEWS.d/next/Library/2026-01-23-06-43-21.gh-issue-144169.LFy9yi.rst b/Misc/NEWS.d/next/Library/2026-01-23-06-43-21.gh-issue-144169.LFy9yi.rst
new file mode 100644 (file)
index 0000000..e2ef3d7
--- /dev/null
@@ -0,0 +1,2 @@
+Fix three crashes when non-string keyword arguments are supplied to objects
+in the :mod:`ast` module.
index 3e252cbc4883d194a6ee6810f9ae6dca8bb48616..5ad20d49fa4b3100d954b72deee445c01c8d9ced 100755 (executable)
@@ -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;
             }
index 79608dee9bfac224b4ef98d92732486eb4ae4f68..1cc88dc179e120d9cdfce193595ded579c758a0b 100644 (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;
             }