diff -r 16ea07d420b8 Lib/ctypes/test/test_structures.py --- a/Lib/ctypes/test/test_structures.py Fri Oct 28 12:17:17 2016 +0300 +++ b/Lib/ctypes/test/test_structures.py Fri Oct 28 12:37:10 2016 +0300 @@ -321,13 +321,13 @@ class StructureTestCase(unittest.TestCas cls, msg = self.get_except(Person, b"Someone", (1, 2)) self.assertEqual(cls, RuntimeError) self.assertEqual(msg, - "(Phone) : " + "(Phone) TypeError: " "expected bytes, int found") cls, msg = self.get_except(Person, b"Someone", (b"a", b"b", b"c")) self.assertEqual(cls, RuntimeError) self.assertEqual(msg, - "(Phone) : too many initializers") + "(Phone) TypeError: too many initializers") def test_huge_field_name(self): # issue12881: segfault with large structure field names diff -r 16ea07d420b8 Modules/_ctypes/callproc.c --- a/Modules/_ctypes/callproc.c Fri Oct 28 12:17:17 2016 +0300 +++ b/Modules/_ctypes/callproc.c Fri Oct 28 12:37:10 2016 +0300 @@ -929,24 +929,22 @@ static PyObject *GetResult(PyObject *res void _ctypes_extend_error(PyObject *exc_class, const char *fmt, ...) { va_list vargs; - PyObject *tp, *v, *tb, *s, *cls_str, *msg_str; + PyObject *tp, *v, *tb, *s, *msg_str; + + PyErr_Fetch(&tp, &v, &tb); + assert(tp != NULL); + PyErr_NormalizeException(&tp, &v, &tb); va_start(vargs, fmt); s = PyUnicode_FromFormatV(fmt, vargs); va_end(vargs); - if (!s) - return; + if (s == NULL) + goto error; - PyErr_Fetch(&tp, &v, &tb); - PyErr_NormalizeException(&tp, &v, &tb); - cls_str = PyObject_Str(tp); - if (cls_str) { - PyUnicode_AppendAndDel(&s, cls_str); - PyUnicode_AppendAndDel(&s, PyUnicode_FromString(": ")); - if (s == NULL) - goto error; - } else - PyErr_Clear(); + Py_SETREF(s, PyUnicode_FromFormat("%U%.200s: ", + s, ((PyTypeObject*)tp)->tp_name)); + if (s == NULL) + goto error; msg_str = PyObject_Str(v); if (msg_str) PyUnicode_AppendAndDel(&s, msg_str); @@ -957,11 +955,9 @@ void _ctypes_extend_error(PyObject *exc_ if (s == NULL) goto error; PyErr_SetObject(exc_class, s); + return; error: - Py_XDECREF(tp); - Py_XDECREF(v); - Py_XDECREF(tb); - Py_XDECREF(s); + _PyErr_ChainExceptions(tp, v, tb); } diff -r 16ea07d420b8 Modules/atexitmodule.c --- a/Modules/atexitmodule.c Fri Oct 28 12:17:17 2016 +0300 +++ b/Modules/atexitmodule.c Fri Oct 28 12:37:10 2016 +0300 @@ -97,7 +97,7 @@ atexit_callfuncs(void) Py_XDECREF(exc_tb); } PyErr_Fetch(&exc_type, &exc_value, &exc_tb); - if (!PyErr_ExceptionMatches(PyExc_SystemExit)) { + if (!PyErr_GivenExceptionMatches(exc_type, PyExc_SystemExit)) { PySys_WriteStderr("Error in atexit._run_exitfuncs:\n"); PyErr_NormalizeException(&exc_type, &exc_value, &exc_tb); PyErr_Display(exc_type, exc_value, exc_tb); diff -r 16ea07d420b8 Objects/exceptions.c --- a/Objects/exceptions.c Fri Oct 28 12:17:17 2016 +0300 +++ b/Objects/exceptions.c Fri Oct 28 12:37:10 2016 +0300 @@ -2784,7 +2784,7 @@ PyObject * return NULL; } - PyErr_Format(exc, "%U (%s: %S)", + PyErr_Format(exc, "%U (%.100s: %S)", msg_prefix, Py_TYPE(val)->tp_name, val); Py_DECREF(exc); Py_DECREF(msg_prefix); diff -r 16ea07d420b8 Objects/genobject.c --- a/Objects/genobject.c Fri Oct 28 12:17:17 2016 +0300 +++ b/Objects/genobject.c Fri Oct 28 12:37:10 2016 +0300 @@ -265,9 +265,7 @@ gen_send_ex(PyGenObject *gen, PyObject * "generator '%.50S' raised StopIteration", gen->gi_qualname)) { /* Warning was converted to an error. */ - Py_XDECREF(exc); - Py_XDECREF(val); - Py_XDECREF(tb); + _PyErr_ChainExceptions(exc, val, tb); } else { PyErr_Restore(exc, val, tb); @@ -597,8 +595,8 @@ int Py_INCREF(value); Py_DECREF(ev); } + Py_DECREF(et); } - Py_XDECREF(et); Py_XDECREF(tb); } else if (PyErr_Occurred()) { return -1; diff -r 16ea07d420b8 Python/ceval.c --- a/Python/ceval.c Fri Oct 28 12:17:17 2016 +0300 +++ b/Python/ceval.c Fri Oct 28 12:37:10 2016 +0300 @@ -4422,6 +4422,7 @@ call_exc_trace(Py_tracefunc func, PyObje PyObject *type, *value, *traceback, *orig_traceback, *arg; int err; PyErr_Fetch(&type, &value, &orig_traceback); + assert(type != NULL); if (value == NULL) { value = Py_None; Py_INCREF(value); @@ -4437,11 +4438,8 @@ call_exc_trace(Py_tracefunc func, PyObje Py_DECREF(arg); if (err == 0) PyErr_Restore(type, value, orig_traceback); - else { - Py_XDECREF(type); - Py_XDECREF(value); - Py_XDECREF(orig_traceback); - } + else + _PyErr_ChainExceptions(type, value, orig_traceback); } static int @@ -4459,9 +4457,7 @@ call_trace_protected(Py_tracefunc func, return 0; } else { - Py_XDECREF(type); - Py_XDECREF(value); - Py_XDECREF(traceback); + _PyErr_ChainExceptions(type, value, traceback); return -1; } } diff -r 16ea07d420b8 Python/errors.c --- a/Python/errors.c Fri Oct 28 12:17:17 2016 +0300 +++ b/Python/errors.c Fri Oct 28 12:37:10 2016 +0300 @@ -37,6 +37,13 @@ PyErr_Restore(PyObject *type, PyObject * traceback = NULL; } +#ifdef Py_DEBUG + if (type == NULL) { + assert(value == NULL); + assert(traceback == NULL); + } +#endif + /* Save these in locals to safeguard against recursive invocation through Py_XDECREF */ oldtype = tstate->curexc_type; @@ -226,17 +233,18 @@ PyErr_ExceptionMatches(PyObject *exc) void PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb) { - PyObject *type = *exc; - PyObject *value = *val; - PyObject *inclass = NULL; - PyObject *initial_tb = NULL; - PyThreadState *tstate = NULL; + int recursion_depth = 0; + PyObject *type, *value, *initial_tb; + PyThreadState *tstate; +restart: + type = *exc; if (type == NULL) { /* There was no exception, so nothing to do. */ return; } + value = *val; /* If PyErr_SetNone() was used, the value will have been actually set to NULL. */ @@ -245,14 +253,18 @@ PyErr_NormalizeException(PyObject **exc, Py_INCREF(value); } - if (PyExceptionInstance_Check(value)) - inclass = PyExceptionInstance_Class(value); - /* Normalize the exception so that if the type is a class, the value will be an instance. */ if (PyExceptionClass_Check(type)) { + PyObject *inclass; int is_subclass; + + if (PyExceptionInstance_Check(value)) + inclass = PyExceptionInstance_Class(value); + else + inclass = NULL; + if (inclass) { is_subclass = PyObject_IsSubclass(inclass, type); if (is_subclass < 0) @@ -266,7 +278,7 @@ PyErr_NormalizeException(PyObject **exc, value as an argument to instantiation of the type class. */ - if (!inclass || !is_subclass) { + if (!is_subclass) { PyObject *fixed_value; fixed_value = _PyErr_CreateException(type, value); @@ -289,6 +301,7 @@ PyErr_NormalizeException(PyObject **exc, *exc = type; *val = value; return; + finally: Py_DECREF(type); Py_DECREF(value); @@ -298,6 +311,7 @@ finally: */ initial_tb = *tb; PyErr_Fetch(exc, val, tb); + assert(*exc != NULL); if (initial_tb != NULL) { if (*tb == NULL) *tb = initial_tb; @@ -306,18 +320,17 @@ finally: } /* normalize recursively */ tstate = PyThreadState_GET(); - if (++tstate->recursion_depth > Py_GetRecursionLimit()) { - --tstate->recursion_depth; + if (++recursion_depth > Py_GetRecursionLimit() - tstate->recursion_depth) { /* throw away the old exception and use the recursion error instead */ Py_INCREF(PyExc_RecursionError); Py_SETREF(*exc, PyExc_RecursionError); Py_INCREF(PyExc_RecursionErrorInst); - Py_SETREF(*val, PyExc_RecursionErrorInst); + Py_XSETREF(*val, PyExc_RecursionErrorInst); /* just keeping the old traceback */ return; } - PyErr_NormalizeException(exc, val, tb); - --tstate->recursion_depth; + /* eliminate tail recursion */ + goto restart; } @@ -333,6 +346,13 @@ PyErr_Fetch(PyObject **p_type, PyObject tstate->curexc_type = NULL; tstate->curexc_value = NULL; tstate->curexc_traceback = NULL; + +#ifdef Py_DEBUG + if (*p_type == NULL) { + assert(*p_value == NULL); + assert(*p_traceback == NULL); + } +#endif } void diff -r 16ea07d420b8 Python/pylifecycle.c --- a/Python/pylifecycle.c Fri Oct 28 12:17:17 2016 +0300 +++ b/Python/pylifecycle.c Fri Oct 28 12:37:10 2016 +0300 @@ -1378,14 +1378,16 @@ static int PyException_SetTraceback(v, tb); if (exception == NULL) { /* PyErr_NormalizeException() failed */ + Py_XDECREF(v); + Py_DECREF(tb); return 0; } has_tb = (tb != Py_None); PyErr_Display(exception, v, tb); - Py_XDECREF(exception); - Py_XDECREF(v); - Py_XDECREF(tb); + Py_DECREF(exception); + Py_DECREF(v); + Py_DECREF(tb); /* sys.stderr may be buffered: call sys.stderr.flush() */ res = _PyObject_CallMethodId(ferr, &PyId_flush, NULL); diff -r 16ea07d420b8 Python/pythonrun.c --- a/Python/pythonrun.c Fri Oct 28 12:17:17 2016 +0300 +++ b/Python/pythonrun.c Fri Oct 28 12:37:10 2016 +0300 @@ -620,8 +620,7 @@ PyErr_PrintEx(int set_sys_last_vars) Py_INCREF(tb); } PyException_SetTraceback(v, tb); - if (exception == NULL) - return; + assert(exception != NULL); /* Now we know v != NULL too */ if (set_sys_last_vars) { _PySys_SetObjectId(&PyId_last_type, exception); @@ -630,13 +629,8 @@ PyErr_PrintEx(int set_sys_last_vars) } hook = _PySys_GetObjectId(&PyId_excepthook); if (hook) { - PyObject* stack[3]; - PyObject *result; - - stack[0] = exception; - stack[1] = v; - stack[2] = tb; - result = _PyObject_FastCall(hook, stack, 3); + PyObject *stack[3] = {exception, v, tb}; + PyObject *result = _PyObject_FastCall(hook, stack, 3); if (result == NULL) { PyObject *exception2, *v2, *tb2; if (PyErr_ExceptionMatches(PyExc_SystemExit)) { @@ -663,15 +657,15 @@ PyErr_PrintEx(int set_sys_last_vars) Py_DECREF(exception2); Py_DECREF(v2); Py_XDECREF(tb2); + Py_DECREF(result); } - Py_XDECREF(result); } else { PySys_WriteStderr("sys.excepthook is missing\n"); PyErr_Display(exception, v, tb); } - Py_XDECREF(exception); - Py_XDECREF(v); - Py_XDECREF(tb); + Py_DECREF(exception); + Py_DECREF(v); + Py_DECREF(tb); } static void diff -r 16ea07d420b8 Python/traceback.c --- a/Python/traceback.c Fri Oct 28 12:17:17 2016 +0300 +++ b/Python/traceback.c Fri Oct 28 12:37:10 2016 +0300 @@ -485,22 +485,16 @@ PyTraceBack_Print(PyObject *v, PyObject } limitv = PySys_GetObject("tracebacklimit"); if (limitv) { + int overflow; PyObject *exc_type, *exc_value, *exc_tb; PyErr_Fetch(&exc_type, &exc_value, &exc_tb); - limit = PyLong_AsLong(limitv); + limit = PyLong_AsLongAndOverflow(limitv, &overflow); if (limit == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - limit = PyTraceBack_LIMIT; - } - else { - Py_XDECREF(exc_type); - Py_XDECREF(exc_value); - Py_XDECREF(exc_tb); - return 0; - } + _PyErr_ChainExceptions(exc_type, exc_value, exc_tb); + return 0; } - else if (limit <= 0) { + else if (limit <= 0) { /* negative or overflows */ limit = PyTraceBack_LIMIT; } PyErr_Restore(exc_type, exc_value, exc_tb);