Skip to content

Existing INSTRUCTION callbacks can be dropped when a second monitoring tool is added #157900

Description

@HanpuLi

Bug description

Adding a second sys.monitoring tool can silently drop an existing tool's INSTRUCTION callbacks.

This reproduces on current main:

import sys

E = sys.monitoring.events
TOOL1 = 2
TOOL2 = 3
active = False
counts = [0, 0]

def callback1(code, offset):
    if active and code is f.__code__:
        counts[0] += 1

def callback2(code, offset):
    if active and code is f.__code__:
        counts[1] += 1

def f():
    global active
    sys.monitoring.set_local_events(TOOL2, f.__code__, E.INSTRUCTION)
    active = True
    value = 1
    value += 1
    active = False
    return value

sys.monitoring.use_tool_id(TOOL1, "tool1")
sys.monitoring.use_tool_id(TOOL2, "tool2")
sys.monitoring.register_callback(TOOL1, E.INSTRUCTION, callback1)
sys.monitoring.register_callback(TOOL2, E.INSTRUCTION, callback2)
sys.monitoring.set_events(TOOL1, E.INSTRUCTION)
f()
print(counts)

Expected both tools to see the same instructions. Actual output is:

[0, 8]

The transition from single-tool to multi-tool monitoring allocates per_instruction_tools, but the new table starts empty even at locations that are already instrumented for the existing tool. Once the table exists, instruction dispatch uses it instead of the global/local tool union, so the existing tool is lost at those locations.

This also shows up when sys.settrace() enables opcode tracing while another monitoring tool is active: the first opcode event is missed. I originally reduced this from coveragepy/coveragepy#2095.

CPython versions tested on

CPython main branch (b426caa), Python 3.15.0rc2, Python 3.14.7.

Operating systems tested on

macOS 27.0 arm64.

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)topic-profilingtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions