diff options
author | Fred Drake <fdrake@acm.org> | 2001-12-10 23:44:54 (GMT) |
---|---|---|
committer | Fred Drake <fdrake@acm.org> | 2001-12-10 23:44:54 (GMT) |
commit | ef8ebd1e74cc8f91d2f0a6e5a8a99c8bd6b125b0 (patch) | |
tree | 5e371f268d467523b6cbd945eb7adc65494eaedb | |
parent | 65760b2173da008814ac0d207376e12527c5b3b2 (diff) | |
download | cpython-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.c | 44 |
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); } } |