Single-threaded re-entrancy via a recursive generator causes an access violation (segfault) in `pairwise_next`
還沒有人認領這個 Issue。
- 主要語言
- Python
- 星號
- 77.2k
- 分支
- 35.9k
- PR 合併指標
- PR 指標待擷取
描述
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
貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
研究方向
從 pairwise_next 入口點開始,結合 recursive-generator 重現程式檢查關聯的 PR gh-150589。驗證第二次 tp_iternext 呼叫在同一執行緒重入期間仍然安全,並重新執行重現程式以確認它不再導致存取違規。
由索引模型根據 Issue 內容生成。
評估
- 技術堆疊
- c, python
- 領域
- backend
- Issue 類型
- 缺陷
- 難度
- 4/5
- 預估耗時
- 3-5 天
- 活躍度
- 停滯
- 描述清晰度
- 描述清楚
- 新手友好度
- 25/100