Skip to content

asyncio: FutureIter_dealloc() crashes with negative refcount #122695

@douglas-raillard-arm

Description

@douglas-raillard-arm

Crash report

What happened?

This is not a standalone reproducer as I'm still working on that, but the code triggering it is:

 @classmethod def _get_referred_objs(cls, obj, predicate=lambda x: True): visited = set() objs = [] def update_refs(obj): obj_id = id(obj) # Avoid cycles. Use the id() of the objects directly since the # inclusion check is orders of magnitude faster than checking for # inclusing on the object directly. It also handles well non hashable # objects and broken __eq__ implementations. if obj_id in visited: return else: visited.add(obj_id) # Filter-out weird objects that end up in the list and that can # trigger a coredump on the interpreter with warnings.catch_warnings(): warnings.simplefilter("ignore") has_class = hasattr(obj, '__class__') if has_class and predicate(obj): objs.append(obj) for sub in gc.get_referents(obj): update_refs(sub) update_refs(obj) return objs

The issue was triggered on Gentoo on an arm64 machine. For some reason, this works fine on x86-64. I then managed to trigger it again under a different Python 3.12.4 interpreter compiled from the git repo with debug symbols to get a gdb backtrace:

#6 0x0000aaaaaadfd4a0 in _PyObject_AssertFailed (obj=obj@entry=<_asyncio.FutureIter at remote 0xfffff210b3d0>, expr=expr@entry=0x0, msg=msg@entry=0xaaaaaaea5c50 "object has negative ref count", file=<optimized out>, line=<optimized out>, function=function@entry=0xaaaaaaed4928 <__func__.44.lto_priv.1> "_Py_NegativeRefcount") at Objects/object.c:2603 #7 0x0000aaaaaadfd550 in _Py_NegativeRefcount (filename=<optimized out>, lineno=<optimized out>, op=op@entry=<_asyncio.FutureIter at remote 0xfffff210b3d0>) at Objects/object.c:209 #8 0x0000fffff5df4bb0 in Py_DECREF (filename=filename@entry=0xfffff5dfba58 "./Modules/_asynciomodule.c", lineno=lineno@entry=1764, op=<_asyncio.FutureIter at remote 0xfffff210b3d0>) at ./Include/object.h:682 #9 0x0000fffff5df59a0 in FutureIter_clear (it=<optimized out>) at ./Modules/_asynciomodule.c:1764 #10 0x0000fffff5dfb57c in FutureIter_dealloc (it=0xfffff2109f50) at ./Modules/_asynciomodule.c:1601 #11 0x0000aaaaaabc9658 in _Py_Dealloc (op=op@entry=<_asyncio.FutureIter at remote 0xfffff2109f50>) at Objects/object.c:2625 #12 0x0000aaaaaabc9acc in Py_DECREF (filename=filename@entry=0xaaaaaae65f90 "./Include/object.h", lineno=lineno@entry=798, op=<_asyncio.FutureIter at remote 0xfffff2109f50>) at ./Include/object.h:690 #13 0x0000aaaaaabc9a68 in Py_XDECREF (op=<optimized out>) at ./Include/object.h:798 #14 0x0000aaaaaabc9780 in list_dealloc (op=0xffffdd2bc5a0) at Objects/listobject.c:356 #15 0x0000aaaaaabc9658 in _Py_Dealloc ( 

The Python backtrace at this point was deeply recursed in update_refs().

CPython versions tested on:

3.12

Operating systems tested on:

Linux

Output from running 'python -VV' on the command line:

Python 3.12.4 (tags/v3.12.4:8e8a4baf652, Aug 2 2024, 18:22:31) [GCC 13.3.1 20240614]

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.12only security fixestopic-asynciotype-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions