python / python/cpython

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

Ouverte
#149,498 6 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

stdlib
Langage dominant
Python
Étoiles
77.2k
Forks
35.9k
Métriques de merge des PR
Métriques de PR en attente

Description

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

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez par l’implémentation de FOR_ITER dans bytecodes.c et le point d’entrée de dis qui calcule les cibles de saut. Comparez la cible de l’itérateur épuisé décrite dans le rapport avec le comportement à l’exécution, puis ajoutez une couverture de régression montrant que la cible est POP_ITER plutôt que END_FOR.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
devtools
Type d'issue
Bug
Difficulté
3/5
Temps estimé
1-2 jours
Activité
À l'abandon
Clarté
Clairement spécifiée
Accessibilité débutants
35/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.