From 632f50d55e4c88061363b43334be66794d443dad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sat, 14 Mar 2026 10:58:15 +0100 Subject: [PATCH 1/2] [3.13] gh-143636: fix a crash when calling ``__replace__`` on invalid `SimpleNamespace` instances (GH-143655) (cherry picked from commit 97968564b61965f2a65a9be8af731cee6913eb7a) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_types.py | 15 +++++++++++++++ ...2026-01-10-12-59-58.gh-issue-143636.dzr26e.rst | 2 ++ Objects/namespaceobject.c | 10 ++++++++++ 3 files changed, 27 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-10-12-59-58.gh-issue-143636.dzr26e.rst diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index d7c229151b3ab4..f7c701e5f3c732 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -2037,6 +2037,21 @@ class Spam(types.SimpleNamespace): 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 index 00000000000000..4d5249ffe3a206 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-10-12-59-58.gh-issue-143636.dzr26e.rst @@ -0,0 +1,2 @@ +Fix a crash when calling :class:`SimpleNamespace.__replace__() +` on non-namespace instances. Patch by Bénédikt Tran. diff --git a/Objects/namespaceobject.c b/Objects/namespaceobject.c index 7eeac11b553810..c5622e67f2b1f2 100644 --- a/Objects/namespaceobject.c +++ b/Objects/namespaceobject.c @@ -12,6 +12,8 @@ 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 +225,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) { From 8f8cd624a06f901cc40b759c3161bae3e99c4b57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sat, 14 Mar 2026 11:25:16 +0100 Subject: [PATCH 2/2] Update Objects/namespaceobject.c --- Objects/namespaceobject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Objects/namespaceobject.c b/Objects/namespaceobject.c index c5622e67f2b1f2..4b1d625fc78232 100644 --- a/Objects/namespaceobject.c +++ b/Objects/namespaceobject.c @@ -15,6 +15,7 @@ typedef struct { #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}, {NULL}