8000 [3.13] GH-124547: Clear instance dictionary if memory error occurs du… · python/cpython@80de976 · GitHub
[go: up one dir, main page]

Skip to content

Commit 80de976

Browse files
[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 0e21cc6) Co-authored-by: Mark Shannon <mark@hotpy.org>
1 parent 0a125d9 commit 80de976

File tree

3 files changed

+27
-2
lines changed

3 files changed

+27
-2
lines changed

Lib/test/test_class.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"Test the functionality of Python classes implementing operators."
22

33
import unittest
4+
import test.support
45

56
testmeths = [
67

@@ -919,6 +920,20 @@ class C:
919920
C.a = X()
920921
C.a = X()
921922

923+
def test_detach_materialized_dict_no_memory(self):
924+
import _testcapi
925+
class A:
926+
def __init__(self):
927+
self.a = 1
928+
self.b = 2
929+
a = A()
930+
d = a.__dict__
931+
with test.support.catch_unraisable_exception() as ex:
932+
_testcapi.set_nomemory(0, 1)
933+
del a
934+
self.assertEqual(ex.unraisable.exc_type, MemoryError)
935+
with self.assertRaises(KeyError):
936+
d["a"]
922937

923938
if __name__ == '__main__':
924939
unittest.main()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
When deallocating an object with inline values whose ``__dict__`` is still
2+
live: if memory allocation for the inline values fails, clear the
3+
dictionary. Prevents an interpreter crash.

Objects/dictobject.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3918,13 +3918,13 @@ dict_copy_impl(PyDictObject *self)
39183918
}
39193919

39203920
/* Copies the values, but does not change the reference
3921-
* counts of the objects in the array. */
3921+
* counts of the objects in the array.
3922+
* Return NULL, but does *not* set an exception on failure */
39223923
static PyDictValues *
39233924
copy_values(PyDictValues *values)
39243925
{
39253926
PyDictValues *newvalues = new_values(values->capacity);
39263927
if (newvalues == NULL) {
3927-
PyErr_NoMemory();
39283928
return NULL;
39293929
}
39303930
newvalues->size = values->size;
@@ -7189,6 +7189,13 @@ _PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj)
71897189
PyDictValues *values = copy_values(mp->ma_values);
71907190

71917191
if (values == NULL) {
7192+
/* Out of memory. Clear the dict */
7193+
PyInterpreterState *interp = _PyInterpreterState_GET();
7194+
PyDictKeysObject *oldkeys = mp->ma_keys;
7195+
set_keys(mp, Py_EMPTY_KEYS);
7196+
dictkeys_decref(interp, oldkeys, IS_DICT_SHARED(mp));
7197+
STORE_USED(mp, 0);
7198+
PyErr_NoMemory();
71927199
return -1;
71937200
}
71947201
mp->ma_values = values;

0 commit comments

Comments
 (0)
0