]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-143636: fix a crash when calling ``__replace__`` on invalid `SimpleNamespac...
authorBénédikt Tran <10796600+picnixz@users.noreply.github.com>
Sat, 14 Mar 2026 11:00:56 +0000 (12:00 +0100)
committerGitHub <noreply@github.com>
Sat, 14 Mar 2026 11:00:56 +0000 (11:00 +0000)
[3.13] gh-143636: fix a crash when calling ``__replace__`` on invalid `SimpleNamespace` instances (GH-143655)

(cherry picked from commit 97968564b61965f2a65a9be8af731cee6913eb7a)

Lib/test/test_types.py
Misc/NEWS.d/next/Core_and_Builtins/2026-01-10-12-59-58.gh-issue-143636.dzr26e.rst [new file with mode: 0644]
Objects/namespaceobject.c

index d7c229151b3ab4440683e46313a73a1dc249f2d2..f7c701e5f3c732ae076ba138959d3f19dc73344d 100644 (file)
@@ -2037,6 +2037,21 @@ class SimpleNamespaceTests(unittest.TestCase):
         self.assertIs(type(spam2), Spam)
         self.assertEqual(vars(spam2), {'ham': 5, 'eggs': 9})
 
+    def test_replace_invalid_subtype(self):
+        # See https://github.com/python/cpython/issues/143636.
+        class MyNS(types.SimpleNamespace):
+            def __new__(cls, *args, **kwargs):
+                if created:
+                    return 12345
+                return super().__new__(cls)
+
+        created = False
+        ns = MyNS()
+        created = True
+        err = (r"^expect types\.SimpleNamespace type, "
+               r"but .+\.MyNS\(\) returned 'int' object")
+        self.assertRaisesRegex(TypeError, err, copy.replace, ns)
+
     def test_fake_namespace_compare(self):
         # Issue #24257: Incorrect use of PyObject_IsInstance() caused
         # SystemError.
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-10-12-59-58.gh-issue-143636.dzr26e.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-10-12-59-58.gh-issue-143636.dzr26e.rst
new file mode 100644 (file)
index 0000000..4d5249f
--- /dev/null
@@ -0,0 +1,2 @@
+Fix a crash when calling :class:`SimpleNamespace.__replace__()
+<types.SimpleNamespace>` on non-namespace instances. Patch by Bénédikt Tran.
index 7eeac11b5538106a38256763682ea1088f7366fe..4b1d625fc782328fa0414c378659ca94f6365495 100644 (file)
@@ -12,6 +12,9 @@ typedef struct {
     PyObject *ns_dict;
 } _PyNamespaceObject;
 
+#define _PyNamespace_CAST(op) _Py_CAST(_PyNamespaceObject*, (op))
+#define _PyNamespace_Check(op) PyObject_TypeCheck((op), &_PyNamespace_Type)
+
 
 static PyMemberDef namespace_members[] = {
     {"__dict__", _Py_T_OBJECT, offsetof(_PyNamespaceObject, ns_dict), Py_READONLY},
@@ -223,6 +226,14 @@ namespace_replace(PyObject *self, PyObject *args, PyObject *kwargs)
     if (!result) {
         return NULL;
     }
+    if (!_PyNamespace_Check(result)) {
+        PyErr_Format(PyExc_TypeError,
+                     "expect %N type, but %T() returned '%T' object",
+                     &_PyNamespace_Type, self, result);
+        Py_DECREF(result);
+        return NULL;
+    }
+
     if (PyDict_Update(((_PyNamespaceObject*)result)->ns_dict,
                       ((_PyNamespaceObject*)self)->ns_dict) < 0)
     {