diff options
Diffstat (limited to 'Python/ceval.c')
-rw-r--r-- | Python/ceval.c | 81 |
1 files changed, 57 insertions, 24 deletions
diff --git a/Python/ceval.c b/Python/ceval.c index 82b5422..c08c794 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -257,9 +257,9 @@ Py_SetRecursionLimit(int new_limit) PyInterpreterState *interp = _PyInterpreterState_GET(); interp->ceval.recursion_limit = new_limit; for (PyThreadState *p = interp->threads.head; p != NULL; p = p->next) { - int depth = p->recursion_limit - p->recursion_remaining; - p->recursion_limit = new_limit; - p->recursion_remaining = new_limit - depth; + int depth = p->py_recursion_limit - p->py_recursion_remaining; + p->py_recursion_limit = new_limit; + p->py_recursion_remaining = new_limit - depth; } } @@ -268,35 +268,27 @@ Py_SetRecursionLimit(int new_limit) int _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where) { - /* Check against global limit first. */ - int depth = tstate->recursion_limit - tstate->recursion_remaining; - if (depth < tstate->interp->ceval.recursion_limit) { - tstate->recursion_limit = tstate->interp->ceval.recursion_limit; - tstate->recursion_remaining = tstate->recursion_limit - depth; - assert(tstate->recursion_remaining > 0); - return 0; - } #ifdef USE_STACKCHECK if (PyOS_CheckStack()) { - ++tstate->recursion_remaining; + ++tstate->c_recursion_remaining; _PyErr_SetString(tstate, PyExc_MemoryError, "Stack overflow"); return -1; } #endif if (tstate->recursion_headroom) { - if (tstate->recursion_remaining < -50) { + if (tstate->c_recursion_remaining < -50) { /* Overflowing while handling an overflow. Give up. */ Py_FatalError("Cannot recover from stack overflow."); } } else { - if (tstate->recursion_remaining <= 0) { + if (tstate->c_recursion_remaining <= 0) { tstate->recursion_headroom++; _PyErr_Format(tstate, PyExc_RecursionError, "maximum recursion depth exceeded%s", where); tstate->recursion_headroom--; - ++tstate->recursion_remaining; + ++tstate->c_recursion_remaining; return -1; } } @@ -983,6 +975,39 @@ pop_frame(PyThreadState *tstate, _PyInterpreterFrame *frame) return prev_frame; } + +int _Py_CheckRecursiveCallPy( + PyThreadState *tstate) +{ + if (tstate->recursion_headroom) { + if (tstate->py_recursion_remaining < -50) { + /* Overflowing while handling an overflow. Give up. */ + Py_FatalError("Cannot recover from Python stack overflow."); + } + } + else { + if (tstate->py_recursion_remaining <= 0) { + tstate->recursion_headroom++; + _PyErr_Format(tstate, PyExc_RecursionError, + "maximum recursion depth exceeded"); + tstate->recursion_headroom--; + return -1; + } + } + return 0; +} + +static inline int _Py_EnterRecursivePy(PyThreadState *tstate) { + return (tstate->py_recursion_remaining-- <= 0) && + _Py_CheckRecursiveCallPy(tstate); +} + + +static inline void _Py_LeaveRecursiveCallPy(PyThreadState *tstate) { + tstate->py_recursion_remaining++; +} + + /* It is only between the KW_NAMES instruction and the following CALL, * that this has any meaning. */ @@ -1037,10 +1062,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int frame->previous = prev_cframe->current_frame; cframe.current_frame = frame; + if (_Py_EnterRecursiveCallTstate(tstate, "")) { + tstate->c_recursion_remaining--; + tstate->py_recursion_remaining--; + goto exit_unwind; + } + /* support for generator.throw() */ if (throwflag) { - if (_Py_EnterRecursiveCallTstate(tstate, "")) { - tstate->recursion_remaining--; + if (_Py_EnterRecursivePy(tstate)) { goto exit_unwind; } TRACE_FUNCTION_THROW_ENTRY(); @@ -1079,8 +1109,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int start_frame: - if (_Py_EnterRecursiveCallTstate(tstate, "")) { - tstate->recursion_remaining--; + if (_Py_EnterRecursivePy(tstate)) { goto exit_unwind; } @@ -1830,12 +1859,13 @@ handle_eval_breaker: _PyFrame_SetStackPointer(frame, stack_pointer); TRACE_FUNCTION_EXIT(); DTRACE_FUNCTION_EXIT(); - _Py_LeaveRecursiveCallTstate(tstate); + _Py_LeaveRecursiveCallPy(tstate); if (!frame->is_entry) { frame = cframe.current_frame = pop_frame(tstate, frame); _PyFrame_StackPush(frame, retval); goto resume_frame; } + _Py_LeaveRecursiveCallTstate(tstate); /* Restore previous cframe and return. */ tstate->cframe = cframe.previous; tstate->cframe->use_tracing = cframe.use_tracing; @@ -2046,6 +2076,7 @@ handle_eval_breaker: _PyFrame_SetStackPointer(frame, stack_pointer); TRACE_FUNCTION_EXIT(); DTRACE_FUNCTION_EXIT(); + _Py_LeaveRecursiveCallPy(tstate); _Py_LeaveRecursiveCallTstate(tstate); /* Restore previous cframe and return. */ tstate->cframe = cframe.previous; @@ -4800,7 +4831,7 @@ handle_eval_breaker: assert(frame->frame_obj == NULL); gen->gi_frame_state = FRAME_CREATED; gen_frame->owner = FRAME_OWNED_BY_GENERATOR; - _Py_LeaveRecursiveCallTstate(tstate); + _Py_LeaveRecursiveCallPy(tstate); if (!frame->is_entry) { _PyInterpreterFrame *prev = frame->previous; _PyThreadState_PopFrame(tstate, frame); @@ -4808,6 +4839,7 @@ handle_eval_breaker: _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; } + _Py_LeaveRecursiveCallTstate(tstate); /* Make sure that frame is in a valid state */ frame->stacktop = 0; frame->f_locals = NULL; @@ -5178,12 +5210,13 @@ exception_unwind: exit_unwind: assert(_PyErr_Occurred(tstate)); - _Py_LeaveRecursiveCallTstate(tstate); + _Py_LeaveRecursiveCallPy(tstate); if (frame->is_entry) { /* Restore previous cframe and exit */ tstate->cframe = cframe.previous; tstate->cframe->use_tracing = cframe.use_tracing; assert(tstate->cframe->current_frame == frame->previous); + _Py_LeaveRecursiveCallTstate(tstate); return NULL; } frame = cframe.current_frame = pop_frame(tstate, frame); @@ -5755,11 +5788,11 @@ _PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame * frame) // _PyThreadState_PopFrame, since f_code is already cleared at that point: assert((PyObject **)frame + frame->f_code->co_framesize == tstate->datastack_top); - tstate->recursion_remaining--; + tstate->c_recursion_remaining--; assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame); assert(frame->owner == FRAME_OWNED_BY_THREAD); _PyFrame_Clear(frame); - tstate->recursion_remaining++; + tstate->c_recursion_remaining++; _PyThreadState_PopFrame(tstate, frame); } |