Single-threaded re-entrancy via a recursive generator causes an access violation (segfault) in `pairwise_next`
Personne n'a encore pris cette issue.
- Langage dominant
- Python
- Étoiles
- 77.2k
- Forks
- 35.9k
- Métriques de merge des PR
- Métriques de PR en attente
Description
Crash report
What happened?
The existing partial fix in main (the it = po->it; if (it == NULL) re-read guard after the first tp_iternext call) does not cover the second tp_iternext call, where it is still a borrowed reference. In the single-threaded case a re-entrant call can trigger Py_CLEAR(po->it) which drops the generator's refcount to zero and frees it, leaving the outer call's local it as a dangling pointer.
Minimal reproducer:
from itertools import pairwise
def g():
yield next(it)
for _ in range(10000):
try:
it = pairwise(g())
next(it)
except ValueError:
pass
Exception ignored in: <generator object g at 0x...>
ValueError: generator already executing
Windows fatal exception: access violation
This is also the root cause of https://github.com/spyder-ide/qtconsole/issues/635.
Some options to address:
Py_INCREF(it)before the secondtp_iternext(it)call +Py_DECREFafter, or- a re-entrancy guard flag (like
teedataobject.running) as suggested by @rhettinger.
Note: Py_BEGIN_CRITICAL_SECTION (added in PR #144489) does not protect against same-thread re-entrancy.
CPython versions tested on:
CPython main branch
Operating systems tested on:
No response
Output from running 'python -VV' on the command line:
No response
Linked PRs
- gh-150589
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Commencez par le point d’entrée pairwise_next et examinez le PR lié gh-150589 avec le reproducteur recursive-generator. Vérifiez que le deuxième appel à tp_iternext reste sûr lors de la réentrance dans le même thread, puis relancez le reproducteur pour confirmer qu’il ne provoque plus de violation d’accès.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- c, python
- Domaine
- backend
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- À l'abandon
- Clarté
- Clairement spécifiée
- Accessibilité débutants
- 25/100