https://github.com/python/cpython/commit/162b41f57757c1df40eb377985e2e877fb0f0ea3
commit: 162b41f57757c1df40eb377985e2e877fb0f0ea3
branch: main
author: Sam Gross <[email protected]>
committer: colesbury <[email protected]>
date: 2024-07-16T14:58:36-04:00
summary:
gh-121860: Fix crash when materializing managed dict (#121866)
The object's inline values may be marked invalid if the materialized
dict was already initialized and then deleted.
files:
A Misc/NEWS.d/next/Core and
Builtins/2024-07-16-18-23-22.gh-issue-121860.-FTauD.rst
M Lib/test/test_class.py
M Objects/dictobject.c
diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py
index 655d53b8d5bb6a..d1f828b1ed824d 100644
--- a/Lib/test/test_class.py
+++ b/Lib/test/test_class.py
@@ -882,6 +882,24 @@ class Foo:
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."""
diff --git a/Misc/NEWS.d/next/Core and
Builtins/2024-07-16-18-23-22.gh-issue-121860.-FTauD.rst b/Misc/NEWS.d/next/Core
and Builtins/2024-07-16-18-23-22.gh-issue-121860.-FTauD.rst
new file mode 100644
index 00000000000000..a03ee83d6f8ec9
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and
Builtins/2024-07-16-18-23-22.gh-issue-121860.-FTauD.rst
@@ -0,0 +1 @@
+Fix crash when rematerializing a managed dictionary after it was deleted.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 149e552af3a729..ad921fcb113d91 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -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;
}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]