Skip to content

Commit 1c38d89

Browse files
committed
Ensure consistency between BRANCH event offsets and co_branches.
1 parent 6b903b3 commit 1c38d89

File tree

4 files changed

+87
-5
lines changed

4 files changed

+87
-5
lines changed

Lib/test/test_monitoring.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,6 +1658,88 @@ def foo(n=0):
16581658
exit_loop])
16591659

16601660

1661+
class TestBranchConsistency(MonitoringTestBase, unittest.TestCase):
1662+
1663+
def check_branches(self, func, tool=TEST_TOOL, recorders=BRANCH_OFFSET_RECORDERS):
1664+
try:
1665+
self.assertEqual(sys.monitoring._all_events(), {})
1666+
event_list = []
1667+
all_events = 0
1668+
for recorder in recorders:
1669+
ev = recorder.event_type
1670+
sys.monitoring.register_callback(tool, ev, recorder(event_list))
1671+
all_events |= ev
1672+
sys.monitoring.set_local_events(tool, func.__code__, all_events)
1673+
func()
1674+
sys.monitoring.set_local_events(tool, func.__code__, 0)
1675+
for recorder in recorders:
1676+
sys.monitoring.register_callback(tool, recorder.event_type, None)
1677+
lefts = set()
1678+
rights = set()
1679+
for (src, left, right) in func.__code__.co_branches():
1680+
lefts.add((src, left))
1681+
rights.add((src, right))
1682+
for event in event_list:
1683+
way, _, src, dest = event
1684+
if "left" in way:
1685+
self.assertIn((src, dest), lefts)
1686+
else:
1687+
self.assertIn("right", way)
1688+
self.assertIn((src, dest), rights)
1689+
finally:
1690+
sys.monitoring.set_local_events(tool, func.__code__, 0)
1691+
for recorder in recorders:
1692+
sys.monitoring.register_callback(tool, recorder.event_type, None)
1693+
1694+
def test_simple(self):
1695+
1696+
def func():
1697+
x = 1
1698+
for a in range(2):
1699+
if a:
1700+
x = 4
1701+
else:
1702+
x = 6
1703+
7
1704+
1705+
self.check_branches(func)
1706+
1707+
def whilefunc(n=0):
1708+
while n < 3:
1709+
n += 1 # line 2
1710+
3
1711+
1712+
self.check_branches(whilefunc)
1713+
1714+
def test_except_star(self):
1715+
1716+
class Foo:
1717+
def meth(self):
1718+
pass
1719+
1720+
def func():
1721+
try:
1722+
try:
1723+
raise KeyError
1724+
except* Exception as e:
1725+
f = Foo(); f.meth()
1726+
except KeyError:
1727+
pass
1728+
1729+
1730+
self.check_branches(func)
1731+
1732+
def test4(self):
1733+
1734+
def foo(n=0):
1735+
while n<4:
1736+
pass
1737+
n += 1
1738+
return None
1739+
1740+
self.check_branches(foo)
1741+
1742+
16611743
class TestLoadSuperAttr(CheckEvents):
16621744
RECORDERS = CallRecorder, LineRecorder, CRaiseRecorder, CReturnRecorder
16631745

Python/bytecodes.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,6 @@ dummy_func(
362362
}
363363

364364
tier1 inst(INSTRUMENTED_POP_ITER, (iter -- )) {
365-
// Use `this_instr+1` instead of `next_instr` as the macro assigns next_instr`.
366-
(void)this_instr; // INSTRUMENTED_JUMP requires this_instr
367365
INSTRUMENTED_JUMP(prev_instr, this_instr+1, PY_MONITORING_EVENT_BRANCH_RIGHT);
368366
PyStackRef_CLOSE(iter);
369367
}

Python/generated_cases.c.h

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

Python/instrumentation.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3049,11 +3049,15 @@ branchesiter_next(branchesiterator *bi)
30493049
case EXTENDED_ARG:
30503050
oparg = (oparg << 8) | inst.op.arg;
30513051
break;
3052+
case FOR_ITER:
3053+
oparg = (oparg << 8) | inst.op.arg;
3054+
bi->bi_offset = next_offset;
3055+
int target = next_offset + oparg+2; // Skips END_FOR and POP_ITER
3056+
return int_triple(offset*2, next_offset*2, target*2);
30523057
case POP_JUMP_IF_FALSE:
30533058
case POP_JUMP_IF_TRUE:
30543059
case POP_JUMP_IF_NONE:
30553060
case POP_JUMP_IF_NOT_NONE:
3056-
case FOR_ITER:
30573061
oparg = (oparg << 8) | inst.op.arg;
30583062
/* Skip NOT_TAKEN */
30593063
int not_taken = next_offset + 1;

0 commit comments

Comments
 (0)