uvloop debug mode crashes on Python 3.14 during async generator finalization (traceback.walk_stack sees non-frame object)
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 48/100
Línea de trabajo
Comienza con cbhandles.pyx:extract_stack y el comportamiento de traceback.walk_stack en Python 3.14; después reproduce el fallo usando uvloop_python314_bug_repro.py con el modo de depuración habilitado. Sigue la finalización de los generadores asíncronos a través de call_soon_threadsafe y verifica que la reproducción termine correctamente sin un AttributeError ni un fallo de segmentación.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Overview
When an async generator is finalized under uvloop debug mode, uvloop’s extract_stack() calls traceback.walk_stack() on Python 3.14. The stack walker receives a non-frame object (e.g. _asyncio.TaskStepMethWrapper) and crashes (traceback.walk_stack_generator) or raises AttributeError. It's worth mentioning this does NOT happen with asyncio debug.
Environment
- uvloop 0.22.1
- Python 3.14.0
- macOS (Darwin 24.6.0, arm64)
- Debug mode enabled (PYTHONASYNCIODEBUG=1 or uvloop.run(debug=True))
Reproduction
- Set
PYTHONFAULTHANDLER=1 PYTHONASYNCIODEBUG=1as environment variables. - Run the following script with
python3 uvloop_python314_bug_repro.py
"""uvloop_python314_bug_repro.py
Minimal repro: uvloop 0.22.1 + Python 3.14 debug async-gen finalization crash.
This creates a nested async-generator chain and breaks on a "[DONE]" sentinel
without closing the inner iterator. Under uvloop debug, async generator
finalization schedules aclose() via call_soon_threadsafe, which calls
extract_stack(). On Python 3.14, traceback.walk_stack sees a non-frame object
(for example, _asyncio.TaskStepMethWrapper) and raises AttributeError. The
unpatched build can segfault in traceback.walk_stack_generator.
Run:
uv run --active --no-sync python uvloop_python314_bug_repro.py
"""
from __future__ import annotations
import asyncio
import gc
import os
import sys
from typing import AsyncIterator
import uvloop
os.environ["PYTHONASYNCIODEBUG"] = "1"
REPEATS = 1
class FakeResponse:
async def aiter_raw(self) -> AsyncIterator[bytes]:
payloads = [
b"data: one\n\n",
b"data: [DONE]\n\n",
b"data: trailing\n\n",
]
for payload in payloads:
yield payload
await asyncio.sleep(0)
async def aclose(self) -> None:
await asyncio.sleep(0)
class Decoder:
async def _aiter_chunks(self, source: AsyncIterator[bytes]) -> AsyncIterator[bytes]:
async for chunk in source:
yield chunk
async def aiter_bytes(self, source: AsyncIterator[bytes]) -> AsyncIterator[str]:
async for chunk in self._aiter_chunks(source):
for line in chunk.splitlines():
yield line.decode("utf-8")
class AsyncStream:
def __init__(self) -> None:
self.response = FakeResponse()
self.decoder = Decoder()
self._iterator: AsyncIterator[str] = self.__stream__()
def __aiter__(self) -> AsyncIterator[str]:
return self._iterator
async def __stream__(self) -> AsyncIterator[str]:
iterator = self._iter_events()
try:
async for event in iterator:
if event.endswith("[DONE]"):
break
yield event
finally:
await self.response.aclose()
async def _iter_events(self) -> AsyncIterator[str]:
async for event in self.decoder.aiter_bytes(self.response.aiter_raw()):
yield event
async def exercise_once() -> None:
stream = AsyncStream()
async for _ in stream:
pass
del stream
gc.collect()
await asyncio.sleep(0)
async def main() -> None:
loop = asyncio.get_running_loop()
print(f"Python: {sys.version}")
print(f"Loop: {type(loop).__name__}")
print(f"Debug: {loop.get_debug()}")
for _ in range(REPEATS):
await exercise_once()
await asyncio.sleep(0.1)
if __name__ == "__main__":
print(f"uvloop: {uvloop.__version__}")
uvloop.run(main(), debug=True)
Expected
Clean exit (debug stack capture should never crash the process).
Actual
Fatal Python error: Segmentation fault
File ".../traceback.py", line 393 in walk_stack_generator
...
Ideas
Python 3.14 changed frame introspection behavior. During async generator finalization, uvloop's debug stack capture (cbhandles.pyx:extract_stack) calls traceback.walk_stack(). The stack can contain non-frame objects like _asyncio.TaskStepMethWrapper which lack the f_back attribute that walk_stack_generator expects.
The crash path:
- Async generator breaks early (e.g., on
[DONE]sentinel) - GC finalizes the generator
- Finalizer schedules
aclose()viacall_soon_threadsafe - uvloop debug captures stack →
traceback.walk_stack()→ crash
This happens during async generator finalization; the finalizer schedules aclose() via call_soon_threadsafe, which triggers uvloop’s debug stack capture. A defensive guard before calling traceback.walk_stack (e.g. require a real frame, or swallow AttributeError/TypeError) avoids the crash.
Workaround
Explicitly close/break async generator chains before they go out of scope, or disable uvloop debug mode on Python 3.14.
- Lenguaje dominante
- Cython
- Estrellas
- 11.9k
- Forks
- 615
- Métricas de merge de PR
- Sin PR fusionados en 30 d
Guía de contribución
No hay ninguna guía de contribución indexada para este repositorio
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de MagicStack/uvloop
-
License not clear Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
MagicStack/uvloop#759 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
MagicStack/uvloop#741 · 2 reacciones ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
MagicStack/uvloop#702 · 8 comentarios · 9 reacciones ·
-
Dificultad 4/5 3-5 días Aptitud para principiantes 25/100
MagicStack/uvloop#766 ·
-
Directly constructed subprocess pipe protocols segfault when callbacks use a non-process owner Abierto
Dificultad 4/5 3-5 días Aptitud para principiantes 52/100
MagicStack/uvloop#765 ·
Todos los issues de MagicStack/uvloop
Issues similares
-
bug customer-eng Durable Agents Inngest status: needs triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
-
integration: elevenlabs
Dificultad 1/5 Menos de una hora Aptitud para principiantes 88/100
home-assistant/core#182944 · 1 comentario ·
-
ai-observability bug team/ai-observability
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
vicharanashala/fln#563 ·