comparison Python/errors.c @ 48887:c562c8dae49a

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.
author Amaury Forgeot d'Arc <amauryfa@gmail.com>
date Fri, 29 Aug 2008 07:13:32 +0000
parents d6e86a96f9b3
children f221fce3d6ba
comparison
equal deleted inserted replaced
48886:6ceb7c89e776 48887:c562c8dae49a
51 51
52 void 52 void
53 PyErr_SetObject(PyObject *exception, PyObject *value) 53 PyErr_SetObject(PyObject *exception, PyObject *value)
54 { 54 {
55 PyThreadState *tstate = PyThreadState_GET(); 55 PyThreadState *tstate = PyThreadState_GET();
56 PyObject *exc_value;
56 PyObject *tb = NULL; 57 PyObject *tb = NULL;
57 58
58 if (exception != NULL && 59 if (exception != NULL &&
59 !PyExceptionClass_Check(exception)) { 60 !PyExceptionClass_Check(exception)) {
60 PyErr_Format(PyExc_SystemError, 61 PyErr_Format(PyExc_SystemError,
61 "exception %R not a BaseException subclass", 62 "exception %R not a BaseException subclass",
62 exception); 63 exception);
63 return; 64 return;
64 } 65 }
65 Py_XINCREF(value); 66 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) {
67 /* Implicit exception chaining */ 69 /* Implicit exception chaining */
70 Py_INCREF(exc_value);
68 if (value == NULL || !PyExceptionInstance_Check(value)) { 71 if (value == NULL || !PyExceptionInstance_Check(value)) {
69 /* We must normalize the value right now */ 72 /* We must normalize the value right now */
70 PyObject *args, *fixed_value; 73 PyObject *args, *fixed_value;
71 if (value == NULL || value == Py_None) 74 if (value == NULL || value == Py_None)
72 args = PyTuple_New(0); 75 args = PyTuple_New(0);
86 } 89 }
87 /* Avoid reference cycles through the context chain. 90 /* Avoid reference cycles through the context chain.
88 This is O(chain length) but context chains are 91 This is O(chain length) but context chains are
89 usually very short. Sensitive readers may try 92 usually very short. Sensitive readers may try
90 to inline the call to PyException_GetContext. */ 93 to inline the call to PyException_GetContext. */
91 if (tstate->exc_value != value) { 94 if (exc_value != value) {
92 PyObject *o = tstate->exc_value, *context; 95 PyObject *o = exc_value, *context;
93 while ((context = PyException_GetContext(o))) { 96 while ((context = PyException_GetContext(o))) {
94 Py_DECREF(context); 97 Py_DECREF(context);
95 if (context == value) { 98 if (context == value) {
96 PyException_SetContext(o, NULL); 99 PyException_SetContext(o, NULL);
97 break; 100 break;
98 } 101 }
99 o = context; 102 o = context;
100 } 103 }
101 Py_INCREF(tstate->exc_value); 104 PyException_SetContext(value, exc_value);
102 PyException_SetContext(value, tstate->exc_value); 105 } else {
106 Py_DECREF(exc_value);
103 } 107 }
104 } 108 }
105 if (value != NULL && PyExceptionInstance_Check(value)) 109 if (value != NULL && PyExceptionInstance_Check(value))
106 tb = PyException_GetTraceback(value); 110 tb = PyException_GetTraceback(value);
107 Py_XINCREF(exception); 111 Py_XINCREF(exception);