Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit db26f7c

Browse files
committed
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.
1 parent 4f3c561 commit db26f7c

4 files changed

Lines changed: 36 additions & 10 deletions

File tree

Lib/test/test_raise.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,30 @@ def f():
324324

325325
f()
326326

327+
def test_3611(self):
328+
# A re-raised exception in a __del__ caused the __context__
329+
# to be cleared
330+
class C:
331+
def __del__(self):
332+
try:
333+
1/0
334+
except:
335+
raise
336+
337+
def f():
338+
x = C()
339+
try:
340+
try:
341+
x.x
342+
except AttributeError:
343+
del x
344+
raise TypeError
345+
except Exception as e:
346+
self.assertNotEqual(e.__context__, None)
347+
self.assert_(isinstance(e.__context__, AttributeError))
348+
349+
with support.captured_output("stderr"):
350+
f()
327351

328352
class TestRemovedFunctionality(unittest.TestCase):
329353
def test_tuples(self):

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ What's New in Python 3.0 release candidate 1
1212
Core and Builtins
1313
-----------------
1414

15+
- Issue #3611: An exception __context__ could be cleared in a complex pattern
16+
involving a __del__ method re-raising an exception.
17+
1518
- Issue #2534: speed up isinstance() and issubclass() by 50-70%, so as to
1619
match Python 2.5 speed despite the __instancecheck__ / __subclasscheck__
1720
mechanism. In the process, fix a bug where isinstance() and issubclass(),

Python/ceval.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2453,11 +2453,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
24532453

24542454
if (b->b_type == EXCEPT_HANDLER) {
24552455
UNWIND_EXCEPT_HANDLER(b);
2456-
if (why == WHY_EXCEPTION && !throwflag) {
2457-
Py_CLEAR(tstate->exc_type);
2458-
Py_CLEAR(tstate->exc_value);
2459-
Py_CLEAR(tstate->exc_traceback);
2460-
}
24612456
continue;
24622457
}
24632458
UNWIND_BLOCK(b);

Python/errors.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ void
5353
PyErr_SetObject(PyObject *exception, PyObject *value)
5454
{
5555
PyThreadState *tstate = PyThreadState_GET();
56+
PyObject *exc_value;
5657
PyObject *tb = NULL;
5758

5859
if (exception != NULL &&
@@ -63,8 +64,10 @@ PyErr_SetObject(PyObject *exception, PyObject *value)
6364
return;
6465
}
6566
Py_XINCREF(value);
66-
if (tstate->exc_value != NULL && tstate->exc_value != Py_None) {
67+
exc_value = tstate->exc_value;
68+
if (exc_value != NULL && exc_value != Py_None) {
6769
/* Implicit exception chaining */
70+
Py_INCREF(exc_value);
6871
if (value == NULL || !PyExceptionInstance_Check(value)) {
6972
/* We must normalize the value right now */
7073
PyObject *args, *fixed_value;
@@ -88,8 +91,8 @@ PyErr_SetObject(PyObject *exception, PyObject *value)
8891
This is O(chain length) but context chains are
8992
usually very short. Sensitive readers may try
9093
to inline the call to PyException_GetContext. */
91-
if (tstate->exc_value != value) {
92-
PyObject *o = tstate->exc_value, *context;
94+
if (exc_value != value) {
95+
PyObject *o = exc_value, *context;
9396
while ((context = PyException_GetContext(o))) {
9497
Py_DECREF(context);
9598
if (context == value) {
@@ -98,8 +101,9 @@ PyErr_SetObject(PyObject *exception, PyObject *value)
98101
}
99102
o = context;
100103
}
101-
Py_INCREF(tstate->exc_value);
102-
PyException_SetContext(value, tstate->exc_value);
104+
PyException_SetContext(value, exc_value);
105+
} else {
106+
Py_DECREF(exc_value);
103107
}
104108
}
105109
if (value != NULL && PyExceptionInstance_Check(value))

0 commit comments

Comments
 (0)