Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit bcea36f

Browse filesBrowse files
gh-103845: Remove line & instruction instrumentations before adding them back (GH-103851)
1 parent 0a5cd98 commit bcea36f
Copy full SHA for bcea36f

File tree

Expand file treeCollapse file tree

3 files changed

+70
-8
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+70
-8
lines changed

‎Lib/test/test_monitoring.py

Copy file name to clipboardExpand all lines: Lib/test/test_monitoring.py
+36Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,42 @@ def func3():
876876
('instruction', 'func3', 34),
877877
('line', 'check_events', 11)])
878878

879+
def test_with_restart(self):
880+
def func1():
881+
line1 = 1
882+
line2 = 2
883+
line3 = 3
884+
885+
self.check_events(func1, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [
886+
('line', 'check_events', 10),
887+
('line', 'func1', 1),
888+
('instruction', 'func1', 2),
889+
('instruction', 'func1', 4),
890+
('line', 'func1', 2),
891+
('instruction', 'func1', 6),
892+
('instruction', 'func1', 8),
893+
('line', 'func1', 3),
894+
('instruction', 'func1', 10),
895+
('instruction', 'func1', 12),
896+
('instruction', 'func1', 14),
897+
('line', 'check_events', 11)])
898+
899+
sys.monitoring.restart_events()
900+
901+
self.check_events(func1, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [
902+
('line', 'check_events', 10),
903+
('line', 'func1', 1),
904+
('instruction', 'func1', 2),
905+
('instruction', 'func1', 4),
906+
('line', 'func1', 2),
907+
('instruction', 'func1', 6),
908+
('instruction', 'func1', 8),
909+
('line', 'func1', 3),
910+
('instruction', 'func1', 10),
911+
('instruction', 'func1', 12),
912+
('instruction', 'func1', 14),
913+
('line', 'check_events', 11)])
914+
879915
class TestInstallIncrementallly(MonitoringTestBase, unittest.TestCase):
880916

881917
def check_events(self, func, must_include, tool=TEST_TOOL, recorders=(ExceptionRecorder,)):
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove both line and instruction instrumentation before adding new ones for monitoring, to avoid newly added instrumentation being removed immediately.

‎Python/instrumentation.c

Copy file name to clipboardExpand all lines: Python/instrumentation.c
+33-8Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,25 +1477,25 @@ _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp)
14771477
}
14781478
}
14791479
}
1480-
uint8_t new_line_tools = new_events.tools[PY_MONITORING_EVENT_LINE];
1480+
1481+
// GH-103845: We need to remove both the line and instruction instrumentation before
1482+
// adding new ones, otherwise we may remove the newly added instrumentation.
1483+
14811484
uint8_t removed_line_tools = removed_events.tools[PY_MONITORING_EVENT_LINE];
1482-
if (new_line_tools | removed_line_tools) {
1485+
uint8_t removed_per_instruction_tools = removed_events.tools[PY_MONITORING_EVENT_INSTRUCTION];
1486+
1487+
if (removed_line_tools) {
14831488
_PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines;
14841489
for (int i = code->_co_firsttraceable; i < code_len;) {
14851490
if (line_data[i].original_opcode) {
14861491
if (removed_line_tools) {
14871492
remove_line_tools(code, i, removed_line_tools);
14881493
}
1489-
if (new_line_tools) {
1490-
add_line_tools(code, i, new_line_tools);
1491-
}
14921494
}
14931495
i += instruction_length(code, i);
14941496
}
14951497
}
1496-
uint8_t new_per_instruction_tools = new_events.tools[PY_MONITORING_EVENT_INSTRUCTION];
1497-
uint8_t removed_per_instruction_tools = removed_events.tools[PY_MONITORING_EVENT_INSTRUCTION];
1498-
if (new_per_instruction_tools | removed_per_instruction_tools) {
1498+
if (removed_per_instruction_tools) {
14991499
for (int i = code->_co_firsttraceable; i < code_len;) {
15001500
int opcode = _Py_GetBaseOpcode(code, i);
15011501
if (opcode == RESUME || opcode == END_FOR) {
@@ -1505,6 +1505,31 @@ _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp)
15051505
if (removed_per_instruction_tools) {
15061506
remove_per_instruction_tools(code, i, removed_per_instruction_tools);
15071507
}
1508+
i += instruction_length(code, i);
1509+
}
1510+
}
1511+
1512+
uint8_t new_line_tools = new_events.tools[PY_MONITORING_EVENT_LINE];
1513+
uint8_t new_per_instruction_tools = new_events.tools[PY_MONITORING_EVENT_INSTRUCTION];
1514+
1515+
if (new_line_tools) {
1516+
_PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines;
1517+
for (int i = code->_co_firsttraceable; i < code_len;) {
1518+
if (line_data[i].original_opcode) {
1519+
if (new_line_tools) {
1520+
add_line_tools(code, i, new_line_tools);
1521+
}
1522+
}
1523+
i += instruction_length(code, i);
1524+
}
1525+
}
1526+
if (new_per_instruction_tools) {
1527+
for (int i = code->_co_firsttraceable; i < code_len;) {
1528+
int opcode = _Py_GetBaseOpcode(code, i);
1529+
if (opcode == RESUME || opcode == END_FOR) {
1530+
i += instruction_length(code, i);
1531+
continue;
1532+
}
15081533
if (new_per_instruction_tools) {
15091534
add_per_instruction_tools(code, i, new_per_instruction_tools);
15101535
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.