Skip to content

Deadlock when sentinel equality re-enters iterator via iter(callable, sentinel) #6589

@jackfromeast

Description

@jackfromeast

What happened?

PyCallableIterator::next keeps an upgradable read lock while comparing the callable result to the sentinel with vm.bool_eq. If the sentinel’s __eq__ calls next() on the same iterator (as in the PoC), the re-entrant next blocks on the same lock, hanging the interpreter instead of finishing iteration.

Proof of Concept:

class Evil:
    def __init__(self):
        self.it = None
    def __eq__(self, other):
        next(self.it)
        return True

evil = Evil()
itr = iter(lambda: evil, evil)
evil.it = itr
next(itr)
Affected Versions
RustPython Version Status Exit Code
Python 3.13.0alpha (heads/main-dirty:21300f689, Dec 13 2025, 22:16:49) [RustPython 0.4.0 with rustc 1.90.0-nightly (11ad40bb8 2025-06-28)] Deadlock 124
Vulnerable Code
fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
    let status = zelf.status.upgradable_read(); // holds the lock across user comparisons
    let next = if let IterStatus::Active(callable) = &*status {
        let ret = callable.invoke((), vm)?; // user callable returns a value that may be sentinel
        if vm.bool_eq(&ret, &zelf.sentinel)? { // runs sentinel.__eq__, which can call next() again
            *PyRwLockUpgradableReadGuard::upgrade(status) = IterStatus::Exhausted;
            PyIterReturn::StopIteration(None)
        } else {
            PyIterReturn::Return(ret)
        }
    } else {
        PyIterReturn::StopIteration(None)
    };
    Ok(next) // re-entrant next() blocks on the upgradable_read above, causing deadlock
}
Rust Output
Error: Execution timed out
CPython Output
Traceback (most recent call last):
  File "<string>", line 11, in <module>
StopIteration

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions