diff options
author | Jason R. Coombs <jaraco@jaraco.com> | 2020-12-27 12:46:59 -0500 |
---|---|---|
committer | Jason R. Coombs <jaraco@jaraco.com> | 2020-12-27 12:46:59 -0500 |
commit | a78f0158a28734f965218b834ea8c0b166b7353f (patch) | |
tree | dca70268e2a41d49658e7eed783c6fc243d119cd /Python/ceval.c | |
parent | ec8e6895a3ce9cd69b6ceb75a15fcc74d4a522dc (diff) | |
parent | bf64d9064ab641b1ef9a0c4bda097ebf1204faf4 (diff) | |
download | cpython-git-revert-23107-revert-13893-fix-issue-37193.tar.gz |
Merge branch 'master' into revert-23107-revert-13893-fix-issue-37193revert-23107-revert-13893-fix-issue-37193
Diffstat (limited to 'Python/ceval.c')
-rw-r--r-- | Python/ceval.c | 147 |
1 files changed, 81 insertions, 66 deletions
diff --git a/Python/ceval.c b/Python/ceval.c index 13b209fc70..f0f39539c9 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -66,8 +66,8 @@ static void call_exc_trace(Py_tracefunc, PyObject *, PyThreadState *, PyFrameObject *); static int maybe_call_line_trace(Py_tracefunc, PyObject *, PyThreadState *, PyFrameObject *, - int *, int *, int *); -static void maybe_dtrace_line(PyFrameObject *, int *, int *, int *); + PyCodeAddressRange *, int *); +static void maybe_dtrace_line(PyFrameObject *, PyCodeAddressRange *, int *); static void dtrace_function_entry(PyFrameObject *); static void dtrace_function_return(PyFrameObject *); @@ -203,13 +203,18 @@ UNSIGNAL_PENDING_CALLS(PyInterpreterState *interp) static inline void -SIGNAL_PENDING_SIGNALS(PyInterpreterState *interp) +SIGNAL_PENDING_SIGNALS(PyInterpreterState *interp, int force) { struct _ceval_runtime_state *ceval = &interp->runtime->ceval; struct _ceval_state *ceval2 = &interp->ceval; _Py_atomic_store_relaxed(&ceval->signals_pending, 1); - /* eval_breaker is not set to 1 if thread_can_handle_signals() is false */ - COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); + if (force) { + _Py_atomic_store_relaxed(&ceval2->eval_breaker, 1); + } + else { + /* eval_breaker is not set to 1 if thread_can_handle_signals() is false */ + COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); + } } @@ -559,10 +564,22 @@ PyEval_RestoreThread(PyThreadState *tstate) void _PyEval_SignalReceived(PyInterpreterState *interp) { +#ifdef MS_WINDOWS + // bpo-42296: On Windows, _PyEval_SignalReceived() is called from a signal + // handler which can run in a thread different than the Python thread, in + // which case _Py_ThreadCanHandleSignals() is wrong. Ignore + // _Py_ThreadCanHandleSignals() and always set eval_breaker to 1. + // + // The next eval_frame_handle_pending() call will call + // _Py_ThreadCanHandleSignals() to recompute eval_breaker. + int force = 1; +#else + int force = 0; +#endif /* bpo-30703: Function called when the C signal handler of Python gets a signal. We cannot queue a callback using _PyEval_AddPendingCall() since that function is not async-signal-safe. */ - SIGNAL_PENDING_SIGNALS(interp); + SIGNAL_PENDING_SIGNALS(interp, force); } /* Push one item onto the queue while holding the lock. */ @@ -662,7 +679,7 @@ handle_signals(PyThreadState *tstate) UNSIGNAL_PENDING_SIGNALS(tstate->interp); if (_PyErr_CheckSignalsTstate(tstate) < 0) { /* On failure, re-schedule a call to handle_signals(). */ - SIGNAL_PENDING_SIGNALS(tstate->interp); + SIGNAL_PENDING_SIGNALS(tstate->interp, 0); return -1; } return 0; @@ -840,20 +857,22 @@ _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where) return -1; } #endif - if (tstate->overflowed) { + if (tstate->recursion_headroom) { if (tstate->recursion_depth > recursion_limit + 50) { /* Overflowing while handling an overflow. Give up. */ Py_FatalError("Cannot recover from stack overflow."); } - return 0; } - if (tstate->recursion_depth > recursion_limit) { - --tstate->recursion_depth; - tstate->overflowed = 1; - _PyErr_Format(tstate, PyExc_RecursionError, - "maximum recursion depth exceeded%s", - where); - return -1; + else { + if (tstate->recursion_depth > recursion_limit) { + tstate->recursion_headroom++; + _PyErr_Format(tstate, PyExc_RecursionError, + "maximum recursion depth exceeded%s", + where); + tstate->recursion_headroom--; + --tstate->recursion_depth; + return -1; + } } return 0; } @@ -948,6 +967,17 @@ eval_frame_handle_pending(PyThreadState *tstate) return -1; } +#ifdef MS_WINDOWS + // bpo-42296: On Windows, _PyEval_SignalReceived() can be called in a + // different thread than the Python thread, in which case + // _Py_ThreadCanHandleSignals() is wrong. Recompute eval_breaker in the + // current Python thread with the correct _Py_ThreadCanHandleSignals() + // value. It prevents to interrupt the eval loop at every instruction if + // the current Python thread cannot handle signals (if + // _Py_ThreadCanHandleSignals() is false). + COMPUTE_EVAL_BREAKER(tstate->interp, ceval, ceval2); +#endif + return 0; } @@ -976,7 +1006,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) is true when the line being executed has changed. The initial values are such as to make this false the first time it is tested. */ - int instr_ub = -1, instr_lb = 0, instr_prev = -1; const _Py_CODEUNIT *first_instr; PyObject *names; @@ -1390,6 +1419,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) dtrace_function_entry(f); co = f->f_code; + PyCodeAddressRange bounds; + _PyCode_InitAddressRange(co, &bounds); + int instr_prev = -1; + names = co->co_names; consts = co->co_consts; fastlocals = f->f_localsplus; @@ -1514,7 +1547,7 @@ main_loop: f->f_lasti = INSTR_OFFSET(); if (PyDTrace_LINE_ENABLED()) - maybe_dtrace_line(f, &instr_lb, &instr_ub, &instr_prev); + maybe_dtrace_line(f, &bounds, &instr_prev); /* line-by-line tracing support */ @@ -1528,7 +1561,7 @@ main_loop: err = maybe_call_line_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, f, - &instr_lb, &instr_ub, &instr_prev); + &bounds, &instr_prev); /* Reload possibly changed frame fields */ JUMPTO(f->f_lasti); stack_pointer = f->f_valuestack+f->f_stackdepth; @@ -2397,6 +2430,10 @@ main_loop: } case TARGET(RERAISE): { + assert(f->f_iblock > 0); + if (oparg) { + f->f_lasti = f->f_blockstack[f->f_iblock-1].b_handler; + } PyObject *exc = POP(); PyObject *val = POP(); PyObject *tb = POP(); @@ -3179,7 +3216,6 @@ main_loop: if (co_opcache != NULL && /* co_opcache can be NULL after a DEOPT() call. */ type->tp_getattro == PyObject_GenericGetAttr) { - PyObject *descr; Py_ssize_t ret; if (type->tp_dictoffset > 0) { @@ -3190,12 +3226,7 @@ main_loop: goto error; } } - - descr = _PyType_Lookup(type, name); - if (descr == NULL || - Py_TYPE(descr)->tp_descr_get == NULL || - !PyDescr_IsData(descr)) - { + if (_PyType_Lookup(type, name) == NULL) { dictptr = (PyObject **) ((char *)owner + type->tp_dictoffset); dict = *dictptr; @@ -3855,7 +3886,7 @@ main_loop: func ->func_closure = POP(); } if (oparg & 0x04) { - assert(PyDict_CheckExact(TOP())); + assert(PyTuple_CheckExact(TOP())); func->func_annotations = POP(); } if (oparg & 0x02) { @@ -4012,7 +4043,7 @@ exception_unwind: int handler = b->b_handler; _PyErr_StackItem *exc_info = tstate->exc_info; /* Beware, this invalidates all b->b_* fields */ - PyFrame_BlockSetup(f, EXCEPT_HANDLER, -1, STACK_LEVEL()); + PyFrame_BlockSetup(f, EXCEPT_HANDLER, f->f_lasti, STACK_LEVEL()); PUSH(exc_info->exc_traceback); PUSH(exc_info->exc_value); if (exc_info->exc_type != NULL) { @@ -4045,14 +4076,7 @@ exception_unwind: PUSH(exc); JUMPTO(handler); if (_Py_TracingPossible(ceval2)) { - int needs_new_execution_window = (f->f_lasti < instr_lb || f->f_lasti >= instr_ub); - int needs_line_update = (f->f_lasti == instr_lb || f->f_lasti < instr_prev); - /* Make sure that we trace line after exception if we are in a new execution - * window or we don't need a line update and we are not in the first instruction - * of the line. */ - if (needs_new_execution_window || (!needs_line_update && instr_lb > 0)) { - instr_prev = INT_MAX; - } + instr_prev = INT_MAX; } /* Resume normal execution */ f->f_state = FRAME_EXECUTING; @@ -4966,7 +4990,7 @@ _PyEval_CallTracing(PyObject *func, PyObject *args) static int maybe_call_line_trace(Py_tracefunc func, PyObject *obj, PyThreadState *tstate, PyFrameObject *frame, - int *instr_lb, int *instr_ub, int *instr_prev) + PyCodeAddressRange *bounds, int *instr_prev) { int result = 0; int line = frame->f_lineno; @@ -4974,21 +4998,17 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, /* If the last instruction executed isn't in the current instruction window, reset the window. */ - if (frame->f_lasti < *instr_lb || frame->f_lasti >= *instr_ub) { - PyAddrPair bounds; - line = _PyCode_CheckLineNumber(frame->f_code, frame->f_lasti, - &bounds); - *instr_lb = bounds.ap_lower; - *instr_ub = bounds.ap_upper; - } + line = _PyCode_CheckLineNumber(frame->f_lasti, bounds); /* If the last instruction falls at the start of a line or if it represents a jump backwards, update the frame's line number and then call the trace function if we're tracing source lines. */ - if ((frame->f_lasti == *instr_lb || frame->f_lasti < *instr_prev)) { - frame->f_lineno = line; - if (frame->f_trace_lines) { - result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None); + if ((line != frame->f_lineno || frame->f_lasti < *instr_prev)) { + if (line != -1) { + frame->f_lineno = line; + if (frame->f_trace_lines) { + result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None); + } } } /* Always emit an opcode event if we're tracing all opcodes. */ @@ -5913,33 +5933,28 @@ dtrace_function_return(PyFrameObject *f) /* DTrace equivalent of maybe_call_line_trace. */ static void maybe_dtrace_line(PyFrameObject *frame, - int *instr_lb, int *instr_ub, int *instr_prev) + PyCodeAddressRange *bounds, int *instr_prev) { - int line = frame->f_lineno; const char *co_filename, *co_name; /* If the last instruction executed isn't in the current instruction window, reset the window. */ - if (frame->f_lasti < *instr_lb || frame->f_lasti >= *instr_ub) { - PyAddrPair bounds; - line = _PyCode_CheckLineNumber(frame->f_code, frame->f_lasti, - &bounds); - *instr_lb = bounds.ap_lower; - *instr_ub = bounds.ap_upper; - } + int line = _PyCode_CheckLineNumber(frame->f_lasti, bounds); /* If the last instruction falls at the start of a line or if it represents a jump backwards, update the frame's line number and call the trace function. */ - if (frame->f_lasti == *instr_lb || frame->f_lasti < *instr_prev) { - frame->f_lineno = line; - co_filename = PyUnicode_AsUTF8(frame->f_code->co_filename); - if (!co_filename) - co_filename = "?"; - co_name = PyUnicode_AsUTF8(frame->f_code->co_name); - if (!co_name) - co_name = "?"; - PyDTrace_LINE(co_filename, co_name, line); + if (line != frame->f_lineno || frame->f_lasti < *instr_prev) { + if (line != -1) { + frame->f_lineno = line; + co_filename = PyUnicode_AsUTF8(frame->f_code->co_filename); + if (!co_filename) + co_filename = "?"; + co_name = PyUnicode_AsUTF8(frame->f_code->co_name); + if (!co_name) + co_name = "?"; + PyDTrace_LINE(co_filename, co_name, line); + } } *instr_prev = frame->f_lasti; } |