itertools.count use-after-free via re-entrant step.__radd__
还没有人认领这个 Issue。
- 主要语言
- Python
- 星标
- 77.2k
- 派生
- 35.9k
- PR 合并指标
- PR 指标待抓取
描述
Bug description
itertools.count has a use-after-free when the step object's __radd__ re-enters the iterator.
count_nextlong() borrows lz->long_cnt (the running total) without Py_INCREF, then calls PyNumber_Add(result, step). If step.__radd__ calls next() on the same count, the inner call moves lz->long_cnt to the new value and hands the old total's only reference back, which is then dropped and freed. The outer call still returns that freed total as a dangling pointer.
The step needs __index__ so count() accepts it as a number, and the returned value has to be used to hit the freed memory:
from itertools import count
class Step:
armed = True
def __index__(self): # so count() accepts it as a number
return 1
def __radd__(self, other):
if Step.armed:
Step.armed = False
inner = next(c) # re-enter; steals the running total's ref
f"{inner!r}" # churn the heap so the freed slot is reused
return other + 1
c = count(1 << 100, Step())
val = next(c)
val + 1 # use the returned (dangling) total
Run with PYTHONMALLOC=debug python repro.py -> SIGSEGV. With the fix it prints the correct value.
CPython versions tested on
main
Operating systems tested on
macOS
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
首先,跟踪报告中描述的 count_nextlong() 路径,并使用 PYTHONMALLOC=debug 运行提供的 reproducer。调查可重入的 next() 调用以及运行总计周围的引用生命周期;当 reproducer 在不崩溃的情况下打印出正确值时,工作即完成。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- c, python
- 领域
- backend
- Issue 类型
- 缺陷
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 活跃度
- 冷清
- 描述清晰度
- 基本清楚
- 新手友好度
- 52/100