From 28943772709fca49f76c462a8d4dac3a589be1c0 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 1 May 2022 00:42:06 -0400 Subject: [PATCH 1/2] Add TARGET_SAFE --- Python/ceval.c | 81 +++++++++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 34 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index f3329b5d9d454d..7d572fade9205d 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1357,22 +1357,35 @@ eval_frame_handle_pending(PyThreadState *tstate) #endif #ifdef Py_STATS -#define INSTRUCTION_START(op) \ +#define RECORD_STATS(op) \ do { \ - frame->prev_instr = next_instr++; \ OPCODE_EXE_INC(op); \ _py_stats.opcode_stats[lastopcode].pair_count[op]++; \ lastopcode = op; \ } while (0) #else -#define INSTRUCTION_START(op) (frame->prev_instr = next_instr++) +#define RECORD_STATS(op) ((void)0) #endif +#define INSTRUCTION_START(op) \ + do { \ + frame->prev_instr = next_instr++; \ + RECORD_STATS(op); \ + } while (0) + +#define SAFE_INSTRUCTION_START(op) \ + do { \ + next_instr++;\ + RECORD_STATS(op); \ + } while (0) + #if USE_COMPUTED_GOTOS #define TARGET(op) TARGET_##op: INSTRUCTION_START(op); +#define TARGET_SAFE(op) TARGET_##op: SAFE_INSTRUCTION_START(op); #define DISPATCH_GOTO() goto *opcode_targets[opcode] #else #define TARGET(op) case op: INSTRUCTION_START(op); +#define TARGET_SAFE(op) case op: SAFE_INSTRUCTION_START(op); #define DISPATCH_GOTO() goto dispatch_opcode #endif @@ -1831,16 +1844,16 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int It is essential that any operation that fails must goto error and that all operation that succeed call DISPATCH() ! */ - TARGET(NOP) { + TARGET_SAFE(NOP) { DISPATCH(); } - TARGET(RESUME) { + TARGET_SAFE(RESUME) { _PyCode_Warmup(frame->f_code); JUMP_TO_INSTRUCTION(RESUME_QUICK); } - TARGET(RESUME_QUICK) { + TARGET_SAFE(RESUME_QUICK) { PREDICTED(RESUME_QUICK); assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); @@ -1861,7 +1874,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(LOAD_FAST) { + TARGET_SAFE(LOAD_FAST) { PyObject *value = GETLOCAL(oparg); if (value == NULL) { goto unbound_local_error; @@ -1871,7 +1884,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(LOAD_CONST) { + TARGET_SAFE(LOAD_CONST) { PREDICTED(LOAD_CONST); PyObject *value = GETITEM(consts, oparg); Py_INCREF(value); @@ -1886,7 +1899,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(LOAD_FAST__LOAD_FAST) { + TARGET_SAFE(LOAD_FAST__LOAD_FAST) { PyObject *value = GETLOCAL(oparg); if (value == NULL) { goto unbound_local_error; @@ -1904,7 +1917,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int NOTRACE_DISPATCH(); } - TARGET(LOAD_FAST__LOAD_CONST) { + TARGET_SAFE(LOAD_FAST__LOAD_CONST) { PyObject *value = GETLOCAL(oparg); if (value == NULL) { goto unbound_local_error; @@ -1943,7 +1956,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int NOTRACE_DISPATCH(); } - TARGET(LOAD_CONST__LOAD_FAST) { + TARGET_SAFE(LOAD_CONST__LOAD_FAST) { PyObject *value = GETITEM(consts, oparg); NEXTOPARG(); next_instr++; @@ -1964,7 +1977,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(PUSH_NULL) { + TARGET_SAFE(PUSH_NULL) { /* Use BASIC_PUSH as NULL is not a valid object pointer */ BASIC_PUSH(NULL); DISPATCH(); @@ -2775,7 +2788,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } } - TARGET(LOAD_ASSERTION_ERROR) { + TARGET_SAFE(LOAD_ASSERTION_ERROR) { PyObject *value = PyExc_AssertionError; Py_INCREF(value); PUSH(value); @@ -3122,7 +3135,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } } - TARGET(LOAD_GLOBAL_MODULE) { + TARGET_SAFE(LOAD_GLOBAL_MODULE) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); @@ -3143,7 +3156,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int NOTRACE_DISPATCH(); } - TARGET(LOAD_GLOBAL_BUILTIN) { + TARGET_SAFE(LOAD_GLOBAL_BUILTIN) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); @@ -3237,7 +3250,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(LOAD_DEREF) { + TARGET_SAFE(LOAD_DEREF) { PyObject *cell = GETLOCAL(oparg); PyObject *value = PyCell_GET(cell); if (value == NULL) { @@ -3258,7 +3271,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(COPY_FREE_VARS) { + TARGET_SAFE(COPY_FREE_VARS) { /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; PyObject *closure = frame->f_func->func_closure; @@ -4044,12 +4057,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(JUMP_FORWARD) { + TARGET_SAFE(JUMP_FORWARD) { JUMPBY(oparg); DISPATCH(); } - TARGET(JUMP_BACKWARD) { + TARGET_SAFE(JUMP_BACKWARD) { _PyCode_Warmup(frame->f_code); JUMP_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); } @@ -4247,7 +4260,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(JUMP_BACKWARD_NO_INTERRUPT) { + TARGET_SAFE(JUMP_BACKWARD_NO_INTERRUPT) { /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. @@ -4257,7 +4270,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(JUMP_BACKWARD_QUICK) { + TARGET_SAFE(JUMP_BACKWARD_QUICK) { PREDICTED(JUMP_BACKWARD_QUICK); assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); @@ -4515,7 +4528,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(PUSH_EXC_INFO) { + TARGET_SAFE(PUSH_EXC_INFO) { PyObject *value = TOP(); _PyErr_StackItem *exc_info = tstate->exc_info; @@ -4593,7 +4606,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } } - TARGET(LOAD_METHOD_WITH_VALUES) { + TARGET_SAFE(LOAD_METHOD_WITH_VALUES) { /* LOAD_METHOD, with cached method object */ assert(cframe.use_tracing == 0); PyObject *self = TOP(); @@ -4619,7 +4632,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int NOTRACE_DISPATCH(); } - TARGET(LOAD_METHOD_WITH_DICT) { + TARGET_SAFE(LOAD_METHOD_WITH_DICT) { /* LOAD_METHOD, with a dict Can be either a managed dict, or a tp_dictoffset offset.*/ assert(cframe.use_tracing == 0); @@ -4651,7 +4664,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int NOTRACE_DISPATCH(); } - TARGET(LOAD_METHOD_NO_DICT) { + TARGET_SAFE(LOAD_METHOD_NO_DICT) { assert(cframe.use_tracing == 0); PyObject *self = TOP(); PyTypeObject *self_cls = Py_TYPE(self); @@ -4706,7 +4719,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int NOTRACE_DISPATCH(); } - TARGET(PRECALL) { + TARGET_SAFE(PRECALL) { PREDICTED(PRECALL); /* Designed to work in tamdem with LOAD_METHOD. */ /* `meth` is NULL when LOAD_METHOD thinks that it's not @@ -4752,7 +4765,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(PRECALL_BOUND_METHOD) { + TARGET_SAFE(PRECALL_BOUND_METHOD) { DEOPT_IF(is_method(stack_pointer, oparg), PRECALL); PyObject *function = PEEK(oparg + 1); DEOPT_IF(Py_TYPE(function) != &PyMethod_Type, PRECALL); @@ -4768,7 +4781,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(PRECALL_PYFUNC) { + TARGET_SAFE(PRECALL_PYFUNC) { int nargs = oparg + is_method(stack_pointer, oparg); PyObject *function = PEEK(nargs + 1); DEOPT_IF(Py_TYPE(function) != &PyFunction_Type, PRECALL); @@ -4777,7 +4790,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(KW_NAMES) { + TARGET_SAFE(KW_NAMES) { assert(call_shape.kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(consts)); call_shape.kwnames = GETITEM(consts, oparg); @@ -5583,7 +5596,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(COPY) { + TARGET_SAFE(COPY) { assert(oparg != 0); PyObject *peek = PEEK(oparg); Py_INCREF(peek); @@ -5626,7 +5639,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } } - TARGET(SWAP) { + TARGET_SAFE(SWAP) { assert(oparg != 0); PyObject *top = TOP(); SET_TOP(PEEK(oparg)); @@ -5634,7 +5647,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(EXTENDED_ARG) { + TARGET_SAFE(EXTENDED_ARG) { assert(oparg); oparg <<= 8; oparg |= _Py_OPARG(*next_instr); @@ -5643,14 +5656,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH_GOTO(); } - TARGET(EXTENDED_ARG_QUICK) { + TARGET_SAFE(EXTENDED_ARG_QUICK) { assert(oparg); oparg <<= 8; oparg |= _Py_OPARG(*next_instr); NOTRACE_DISPATCH_SAME_OPARG(); } - TARGET(CACHE) { + TARGET_SAFE(CACHE) { Py_UNREACHABLE(); } From 5bb5601cb55eb06c89d8880d8cbb0a1f3050f639 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 1 May 2022 00:52:44 -0400 Subject: [PATCH 2/2] LOAD_DEREF isn't safe --- Python/ceval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/ceval.c b/Python/ceval.c index 7d572fade9205d..3664d20894e9aa 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3250,7 +3250,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET_SAFE(LOAD_DEREF) { + TARGET(LOAD_DEREF) { PyObject *cell = GETLOCAL(oparg); PyObject *value = PyCell_GET(cell); if (value == NULL) {