Skip to content

Commit d533faf

Browse files
committed
gh-143636: fix a crash when calling __replace__ on invalid SimpleNamespace instances
1 parent ce6bae9 commit d533faf

File tree

3 files changed

+24
-0
lines changed

3 files changed

+24
-0
lines changed

Lib/test/test_types.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2167,6 +2167,19 @@ class Spam(types.SimpleNamespace):
21672167
self.assertIs(type(spam2), Spam)
21682168
self.assertEqual(vars(spam2), {'ham': 5, 'eggs': 9})
21692169

2170+
def test_replace_invalid_subtype(self):
2171+
# See https://github.com/python/cpython/issues/143636.
2172+
class NS(types.SimpleNamespace):
2173+
called = False
2174+
def __new__(cls, *args, **kwargs):
2175+
if cls.called:
2176+
return object()
2177+
cls.called = True
2178+
return super().__new__(cls)
2179+
2180+
err = re.escape("expecting a types.SimpleNamespace object, got object")
2181+
self.assertRaisesRegex(TypeError, err, NS().__replace__)
2182+
21702183
def test_fake_namespace_compare(self):
21712184
# Issue #24257: Incorrect use of PyObject_IsInstance() caused
21722185
# 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[] = {
@@ -234,6 +235,14 @@ namespace_replace(PyObject *self, PyObject *args, PyObject *kwargs)
234235
if (!result) {
235236
return NULL;
236237
}
238+
if (!_PyNamespace_Check(result)) {
239+
PyErr_Format(PyExc_TypeError,
240+
"expecting a %s object, got %T",
241+
_PyNamespace_Type.tp_name, result);
242+
Py_DECREF(result);
243+
return NULL;
244+
}
245+
237246
if (PyDict_Update(((_PyNamespaceObject*)result)->ns_dict,
238247
((_PyNamespaceObject*)self)->ns_dict) < 0)
239248
{

0 commit comments

Comments
 (0)