Skip to content

Commit ada9651

Browse files
Prevent deinstrumenting INSTRUCTION from deinstrumenting LINE
1 parent 5bda2f6 commit ada9651

File tree

2 files changed

+36
-14
lines changed

2 files changed

+36
-14
lines changed

Lib/test/test_monitoring.py

+17
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,23 @@ def func1():
11521152
('instruction', 'func1', 14),
11531153
('line', 'get_events', 11)])
11541154

1155+
def test_turn_off_only_instruction(self):
1156+
"""
1157+
LINE events should be recorded after INSTRUCTION event is turned off
1158+
"""
1159+
events = []
1160+
def line(*args):
1161+
events.append("line")
1162+
sys.monitoring.set_events(TEST_TOOL, 0)
1163+
sys.monitoring.register_callback(TEST_TOOL, E.LINE, line)
1164+
sys.monitoring.register_callback(TEST_TOOL, E.INSTRUCTION, lambda *args: None)
1165+
sys.monitoring.set_events(TEST_TOOL, E.LINE | E.INSTRUCTION)
1166+
sys.monitoring.set_events(TEST_TOOL, E.LINE)
1167+
events = []
1168+
a = 0
1169+
sys.monitoring.set_events(TEST_TOOL, 0)
1170+
self.assertGreater(len(events), 0)
1171+
11551172
class TestInstallIncrementallly(MonitoringTestBase, unittest.TestCase):
11561173

11571174
def check_events(self, func, must_include, tool=TEST_TOOL, recorders=(ExceptionRecorder,)):

Python/instrumentation.c

+19-14
Original file line numberDiff line numberDiff line change
@@ -630,21 +630,26 @@ static void
630630
de_instrument_per_instruction(PyCodeObject *code, int i)
631631
{
632632
_Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
633-
uint8_t *opcode_ptr = &instr->op.code;
634-
int opcode =*opcode_ptr;
633+
int opcode = instr->op.code;
635634
if (opcode == INSTRUMENTED_LINE) {
636-
opcode_ptr = &code->_co_monitoring->lines[i].original_opcode;
637-
opcode = *opcode_ptr;
638-
}
639-
if (opcode != INSTRUMENTED_INSTRUCTION) {
640-
return;
641-
}
642-
int original_opcode = code->_co_monitoring->per_instruction_opcodes[i];
643-
CHECK(original_opcode != 0);
644-
CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]);
645-
instr->op.code = original_opcode;
646-
if (_PyOpcode_Caches[original_opcode]) {
647-
instr[1].cache = adaptive_counter_warmup();
635+
// We need to keep INSTRUMENTED_LINE when deinstrumenting INSTRUCTION
636+
opcode = code->_co_monitoring->lines[i].original_opcode;
637+
if (opcode != INSTRUMENTED_INSTRUCTION) {
638+
return;
639+
}
640+
code->_co_monitoring->lines[i].original_opcode =
641+
code->_co_monitoring->per_instruction_opcodes[i];
642+
} else {
643+
if (opcode != INSTRUMENTED_INSTRUCTION) {
644+
return;
645+
}
646+
int original_opcode = code->_co_monitoring->per_instruction_opcodes[i];
647+
CHECK(original_opcode != 0);
648+
CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]);
649+
instr->op.code = original_opcode;
650+
if (_PyOpcode_Caches[original_opcode]) {
651+
instr[1].cache = adaptive_counter_warmup();
652+
}
648653
}
649654
assert(instr->op.code != INSTRUMENTED_INSTRUCTION);
650655
/* Keep things clean for sanity check */

0 commit comments

Comments
 (0)