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]

Reply via email to