Skip to content

Commit 6b903b3

Browse files
committed
Fix handling of branch events not from source instruction
1 parent 592e328 commit 6b903b3

File tree

6 files changed

+37
-33
lines changed

6 files changed

+37
-33
lines changed

Include/internal/pycore_instruments.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ _Py_call_instrumentation_instruction(
4848

4949
_Py_CODEUNIT *
5050
_Py_call_instrumentation_jump(
51-
PyThreadState *tstate, int event,
52-
_PyInterpreterFrame *frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *target);
51+
_Py_CODEUNIT *instr, PyThreadState *tstate, int event,
52+
_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest);
5353

5454
extern int
5555
_Py_call_instrumentation_arg(PyThreadState *tstate, int event,

Python/bytecodes.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,12 +358,12 @@ dummy_func(
358358
ERROR_NO_POP();
359359
}
360360
}
361-
frame->instr_ptr = prev_instr;
362361
DECREF_INPUTS();
363362
}
364363

365364
tier1 inst(INSTRUMENTED_POP_ITER, (iter -- )) {
366365
// Use `this_instr+1` instead of `next_instr` as the macro assigns next_instr`.
366+
(void)this_instr; // INSTRUMENTED_JUMP requires this_instr
367367
INSTRUMENTED_JUMP(prev_instr, this_instr+1, PY_MONITORING_EVENT_BRANCH_RIGHT);
368368
PyStackRef_CLOSE(iter);
369369
}
@@ -4789,6 +4789,7 @@ dummy_func(
47894789
}
47904790

47914791
inst(INSTRUMENTED_NOT_TAKEN, ( -- )) {
4792+
(void)this_instr; // INSTRUMENTED_JUMP requires this_instr
47924793
INSTRUMENTED_JUMP(prev_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT);
47934794
}
47944795

Python/ceval_macros.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ do { \
363363
next_instr = dest; \
364364
} else { \
365365
_PyFrame_SetStackPointer(frame, stack_pointer); \
366-
next_instr = _Py_call_instrumentation_jump(tstate, event, frame, src, dest); \
366+
next_instr = _Py_call_instrumentation_jump(this_instr, tstate, event, frame, src, dest); \
367367
stack_pointer = _PyFrame_GetStackPointer(frame); \
368368
if (next_instr == NULL) { \
369369
next_instr = (dest)+1; \

Python/codegen.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2017,9 +2017,7 @@ codegen_for(compiler *c, stmt_ty s)
20172017
* Iteration over a generator will jump to the first of these instructions,
20182018
* but a non-generator will jump to a later instruction.
20192019
*/
2020-
/* Branches *to* the POP_ITER must come from the same location as the FOR_ITER.
2021-
* So, the END_FOR must have the same location as the FOR_ITER. */
2022-
ADDOP(c, loc, END_FOR);
2020+
ADDOP(c, NO_LOCATION, END_FOR);
20232021
ADDOP(c, NO_LOCATION, POP_ITER);
20242022

20252023
_PyCompile_PopFBlock(c, COMPILE_FBLOCK_FOR_LOOP, start);
@@ -4284,7 +4282,7 @@ codegen_sync_comprehension_generator(compiler *c, location loc,
42844282
* Iteration over a generator will jump to the first of these instructions,
42854283
* but a non-generator will jump to a later instruction.
42864284
*/
4287-
ADDOP(c, LOC(gen->iter), END_FOR);
4285+
ADDOP(c, NO_LOCATION, END_FOR);
42884286
ADDOP(c, NO_LOCATION, POP_ITER);
42894287
}
42904288

Python/generated_cases.c.h

Lines changed: 4 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/instrumentation.c

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,8 +1083,8 @@ static const char *const event_names [] = {
10831083

10841084
static int
10851085
call_instrumentation_vector(
1086-
PyThreadState *tstate, int event,
1087-
_PyInterpreterFrame *frame, _Py_CODEUNIT *instr, Py_ssize_t nargs, PyObject *args[])
1086+
_Py_CODEUNIT *instr, PyThreadState *tstate, int event,
1087+
_PyInterpreterFrame *frame, _Py_CODEUNIT *arg2, Py_ssize_t nargs, PyObject *args[])
10881088
{
10891089
if (tstate->tracing) {
10901090
return 0;
@@ -1097,13 +1097,13 @@ call_instrumentation_vector(
10971097
int offset = (int)(instr - _PyFrame_GetBytecode(frame));
10981098
/* Offset visible to user should be the offset in bytes, as that is the
10991099
* convention for APIs involving code offsets. */
1100-
int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT);
1101-
PyObject *offset_obj = PyLong_FromLong(bytes_offset);
1102-
if (offset_obj == NULL) {
1100+
int bytes_arg2 = (int)(arg2 - _PyFrame_GetBytecode(frame)) * (int)sizeof(_Py_CODEUNIT);
1101+
PyObject *arg2_obj = PyLong_FromLong(bytes_arg2);
1102+
if (arg2_obj == NULL) {
11031103
return -1;
11041104
}
11051105
assert(args[2] == NULL);
1106-
args[2] = offset_obj;
1106+
args[2] = arg2_obj;
11071107
PyInterpreterState *interp = tstate->interp;
11081108
uint8_t tools = get_tools_for_instruction(code, interp, offset, event);
11091109
size_t nargsf = (size_t) nargs | PY_VECTORCALL_ARGUMENTS_OFFSET;
@@ -1141,7 +1141,7 @@ call_instrumentation_vector(
11411141
}
11421142
}
11431143
}
1144-
Py_DECREF(offset_obj);
1144+
Py_DECREF(arg2_obj);
11451145
return err;
11461146
}
11471147

@@ -1151,7 +1151,7 @@ _Py_call_instrumentation(
11511151
_PyInterpreterFrame *frame, _Py_CODEUNIT *instr)
11521152
{
11531153
PyObject *args[3] = { NULL, NULL, NULL };
1154-
return call_instrumentation_vector(tstate, event, frame, instr, 2, args);
1154+
return call_instrumentation_vector(instr, tstate, event, frame, instr, 2, args);
11551155
}
11561156

11571157
int
@@ -1160,7 +1160,7 @@ _Py_call_instrumentation_arg(
11601160
_PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg)
11611161
{
11621162
PyObject *args[4] = { NULL, NULL, NULL, arg };
1163-
return call_instrumentation_vector(tstate, event, frame, instr, 3, args);
1163+
return call_instrumentation_vector(instr, tstate, event, frame, instr, 3, args);
11641164
}
11651165

11661166
int
@@ -1169,25 +1169,25 @@ _Py_call_instrumentation_2args(
11691169
_PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1)
11701170
{
11711171
PyObject *args[5] = { NULL, NULL, NULL, arg0, arg1 };
1172-
return call_instrumentation_vector(tstate, event, frame, instr, 4, args);
1172+
return call_instrumentation_vector(instr, tstate, event, frame, instr, 4, args);
11731173
}
11741174

11751175
_Py_CODEUNIT *
11761176
_Py_call_instrumentation_jump(
1177-
PyThreadState *tstate, int event,
1178-
_PyInterpreterFrame *frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *target)
1177+
_Py_CODEUNIT *instr, PyThreadState *tstate, int event,
1178+
_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest)
11791179
{
11801180
assert(event == PY_MONITORING_EVENT_JUMP ||
11811181
event == PY_MONITORING_EVENT_BRANCH_RIGHT ||
11821182
event == PY_MONITORING_EVENT_BRANCH_LEFT);
1183-
int to = (int)(target - _PyFrame_GetBytecode(frame));
1183+
int to = (int)(dest - _PyFrame_GetBytecode(frame));
11841184
PyObject *to_obj = PyLong_FromLong(to * (int)sizeof(_Py_CODEUNIT));
11851185
if (to_obj == NULL) {
11861186
return NULL;
11871187
}
11881188
PyObject *args[4] = { NULL, NULL, NULL, to_obj };
11891189
_Py_CODEUNIT *instr_ptr = frame->instr_ptr;
1190-
int err = call_instrumentation_vector(tstate, event, frame, instr, 3, args);
1190+
int err = call_instrumentation_vector(instr, tstate, event, frame, src, 3, args);
11911191
Py_DECREF(to_obj);
11921192
if (err) {
11931193
return NULL;
@@ -1196,7 +1196,7 @@ _Py_call_instrumentation_jump(
11961196
/* The callback has caused a jump (by setting the line number) */
11971197
return frame->instr_ptr;
11981198
}
1199-
return target;
1199+
return dest;
12001200
}
12011201

12021202
static void
@@ -1206,7 +1206,7 @@ call_instrumentation_vector_protected(
12061206
{
12071207
assert(_PyErr_Occurred(tstate));
12081208
PyObject *exc = _PyErr_GetRaisedException(tstate);
1209-
int err = call_instrumentation_vector(tstate, event, frame, instr, nargs, args);
1209+
int err = call_instrumentation_vector(instr, tstate, event, frame, instr, nargs, args);
12101210
if (err) {
12111211
Py_XDECREF(exc);
12121212
}
@@ -1498,9 +1498,10 @@ initialize_lines(PyCodeObject *code)
14981498
case END_FOR:
14991499
case END_SEND:
15001500
case RESUME:
1501+
case POP_ITER:
15011502
/* END_FOR cannot start a line, as it is skipped by FOR_ITER
15021503
* END_SEND cannot start a line, as it is skipped by SEND
1503-
* RESUME must not be instrumented with INSTRUMENT_LINE */
1504+
* RESUME and POP_ITER must not be instrumented with INSTRUMENT_LINE */
15041505
line_data[i].original_opcode = 0;
15051506
break;
15061507
default:
@@ -1572,11 +1573,14 @@ initialize_lines(PyCodeObject *code)
15721573
}
15731574
assert(target >= 0);
15741575
if (line_data[target].line_delta != NO_LINE) {
1575-
line_data[target].original_opcode = _Py_GetBaseCodeUnit(code, target).op.code;
1576-
if (line_data[target].line_delta == COMPUTED_LINE_LINENO_CHANGE) {
1577-
// If the line is a jump target, we are not sure if the line
1578-
// number changes, so we set it to COMPUTED_LINE.
1579-
line_data[target].line_delta = COMPUTED_LINE;
1576+
int opcode = _Py_GetBaseCodeUnit(code, target).op.code;
1577+
if (opcode != POP_ITER) {
1578+
line_data[target].original_opcode = opcode;
1579+
if (line_data[target].line_delta == COMPUTED_LINE_LINENO_CHANGE) {
1580+
// If the line is a jump target, we are not sure if the line
1581+
// number changes, so we set it to COMPUTED_LINE.
1582+
line_data[target].line_delta = COMPUTED_LINE;
1583+
}
15801584
}
15811585
}
15821586
}

0 commit comments

Comments
 (0)