mirror of
https://github.com/python/cpython
synced 2024-10-05 08:19:57 +00:00
Issue 3611: in some cases (a __del__ re-raising an exception, when called from inside
an 'except' clause), the exception __context__ would be reset to None. This crases the interpreter if this precisely happens inside PyErr_SetObject. - now the __context__ is properly preserved - in any case, PyErr_SetObject now saves the current exc_value in a local variable, to avoid such crashes in the future. Reviewer: Antoine Pitrou.
This commit is contained in:
parent
4f3c5616cc
commit
db26f7c137
|
@ -324,6 +324,30 @@ def f():
|
|||
|
||||
f()
|
||||
|
||||
def test_3611(self):
|
||||
# A re-raised exception in a __del__ caused the __context__
|
||||
# to be cleared
|
||||
class C:
|
||||
def __del__(self):
|
||||
try:
|
||||
1/0
|
||||
except:
|
||||
raise
|
||||
|
||||
def f():
|
||||
x = C()
|
||||
try:
|
||||
try:
|
||||
x.x
|
||||
except AttributeError:
|
||||
del x
|
||||
raise TypeError
|
||||
except Exception as e:
|
||||
self.assertNotEqual(e.__context__, None)
|
||||
self.assert_(isinstance(e.__context__, AttributeError))
|
||||
|
||||
with support.captured_output("stderr"):
|
||||
f()
|
||||
|
||||
class TestRemovedFunctionality(unittest.TestCase):
|
||||
def test_tuples(self):
|
||||
|
|
|
@ -12,6 +12,9 @@ What's New in Python 3.0 release candidate 1
|
|||
Core and Builtins
|
||||
-----------------
|
||||
|
||||
- Issue #3611: An exception __context__ could be cleared in a complex pattern
|
||||
involving a __del__ method re-raising an exception.
|
||||
|
||||
- Issue #2534: speed up isinstance() and issubclass() by 50-70%, so as to
|
||||
match Python 2.5 speed despite the __instancecheck__ / __subclasscheck__
|
||||
mechanism. In the process, fix a bug where isinstance() and issubclass(),
|
||||
|
|
|
@ -2453,11 +2453,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
|
|||
|
||||
if (b->b_type == EXCEPT_HANDLER) {
|
||||
UNWIND_EXCEPT_HANDLER(b);
|
||||
if (why == WHY_EXCEPTION && !throwflag) {
|
||||
Py_CLEAR(tstate->exc_type);
|
||||
Py_CLEAR(tstate->exc_value);
|
||||
Py_CLEAR(tstate->exc_traceback);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
UNWIND_BLOCK(b);
|
||||
|
|
|
@ -53,6 +53,7 @@ void
|
|||
PyErr_SetObject(PyObject *exception, PyObject *value)
|
||||
{
|
||||
PyThreadState *tstate = PyThreadState_GET();
|
||||
PyObject *exc_value;
|
||||
PyObject *tb = NULL;
|
||||
|
||||
if (exception != NULL &&
|
||||
|
@ -63,8 +64,10 @@ PyErr_SetObject(PyObject *exception, PyObject *value)
|
|||
return;
|
||||
}
|
||||
Py_XINCREF(value);
|
||||
if (tstate->exc_value != NULL && tstate->exc_value != Py_None) {
|
||||
exc_value = tstate->exc_value;
|
||||
if (exc_value != NULL && exc_value != Py_None) {
|
||||
/* Implicit exception chaining */
|
||||
Py_INCREF(exc_value);
|
||||
if (value == NULL || !PyExceptionInstance_Check(value)) {
|
||||
/* We must normalize the value right now */
|
||||
PyObject *args, *fixed_value;
|
||||
|
@ -88,8 +91,8 @@ PyErr_SetObject(PyObject *exception, PyObject *value)
|
|||
This is O(chain length) but context chains are
|
||||
usually very short. Sensitive readers may try
|
||||
to inline the call to PyException_GetContext. */
|
||||
if (tstate->exc_value != value) {
|
||||
PyObject *o = tstate->exc_value, *context;
|
||||
if (exc_value != value) {
|
||||
PyObject *o = exc_value, *context;
|
||||
while ((context = PyException_GetContext(o))) {
|
||||
Py_DECREF(context);
|
||||
if (context == value) {
|
||||
|
@ -98,8 +101,9 @@ PyErr_SetObject(PyObject *exception, PyObject *value)
|
|||
}
|
||||
o = context;
|
||||
}
|
||||
Py_INCREF(tstate->exc_value);
|
||||
PyException_SetContext(value, tstate->exc_value);
|
||||
PyException_SetContext(value, exc_value);
|
||||
} else {
|
||||
Py_DECREF(exc_value);
|
||||
}
|
||||
}
|
||||
if (value != NULL && PyExceptionInstance_Check(value))
|
||||
|
|
Loading…
Reference in a new issue