summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFred Drake <fdrake@acm.org>2001-12-10 23:44:54 (GMT)
committerFred Drake <fdrake@acm.org>2001-12-10 23:44:54 (GMT)
commitef8ebd1e74cc8f91d2f0a6e5a8a99c8bd6b125b0 (patch)
tree5e371f268d467523b6cbd945eb7adc65494eaedb
parent65760b2173da008814ac0d207376e12527c5b3b2 (diff)
downloadcpython-ef8ebd1e74cc8f91d2f0a6e5a8a99c8bd6b125b0.zip
cpython-ef8ebd1e74cc8f91d2f0a6e5a8a99c8bd6b125b0.tar.gz
cpython-ef8ebd1e74cc8f91d2f0a6e5a8a99c8bd6b125b0.tar.bz2
Make sure that when we invoke callback functions associated with weak
references, we do not allow any outstanding exceptions "leak" into the callback's execution state. This closes SF bug #478534.
-rw-r--r--Objects/weakrefobject.c44
1 files changed, 24 insertions, 20 deletions
diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c
index fb58ff4..9a94fd4 100644
--- a/Objects/weakrefobject.c
+++ b/Objects/weakrefobject.c
@@ -655,9 +655,18 @@ PyWeakref_GetObject(PyObject *ref)
}
-/* This is the implementation of the PyObject_ClearWeakRefs() function; it
- * is installed in the init_weakref() function. It is called by the
- * tp_dealloc handler to clear weak references.
+static void
+handle_callback(PyWeakReference *ref, PyObject *callback)
+{
+ PyObject *cbresult = PyObject_CallFunction(callback, "O", ref);
+
+ if (cbresult == NULL)
+ PyErr_WriteUnraisable(callback);
+ else
+ Py_DECREF(cbresult);
+}
+
+/* This function is called by the tp_dealloc handler to clear weak references.
*
* This iterates through the weak references for 'object' and calls callbacks
* for those references which have one. It returns when all callbacks have
@@ -682,25 +691,23 @@ PyObject_ClearWeakRefs(PyObject *object)
clear_weakref(*list);
}
if (*list != NULL) {
- int count = _PyWeakref_GetWeakrefCount(*list);
+ PyWeakReference *current = *list;
+ int count = _PyWeakref_GetWeakrefCount(current);
+ int restore_error = PyErr_Occurred() ? 1 : 0;
+ PyObject *err_type, *err_value, *err_tb;
+ if (restore_error)
+ PyErr_Fetch(&err_type, &err_value, &err_tb);
if (count == 1) {
- PyWeakReference *current = *list;
PyObject *callback = current->wr_callback;
- PyObject *cbresult;
- Py_INCREF(callback);
+ current->wr_callback = NULL;
clear_weakref(current);
- cbresult = PyObject_CallFunction(callback, "O", current);
- if (cbresult == NULL)
- PyErr_WriteUnraisable(callback);
- else
- Py_DECREF(cbresult);
+ handle_callback(current, callback);
Py_DECREF(callback);
}
else {
PyObject *tuple = PyTuple_New(count * 2);
- PyWeakReference *current = *list;
int i = 0;
for (i = 0; i < count; ++i) {
@@ -710,21 +717,18 @@ PyObject_ClearWeakRefs(PyObject *object)
PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
current->wr_callback = NULL;
- next = current->wr_next;
clear_weakref(current);
current = next;
}
for (i = 0; i < count; ++i) {
PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
- PyObject *cbresult = PyObject_CallFunction(callback, "O",
- current);
- if (cbresult == NULL)
- PyErr_WriteUnraisable(callback);
- else
- Py_DECREF(cbresult);
+
+ handle_callback((PyWeakReference *)current, callback);
}
Py_DECREF(tuple);
}
+ if (restore_error)
+ PyErr_Restore(err_type, err_value, err_tb);
}
}