8000 gh-118331: Handle errors in _PyObject_SetManagedDict (#118334) · python/cpython@79688b5 · GitHub
[go: up one dir, main page]

Skip to content

Commit 79688b5

Browse files
authored
gh-118331: Handle errors in _PyObject_SetManagedDict (#118334)
When detaching a dict, the `copy_values` call may fail due to out-of-memory errors. This can be triggered by test_no_memory in test_repl.
1 parent ee3413c commit 79688b5

File tree

3 files changed

+20
-13
lines changed

3 files changed

+20
-13
lines changed

Include/cpython/object.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ do { \
493493
PyAPI_FUNC(void *) PyObject_GetItemData(PyObject *obj);
494494

495495
PyAPI_FUNC(int) PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg);
496-
PyAPI_FUNC(void) _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict);
496+
PyAPI_FUNC(int) _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict);
497497
PyAPI_FUNC(void) PyObject_ClearManagedDict(PyObject *obj);
498498

499499
#define TYPE_MAX_WATCHERS 8

Objects/dictobject.c

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7056,11 +7056,12 @@ set_dict_inline_values(PyObject *obj, PyDictObject *new_dict)
70567056
}
70577057
}
70587058

7059-
void
7059+
int
70607060
_PyObject_SetManagedDict(PyObject * 10000 obj, PyObject *new_dict)
70617061
{
70627062
assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
70637063
assert(_PyObject_InlineValuesConsistencyCheck(obj));
7064+
int err = 0;
70647065
PyTypeObject *tp = Py_TYPE(obj);
70657066
if (tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
70667067
PyDictObject *dict = _PyObject_GetManagedDict(obj);
@@ -7076,11 +7077,11 @@ _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
70767077
Py_END_CRITICAL_SECTION();
70777078

70787079
if (dict == NULL) {
7079-
return;
7080+
return 0;
70807081
}
70817082
#else
70827083
set_dict_inline_values(obj, (PyDictObject *)new_dict);
7083-
return;
7084+
return 0;
70847085
#endif
70857086
}
70867087

@@ -7089,15 +7090,16 @@ _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
70897090
// We've locked dict, but the actual dict could have changed
70907091
// since we locked it.
70917092
dict = _PyObject_ManagedDictPointer(obj)->dict;
7092-
7093-
FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict,
7094-
(PyDictObject *)Py_XNewRef(new_dict));
7095-
7096-
_PyDict_DetachFromObject(dict, obj);
7097-
7093+
err = _PyDict_DetachFromObject(dict, obj);
7094+
if (err == 0) {
7095+
FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict,
7096+
(PyDictObject *)Py_XNewRef(new_dict));
7097+
}
70987098
Py_END_CRITICAL_SECTION2();
70997099

7100-
Py_XDECREF(dict);
7100+
if (err == 0) {
7101+
Py_XDECREF(dict);
7102+
}
71017103
}
71027104
else {
71037105
PyDictObject *dict;
@@ -7114,18 +7116,23 @@ _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
71147116
Py_XDECREF(dict);
71157117
}
71167118
assert(_PyObject_InlineValuesConsistencyCheck(obj));
7119+
return err;
71177120
}
71187121

71197122
void
71207123
PyObject_ClearManagedDict(PyObject *obj)
71217124
{
7122-
_PyObject_SetManagedDict(obj, NULL);
7125+
if (_PyObject_SetManagedDict(obj, NULL) < 0) {
7126+
PyErr_WriteUnraisable(NULL);
7127+
}
71237128
}
71247129

71257130
int
71267131
_PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj)
71277132
{
71287133
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(obj);
7134+
assert(_PyObject_ManagedDictPointer(obj)->dict == mp);
7135+
assert(_PyObject_InlineValuesConsistencyCheck(obj));
71297136

71307137
if (FT_ATOMIC_LOAD_PTR_RELAXED(mp->ma_values) != _PyObject_InlineValues(obj)) {
71317138
return 0;

Objects/typeobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3167,7 +3167,7 @@ subtype_setdict(PyObject *obj, PyObject *value, void *context)
31673167
}
31683168

31693169
if (Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
3170-
_PyObject_SetManagedDict(obj, value);
3170+
return _PyObject_SetManagedDict(obj, value);
31713171
}
31723172
else {
31733173
dictptr = _PyObject_ComputedDictPointer(obj);

0 commit comments

Comments
 (0)
0