mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
ee3413c1c7
commit
79688b5b0e
|
@ -493,7 +493,7 @@ do { \
|
||||||
PyAPI_FUNC(void *) PyObject_GetItemData(PyObject *obj);
|
PyAPI_FUNC(void *) PyObject_GetItemData(PyObject *obj);
|
||||||
|
|
||||||
PyAPI_FUNC(int) PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg);
|
PyAPI_FUNC(int) PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg);
|
||||||
PyAPI_FUNC(void) _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict);
|
PyAPI_FUNC(int) _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict);
|
||||||
PyAPI_FUNC(void) PyObject_ClearManagedDict(PyObject *obj);
|
PyAPI_FUNC(void) PyObject_ClearManagedDict(PyObject *obj);
|
||||||
|
|
||||||
#define TYPE_MAX_WATCHERS 8
|
#define TYPE_MAX_WATCHERS 8
|
||||||
|
|
|
@ -7056,11 +7056,12 @@ set_dict_inline_values(PyObject *obj, PyDictObject *new_dict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
_PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
|
_PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
|
||||||
{
|
{
|
||||||
assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
||||||
assert(_PyObject_InlineValuesConsistencyCheck(obj));
|
assert(_PyObject_InlineValuesConsistencyCheck(obj));
|
||||||
|
int err = 0;
|
||||||
PyTypeObject *tp = Py_TYPE(obj);
|
PyTypeObject *tp = Py_TYPE(obj);
|
||||||
if (tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
|
if (tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
|
||||||
PyDictObject *dict = _PyObject_GetManagedDict(obj);
|
PyDictObject *dict = _PyObject_GetManagedDict(obj);
|
||||||
|
@ -7076,11 +7077,11 @@ _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
|
||||||
Py_END_CRITICAL_SECTION();
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
if (dict == NULL) {
|
if (dict == NULL) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
set_dict_inline_values(obj, (PyDictObject *)new_dict);
|
set_dict_inline_values(obj, (PyDictObject *)new_dict);
|
||||||
return;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7089,16 +7090,17 @@ _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
|
||||||
// We've locked dict, but the actual dict could have changed
|
// We've locked dict, but the actual dict could have changed
|
||||||
// since we locked it.
|
// since we locked it.
|
||||||
dict = _PyObject_ManagedDictPointer(obj)->dict;
|
dict = _PyObject_ManagedDictPointer(obj)->dict;
|
||||||
|
err = _PyDict_DetachFromObject(dict, obj);
|
||||||
|
if (err == 0) {
|
||||||
FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict,
|
FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict,
|
||||||
(PyDictObject *)Py_XNewRef(new_dict));
|
(PyDictObject *)Py_XNewRef(new_dict));
|
||||||
|
}
|
||||||
_PyDict_DetachFromObject(dict, obj);
|
|
||||||
|
|
||||||
Py_END_CRITICAL_SECTION2();
|
Py_END_CRITICAL_SECTION2();
|
||||||
|
|
||||||
|
if (err == 0) {
|
||||||
Py_XDECREF(dict);
|
Py_XDECREF(dict);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
PyDictObject *dict;
|
PyDictObject *dict;
|
||||||
|
|
||||||
|
@ -7114,18 +7116,23 @@ _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict)
|
||||||
Py_XDECREF(dict);
|
Py_XDECREF(dict);
|
||||||
}
|
}
|
||||||
assert(_PyObject_InlineValuesConsistencyCheck(obj));
|
assert(_PyObject_InlineValuesConsistencyCheck(obj));
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PyObject_ClearManagedDict(PyObject *obj)
|
PyObject_ClearManagedDict(PyObject *obj)
|
||||||
{
|
{
|
||||||
_PyObject_SetManagedDict(obj, NULL);
|
if (_PyObject_SetManagedDict(obj, NULL) < 0) {
|
||||||
|
PyErr_WriteUnraisable(NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj)
|
_PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj)
|
||||||
{
|
{
|
||||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(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)) {
|
if (FT_ATOMIC_LOAD_PTR_RELAXED(mp->ma_values) != _PyObject_InlineValues(obj)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -3167,7 +3167,7 @@ subtype_setdict(PyObject *obj, PyObject *value, void *context)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
if (Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
|
||||||
_PyObject_SetManagedDict(obj, value);
|
return _PyObject_SetManagedDict(obj, value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dictptr = _PyObject_ComputedDictPointer(obj);
|
dictptr = _PyObject_ComputedDictPointer(obj);
|
||||||
|
|
Loading…
Reference in New Issue