[3.13] gh-143636: fix a crash when calling `__replace__ on invalid SimpleNamespace` instances (GH-143655) (#145940)

[3.13] gh-143636: fix a crash when calling ``__replace__`` on invalid `SimpleNamespace` instances (GH-143655)

(cherry picked from commit 97968564b6)
This commit is contained in:
Bénédikt Tran 2026-03-14 12:00:56 +01:00 committed by GitHub
parent e11166cda0
commit cd2e47135c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 28 additions and 0 deletions

View file

@ -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.

View file

@ -0,0 +1,2 @@
Fix a crash when calling :class:`SimpleNamespace.__replace__()
<types.SimpleNamespace>` on non-namespace instances. Patch by Bénédikt Tran.

View 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)
{