Skip to content

Commit 1749b3c

Browse files
[3.14] gh-143636: fix a crash when calling __replace__ on invalid SimpleNamespace instances (GH-143655) (#145938)
gh-143636: fix a crash when calling ``__replace__`` on invalid `SimpleNamespace` instances (GH-143655) (cherry picked from commit 9796856) Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
1 parent ef75726 commit 1749b3c

File tree

3 files changed

+26
-0
lines changed

3 files changed

+26
-0
lines changed

Lib/test/test_types.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2113,6 +2113,21 @@ class Spam(types.SimpleNamespace):
21132113
self.assertIs(type(spam2), Spam)
21142114
self.assertEqual(vars(spam2), {'ham': 5, 'eggs': 9})
21152115

2116+
def test_replace_invalid_subtype(self):
2117+
# See https://github.com/python/cpython/issues/143636.
2118+
class MyNS(types.SimpleNamespace):
2119+
def __new__(cls, *args, **kwargs):
2120+
if created:
2121+
return 12345
2122+
return super().__new__(cls)
2123+
2124+
created = False
2125+
ns = MyNS()
2126+
created = True
2127+
err = (r"^expect types\.SimpleNamespace type, "
2128+
r"but .+\.MyNS\(\) returned 'int' object")
2129+
self.assertRaisesRegex(TypeError, err, copy.replace, ns)
2130+
21162131
def test_fake_namespace_compare(self):
21172132
# Issue #24257: Incorrect use of PyObject_IsInstance() caused
21182133
# SystemError.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix a crash when calling :class:`SimpleNamespace.__replace__()
2+
<types.SimpleNamespace>` on non-namespace instances. Patch by Bénédikt Tran.

Objects/namespaceobject.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ typedef struct {
1313
} _PyNamespaceObject;
1414

1515
#define _PyNamespace_CAST(op) _Py_CAST(_PyNamespaceObject*, (op))
16+
#define _PyNamespace_Check(op) PyObject_TypeCheck((op), &_PyNamespace_Type)
1617

1718

1819
static PyMemberDef namespace_members[] = {
@@ -230,6 +231,14 @@ namespace_replace(PyObject *self, PyObject *args, PyObject *kwargs)
230231
if (!result) {
231232
return NULL;
232233
}
234+
if (!_PyNamespace_Check(result)) {
235+
PyErr_Format(PyExc_TypeError,
236+
"expect %N type, but %T() returned '%T' object",
237+
&_PyNamespace_Type, self, result);
238+
Py_DECREF(result);
239+
return NULL;
240+
}
241+
233242
if (PyDict_Update(((_PyNamespaceObject*)result)->ns_dict,
234243
((_PyNamespaceObject*)self)->ns_dict) < 0)
235244
{

0 commit comments

Comments
 (0)