summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorSam Gross <colesbury@gmail.com>2024-04-29 19:49:01 (GMT)
committerGitHub <noreply@github.com>2024-04-29 19:49:01 (GMT)
commit79688b5b0ea761183193ffb0859415f3b02fa44d (patch)
treee194d6bfee8402b768741968b3753f526493e02f /Objects
parentee3413c1c70725e133b29bb1d245f569a8f64062 (diff)
downloadcpython-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.c29
-rw-r--r--Objects/typeobject.c2
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);