Skip to content

Commit 6613029

Browse files
[3.13] gh-121860: Fix crash when materializing managed dict (GH-121866) (#121867)
The object's inline values may be marked invalid if the materialized dict was already initialized and then deleted. (cherry picked from commit 162b41f) Co-authored-by: Sam Gross <[email protected]>
1 parent d24ec8a commit 6613029

File tree

3 files changed

+31
-5
lines changed

3 files changed

+31
-5
lines changed

Lib/test/test_class.py

+18
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,24 @@ class Foo:
882882
f.a = 3
883883
self.assertEqual(f.a, 3)
884884

885+
def test_rematerialize_object_dict(self):
886+
# gh-121860: rematerializing an object's managed dictionary after it
887+
# had been deleted caused a crash.
888+
class Foo: pass
889+
f = Foo()
890+
f.__dict__["attr"] = 1
891+
del f.__dict__
892+
893+
# Using a str subclass is a way to trigger the re-materialization
894+
class StrSubclass(str): pass
895+
self.assertFalse(hasattr(f, StrSubclass("attr")))
896+
897+
# Changing the __class__ also triggers the re-materialization
898+
class Bar: pass
899+
f.__class__ = Bar
900+
self.assertIsInstance(f, Bar)
901+
self.assertEqual(f.__dict__, {})
902+
885903
def test_store_attr_type_cache(self):
886904
"""Verifies that the type cache doesn't provide a value which is
887905
inconsistent from the dict."""
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix crash when rematerializing a managed dictionary after it was deleted.

Objects/dictobject.c

+12-5
Original file line numberDiff line numberDiff line change
@@ -6683,13 +6683,20 @@ _PyObject_MaterializeManagedDict_LockHeld(PyObject *obj)
66836683
{
66846684
ASSERT_WORLD_STOPPED_OR_OBJ_LOCKED(obj);
66856685

6686-
PyDictValues *values = _PyObject_InlineValues(obj);
6687-
PyInterpreterState *interp = _PyInterpreterState_GET();
6688-
PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
66896686
OBJECT_STAT_INC(dict_materialized_on_request);
6690-
PyDictObject *dict = make_dict_from_instance_attributes(interp, keys, values);
6687+
6688+
PyDictValues *values = _PyObject_InlineValues(obj);
6689+
PyDictObject *dict;
6690+
if (values->valid) {
6691+
PyInterpreterState *interp = _PyInterpreterState_GET();
6692+
PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
6693+
dict = make_dict_from_instance_attributes(interp, keys, values);
6694+
}
6695+
else {
6696+
dict = (PyDictObject *)PyDict_New();
6697+
}
66916698
FT_ATOMIC_STORE_PTR_RELEASE(_PyObject_ManagedDictPointer(obj)->dict,
6692-
(PyDictObject *)dict);
6699+
dict);
66936700
return dict;
66946701
}
66956702

0 commit comments

Comments
 (0)