f.a = 3
self.assertEqual(f.a, 3)
+ def test_rematerialize_object_dict(self):
+ # gh-121860: rematerializing an object's managed dictionary after it
+ # had been deleted caused a crash.
+ class Foo: pass
+ f = Foo()
+ f.__dict__["attr"] = 1
+ del f.__dict__
+
+ # Using a str subclass is a way to trigger the re-materialization
+ class StrSubclass(str): pass
+ self.assertFalse(hasattr(f, StrSubclass("attr")))
+
+ # Changing the __class__ also triggers the re-materialization
+ class Bar: pass
+ f.__class__ = Bar
+ self.assertIsInstance(f, Bar)
+ self.assertEqual(f.__dict__, {})
+
def test_store_attr_type_cache(self):
"""Verifies that the type cache doesn't provide a value which is
inconsistent from the dict."""
{
ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(obj);
- PyDictValues *values = _PyObject_InlineValues(obj);
- PyInterpreterState *interp = _PyInterpreterState_GET();
- PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
OBJECT_STAT_INC(dict_materialized_on_request);
- PyDictObject *dict = make_dict_from_instance_attributes(interp, keys, values);
+
+ PyDictValues *values = _PyObject_InlineValues(obj);
+ PyDictObject *dict;
+ if (values->valid) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
+ dict = make_dict_from_instance_attributes(interp, keys, values);
+ }
+ else {
+ dict = (PyDictObject *)PyDict_New();
+ }
FT_ATOMIC_STORE_PTR_RELEASE(_PyObject_ManagedDictPointer(obj)->dict,
- (PyDictObject *)dict);
+ dict);
return dict;
}