Skip to content

Assertion failure in instrumentation during interpreter finalization #110752

Closed
@gaogaotiantian

Description

@gaogaotiantian

Bug report

Bug description:

import sys

def f(*args):
    pass

def bar():
    yield 42

sys.settrace(f)

g = bar()
next(g)

The code above will trigger an assertion added in #109846.

python: Python/instrumentation.c:1576: _Py_Instrument: Assertion `(interp->ceval.eval_breaker & ~_PY_EVAL_EVENTS_MASK) == 0 || instrumentation_cross_checks(interp, code)' failed.
Aborted

The reason is that during the interpreter finalization, the global event monitors are reset to 0. However, the garbage collection triggered a send to the generator bar which then triggered _Py_Instrument.

is_version_up_to_date is true because the the code was instrumented when last time eval_breaker changed. However, instrumentation_cross_checks would fail, because interp->monitors is reset to 0.

Notice that in the code example above, if the trace function f returns itself rather than None, the assertion failure won't trigger because the generator would not be garbage collected - this might be an instrumentation bug that made the generator uncollectable (I've confirmed that _PyGen_Finalize and gen_close() never executed). However, I did not connect the dots so I don't know why that did not work.

I've made a simple patch in the PR, where I reset the interp->ceval.eval_breaker = 0 in interpreter_clear. It's kind of reasonable but I'm not knowledgeable enough to be confident that this is the/a correct fix.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.13bugs and security fixestype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions