@@ -1234,28 +1234,21 @@ mappingproxy_richcompare(PyObject *self, PyObject *w, int op)
12341234{
12351235 if (op == Py_EQ || op == Py_NE ) {
12361236 mappingproxyobject * v = (mappingproxyobject * )self ;
1237- // Common path optimizations, where we can expose the real mapping:
1238- if (
1239- PyAnyDict_CheckExact (w )
1240- || PyODict_CheckExact (w )
1241- || Py_TYPE (w ) == & PyDictProxy_Type
1242- ) {
1243- return PyObject_RichCompare (v -> mapping , w , op );
1244- }
1245- // We can't expose the `v->mapping` itself, so we create a dict copy:
1246- // it was possible to mutate `v->mapping` in rich-compare methods.
1237+ // We have to guard the mutable `dict` instances, because it can
1238+ // otherwise mutate the type's `__dict__` entries and cause crashes:
12471239 // See gh-152405 on the details.
1248- PyObject * copy = PyDict_New ();
1249- if (copy == NULL ) {
1250- return NULL ;
1251- }
1252- if (PyDict_Update (copy , v -> mapping )) {
1240+ if (PyDict_CheckExact (v -> mapping )) {
1241+ // So, instead we send a copy:
1242+ PyObject * copy = PyDict_Copy (v -> mapping );
1243+ if (copy == NULL ) {
1244+ return NULL ;
1245+ }
1246+ PyObject * res = PyObject_RichCompare (copy , w , op );
12531247 Py_DECREF (copy );
1254- return NULL ;
1248+ return res ;
12551249 }
1256- PyObject * res = PyObject_RichCompare (copy , w , op );
1257- Py_DECREF (copy );
1258- return res ;
1250+ // Otherwise we are free to share the mapping directly:
1251+ return PyObject_RichCompare (v -> mapping , w , op );
12591252 }
12601253 Py_RETURN_NOTIMPLEMENTED ;
12611254}
0 commit comments