GH-124547: Clear instance dictionary if memory error occurs during object dealloc (GH-124627)

This commit is contained in:
Mark Shannon 2024-09-27 14:51:01 -07:00 committed by GitHub
parent 2357d5ba48
commit 0e21cc6cf8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 27 additions and 2 deletions

View File

@ -1,6 +1,7 @@
"Test the functionality of Python classes implementing operators."
import unittest
import test.support
testmeths = [
@ -932,6 +933,20 @@ class TestInlineValues(unittest.TestCase):
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()

View File

@ -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.

View File

@ -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;