diff options
author | Sam Gross <colesbury@gmail.com> | 2024-04-29 19:49:01 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-29 19:49:01 (GMT) |
commit | 79688b5b0ea761183193ffb0859415f3b02fa44d (patch) | |
tree | e194d6bfee8402b768741968b3753f526493e02f /Objects | |
parent | ee3413c1c70725e133b29bb1d245f569a8f64062 (diff) | |
download | cpython-79688b5b0ea761183193ffb0859415f3b02fa44d.zip cpython-79688b5b0ea761183193ffb0859415f3b02fa44d.tar.gz cpython-79688b5b0ea761183193ffb0859415f3b02fa44d.tar.bz2 |
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.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/dictobject.c | 29 | ||||
-rw-r--r-- | Objects/typeobject.c | 2 |
2 files changed, 19 insertions, 12 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 43cb235..1f21f70 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -7056,11 +7056,12 @@ set_dict_inline_values(PyObject *obj, PyDictObject *new_dict) } } -void +int _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict) { assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT); assert(_PyObject_InlineValuesConsistencyCheck(obj)); + int err = 0; PyTypeObject *tp = Py_TYPE(obj); if (tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) { PyDictObject *dict = _PyObject_GetManagedDict(obj); @@ -7076,11 +7077,11 @@ _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict) Py_END_CRITICAL_SECTION(); if (dict == NULL) { - return; + return 0; } #else set_dict_inline_values(obj, (PyDictObject *)new_dict); - return; + return 0; #endif } @@ -7089,15 +7090,16 @@ _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict) // We've locked dict, but the actual dict could have changed // since we locked it. dict = _PyObject_ManagedDictPointer(obj)->dict; - - FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict, - (PyDictObject *)Py_XNewRef(new_dict)); - - _PyDict_DetachFromObject(dict, obj); - + err = _PyDict_DetachFromObject(dict, obj); + if (err == 0) { + FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict, + (PyDictObject *)Py_XNewRef(new_dict)); + } Py_END_CRITICAL_SECTION2(); - Py_XDECREF(dict); + if (err == 0) { + Py_XDECREF(dict); + } } else { PyDictObject *dict; @@ -7114,18 +7116,23 @@ _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict) Py_XDECREF(dict); } assert(_PyObject_InlineValuesConsistencyCheck(obj)); + return err; } void PyObject_ClearManagedDict(PyObject *obj) { - _PyObject_SetManagedDict(obj, NULL); + if (_PyObject_SetManagedDict(obj, NULL) < 0) { + PyErr_WriteUnraisable(NULL); + } } int _PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj) { _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(obj); + assert(_PyObject_ManagedDictPointer(obj)->dict == mp); + assert(_PyObject_InlineValuesConsistencyCheck(obj)); if (FT_ATOMIC_LOAD_PTR_RELAXED(mp->ma_values) != _PyObject_InlineValues(obj)) { return 0; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 07e0a5a..50efbb6 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3167,7 +3167,7 @@ subtype_setdict(PyObject *obj, PyObject *value, void *context) } if (Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT) { - _PyObject_SetManagedDict(obj, value); + return _PyObject_SetManagedDict(obj, value); } else { dictptr = _PyObject_ComputedDictPointer(obj); |