python / python/cpython

dis: FOR_ITER reports wrong exhausted-path jump target (END_FOR instead of POP_ITER)

Offen
#149,498 6 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

stdlib
Vorherrschende Sprache
Python
Sterne
77.2k
Forks
35.9k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

Bug Report

Bug description:

In Python 3.15, dis reports the wrong jump target for FOR_ITER when the iterator is exhausted. The reported target lands on END_FOR, but the CPython runtime actually jumps one instruction past it to POP_ITER.

Root cause: In bytecodes.c, FOR_ITER uses JUMPBY(oparg + 1) to skip past END_FOR. However, dis computes the jump target as NIP + oparg * 2 bytes (without the +1), landing on END_FOR rather than POP_ITER.

import dis

def f():
    for x in [1, 2, 3]:
        pass

instrs = {i.offset: i for i in dis.get_instructions(f.__code__, show_caches=True)}

for i in dis.get_instructions(f.__code__):
    if i.opname == "FOR_ITER":
        for_iter = i

# dis reports this as the jump target:
reported_target = for_iter.jump_target
reported_name = instrs[reported_target].opname  # "END_FOR"

# CPython runtime actually jumps here (oparg+1 instructions past NIP):
nip = for_iter.offset + 4  # 4 bytes = FOR_ITER word + CACHE word
actual_target = nip + (for_iter.arg + 1) * 2
actual_name = instrs[actual_target].opname  # "POP_ITER"

print(f"dis reports:    offset {reported_target} = {reported_name}")   # END_FOR
print(f"runtime jumps:  offset {actual_target}   = {actual_name}")     # POP_ITER

Output:

dis reports:    offset 20 = END_FOR
runtime jumps:  offset 22 = POP_ITER

The stack-effect model remains self-consistent (FOR_ITER +1, END_FOR -1, POP_ITER -2), but the reported jump target is misleading to any tool that builds a control-flow graph from dis output. The exhausted-iterator edge should point to POP_ITER, not END_FOR.

CPython versions tested on:

CPython main branch (3.15)

Operating systems tested on:

macOS

Linked PRs
  • gh-149503

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne mit der FOR_ITER-Implementierung in bytecodes.c und dem dis-Einstiegspunkt, der Sprungziele berechnet. Vergleiche das im Bericht beschriebene Ziel für erschöpfte Iteratoren mit dem Laufzeitverhalten und füge anschließend Regressionstestabdeckung hinzu, die zeigt, dass das Ziel POP_ITER statt END_FOR ist.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
devtools
Issue-Typ
Bug
Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Aktivitätsstatus
Veraltet
Klarheit
Klar beschrieben
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.