[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 162b41f577)

Co-authored-by: Sam Gross <colesbury@gmail.com>
This commit is contained in:
Miss Islington (bot) 2024-07-16 21:26:01 +02:00 committed by GitHub
parent d24ec8a47c
commit 6613029084
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 31 additions and 5 deletions

View File

@ -882,6 +882,24 @@ class TestInlineValues(unittest.TestCase):
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."""

View File

@ -0,0 +1 @@
Fix crash when rematerializing a managed dictionary after it was deleted.

View File

@ -6683,13 +6683,20 @@ _PyObject_MaterializeManagedDict_LockHeld(PyObject *obj)
{
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;
}