https://github.com/python/cpython/commit/0e21cc6cf820679439d72e3ebd06227ee2a085f9
commit: 0e21cc6cf820679439d72e3ebd06227ee2a085f9
branch: main
author: Mark Shannon <[email protected]>
committer: markshannon <[email protected]>
date: 2024-09-27T14:51:01-07:00
summary:
GH-124547: Clear instance dictionary if memory error occurs during object
dealloc (GH-124627)
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 902f788edc22f0..d2b6a23cc3c10d 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 = [
@@ -932,6 +933,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 f38ab1b2865e99..e50cf8bf1787f9 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -3930,13 +3930,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;
@@ -7216,6 +7216,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]