Index: Python/errors.c =================================================================== --- Python/errors.c (revision 47175) +++ Python/errors.c (working copy) @@ -132,6 +132,7 @@ PyObject *value = *val; PyObject *inclass = NULL; PyObject *initial_tb = NULL; + PyThreadState *tstate = NULL; if (type == NULL) { /* There was no exception, so nothing to do. */ @@ -207,7 +208,14 @@ Py_DECREF(initial_tb); } /* normalize recursively */ + tstate = PyThreadState_GET(); + if (++tstate->recursion_depth > Py_GetRecursionLimit()) { + --tstate->recursion_depth; + PyErr_SetObject(PyExc_RuntimeError, PyExc_RecursionErrorInst); + return; + } PyErr_NormalizeException(exc, val, tb); + --tstate->recursion_depth; } Index: Include/pyerrors.h =================================================================== --- Include/pyerrors.h (revision 47175) +++ Include/pyerrors.h (working copy) @@ -163,6 +163,7 @@ #endif PyAPI_DATA(PyObject *) PyExc_MemoryErrorInst; +PyAPI_DATA(PyObject *) PyExc_RecursionErrorInst; /* Predefined warning categories */ PyAPI_DATA(PyObject *) PyExc_Warning; Index: Objects/abstract.c =================================================================== --- Objects/abstract.c (revision 47175) +++ Objects/abstract.c (working copy) @@ -1796,7 +1796,11 @@ ternaryfunc call; if ((call = func->ob_type->tp_call) != NULL) { - PyObject *result = (*call)(func, arg, kw); + PyObject *result; + if (Py_EnterRecursiveCall(" while calling a Python object")) + return NULL; + result = (*call)(func, arg, kw); + Py_LeaveRecursiveCall(); if (result == NULL && !PyErr_Occurred()) PyErr_SetString( PyExc_SystemError, Index: Objects/typeobject.c =================================================================== --- Objects/typeobject.c (revision 47175) +++ Objects/typeobject.c (working copy) @@ -4591,16 +4603,7 @@ if (meth == NULL) return NULL; - /* PyObject_Call() will end up calling slot_tp_call() again if - the object returned for __call__ has __call__ itself defined - upon it. This can be an infinite recursion if you set - __call__ in a class to an instance of it. */ - if (Py_EnterRecursiveCall(" in __call__")) { - Py_DECREF(meth); - return NULL; - } res = PyObject_Call(meth, args, kwds); - Py_LeaveRecursiveCall(); Py_DECREF(meth); return res; Index: Objects/exceptions.c =================================================================== --- Objects/exceptions.c (revision 47175) +++ Objects/exceptions.c (working copy) @@ -1953,6 +1953,12 @@ */ PyObject *PyExc_MemoryErrorInst=NULL; +/* Pre-computed RuntimeError instance for when recursion depth is reached. + Meant to be used when normalizing the exception for exceeding the recursion + depth will cause its own infinite recursion. +*/ +PyObject *PyExc_RecursionErrorInst = NULL; + /* module global functions */ static PyMethodDef functions[] = { /* Sentinel */ @@ -2118,6 +2124,29 @@ if (!PyExc_MemoryErrorInst) Py_FatalError("Cannot pre-allocate MemoryError instance\n"); + PyExc_RecursionErrorInst = BaseException_new(&_PyExc_RuntimeError, NULL, NULL); + if (!PyExc_RecursionErrorInst) + Py_FatalError("Cannot pre-allocate RuntimeError instance for " + "recursion errors"); + else { + PyBaseExceptionObject *err_inst = + (PyBaseExceptionObject *)PyExc_RecursionErrorInst; + PyObject *args_tuple; + PyObject *exc_message; + exc_message = PyString_FromString("maximum recursion depth exceeded"); + if (!exc_message) + Py_FatalError("cannot allocate argument for RuntimeError " + "pre-allocation"); + args_tuple = PyTuple_Pack(1, exc_message); + if (!args_tuple) + Py_FatalError("cannot allocate tuple for RuntimeError " + "pre-allocation"); + Py_DECREF(exc_message); + if (BaseException_init(err_inst, args_tuple, NULL)) + Py_FatalError("init of pre-allocated RuntimeError failed"); + Py_DECREF(args_tuple); + } + Py_DECREF(bltinmod); #if defined _MSC_VER && _MSC_VER >= 1400