https://github.com/python/cpython/commit/80de9766f7b802f7dad0857614f46496a3196186
commit: 80de9766f7b802f7dad0857614f46496a3196186
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: Yhg1s <[email protected]>
date: 2024-09-27T15:23:39-07:00
summary:

[3.13] GH-124547: Clear instance dictionary if memory error occurs during 
object dealloc (GH-124627) (#124714)

GH-124547: Clear instance dictionary if memory error occurs during object 
dealloc (GH-124627)
(cherry picked from commit 0e21cc6cf820679439d72e3ebd06227ee2a085f9)

Co-authored-by: Mark Shannon <[email protected]>

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-12-19-13.gh-issue-124547.P_SHfU.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 d1f828b1ed824d..6002ea757f1f33 100644
--- a/Lib/test/test_class.py
+++ b/Lib/test/test_class.py
@@ -1,6 +1,7 @@
 "Test the functionality of Python classes implementing operators."
 
 import unittest
+import test.support
 
 testmeths = [
 
@@ -919,6 +920,20 @@ class C:
         C.a = X()
         C.a = X()
 
+    def test_detach_materialized_dict_no_memory(self):
+        import _testcapi
+        class A:
+            def __init__(self):
+                self.a = 1
+                self.b = 2
+        a = A()
+        d = a.__dict__
+        with test.support.catch_unraisable_exception() as ex:
+            _testcapi.set_nomemory(0, 1)
+            del a
+            self.assertEqual(ex.unraisable.exc_type, MemoryError)
+        with self.assertRaises(KeyError):
+            d["a"]
 
 if __name__ == '__main__':
     unittest.main()
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-12-19-13.gh-issue-124547.P_SHfU.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-12-19-13.gh-issue-124547.P_SHfU.rst
new file mode 100644
index 00000000000000..1005c651849f45
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-26-12-19-13.gh-issue-124547.P_SHfU.rst
@@ -0,0 +1,3 @@
+When deallocating an object with inline values whose ``__dict__`` is still
+live: if memory allocation for the inline values fails, clear the
+dictionary. Prevents an interpreter crash.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 6586e0c5c27de1..7f7fd836c01509 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -3918,13 +3918,13 @@ dict_copy_impl(PyDictObject *self)
 }
 
 /* Copies the values, but does not change the reference
- * counts of the objects in the array. */
+ * counts of the objects in the array.
+ * Return NULL, but does *not* set an exception on failure  */
 static PyDictValues *
 copy_values(PyDictValues *values)
 {
     PyDictValues *newvalues = new_values(values->capacity);
     if (newvalues == NULL) {
-        PyErr_NoMemory();
         return NULL;
     }
     newvalues->size = values->size;
@@ -7189,6 +7189,13 @@ _PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj)
     PyDictValues *values = copy_values(mp->ma_values);
 
     if (values == NULL) {
+        /* Out of memory. Clear the dict */
+        PyInterpreterState *interp = _PyInterpreterState_GET();
+        PyDictKeysObject *oldkeys = mp->ma_keys;
+        set_keys(mp, Py_EMPTY_KEYS);
+        dictkeys_decref(interp, oldkeys, IS_DICT_SHARED(mp));
+        STORE_USED(mp, 0);
+        PyErr_NoMemory();
         return -1;
     }
     mp->ma_values = values;

_______________________________________________
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