python / python/cpython

`NULL` pointer dereference in `FutureIter_am_send`

Abierto
#146,065 2 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

extension-modules topic-asyncio type-crash
Lenguaje dominante
Python
Estrellas
77.2k
Forks
35.9k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

Crash report

What happened?

It's possible to segfault the interpreter by running the MRE below.

Automated diagnosis:

Bug: NULL pointer dereference in FutureIter_am_send (_asynciomodule.c:1877). FutureIter_am_send passes it->future to Py_BEGIN_CRITICAL_SECTION() without checking for NULL. FutureIter_throw (line 1973) and FutureIter_close (line 1997) both call Py_CLEAR(self->future), setting it->future = NULL. After throw() or close(), any subsequent send()/next() dereferences NULL.

Fix: Add NULL check at the top of FutureIter_am_send:

    if (it->future == NULL) {
        PyErr_SetNone(PyExc_StopIteration);
        *result = NULL;
        return PYGEN_RETURN;
    }

MRE:

import asyncio

async def exploit():
    loop = asyncio.get_event_loop()
    fut = loop.create_future()

    it = fut.__await__()
    it.__next__()       # yields the future, sets fut_blocking

    try:
        it.throw(RuntimeError)  # Py_CLEAR(self->future) -> NULL
    except RuntimeError:
        pass

    it.send(None)       # SEGFAULT: Py_BEGIN_CRITICAL_SECTION(NULL)

asyncio.run(exploit())

Backtrace:

Program received signal SIGSEGV, Segmentation fault.
0x00005555560eb282 in FutureIter_am_send_lock_held (it=0x7c5ff71cf700, result=<optimized out>) at ./Modules/_asynciomodule.c:1849
1849        if (fut->fut_state == STATE_PENDING) {
(gdb) bt
#0  0x00005555560eb282 in FutureIter_am_send_lock_held (it=0x7c5ff71cf700, result=<optimized out>) at ./Modules/_asynciomodule.c:1849
#1  FutureIter_am_send (op=0x7c5ff71cf700, _unused_arg=<optimized out>, result=<optimized out>) at ./Modules/_asynciomodule.c:1878
#2  FutureIter_iternext (it=0x7c5ff71cf700) at ./Modules/_asynciomodule.c:1888
#3  0x0000555555ae6c75 in method_vectorcall_O (func=func@entry=0x7c7ff7322040, args=args@entry=0x7bfff5d36b28, nargsf=nargsf@entry=9223372036854775810, kwnames=kwnames@entry=0x0)
    at Objects/descrobject.c:476
#4  0x0000555555ab9e00 in _PyObject_VectorcallTstate (tstate=0x5555568f7b18 <_PyRuntime+360664>, callable=0x7c7ff7322040, args=0x7bfff5d36b28, nargsf=9223372036854775810, kwnames=0x0)
    at ./Include/internal/pycore_call.h:136
#5  0x0000555555e588dd in _Py_VectorCallInstrumentation_StackRefSteal (callable=..., arguments=<optimized out>, total_args=2, kwnames=..., call_instrumentation=<optimized out>,
    frame=<optimized out>, this_instr=<optimized out>, tstate=<optimized out>) at Python/ceval.c:770
#6  0x0000555555e94263 in _PyEval_EvalFrameDefault (tstate=<optimized out>, frame=<optimized out>, throwflag=<optimized out>) at Python/generated_cases.c.h:1838
#7  0x0000555555b1f1bb in _PyEval_EvalFrame (tstate=0x5555568f7b18 <_PyRuntime+360664>, frame=0x7d0ff724c828, throwflag=0) at ./Include/internal/pycore_ceval.h:118
#8  gen_send_ex2 (gen=0x7d0ff724c7e0, arg=0x5555566bcfa0 <_Py_NoneStruct>, presult=0x7bfff5d36380, exc=0) at Objects/genobject.c:280
#9  0x0000555555a6cefc in PyIter_Send (iter=<optimized out>, arg=0x5555566bcfa0 <_Py_NoneStruct>, result=<optimized out>) at Objects/abstract.c:2936
#10 0x00005555560e584a in task_step_impl (state=<optimized out>, task=0x7d4ff704b3b0, exc=0x0) at ./Modules/_asynciomodule.c:3100
#11 0x00005555560e5033 in task_step (state=state@entry=0x7cfff7122d50, task=0x7d4ff704b3b0, exc=0x0) at ./Modules/_asynciomodule.c:3442
#12 0x00005555560e4977 in TaskStepMethWrapper_call (op=0x7c6ff76084d0, args=0x5555568c0b50 <_PyRuntime+135440>, kwds=0x0) at ./Modules/_asynciomodule.c:2112
#13 0x0000555555aba90b in _PyObject_MakeTpCall (tstate=tstate@entry=0x5555568f7b18 <_PyRuntime+360664>, callable=callable@entry=0x7c6ff76084d0, args=0x7c6ff70b2c38, nargs=0,
    keywords=keywords@entry=0x0) at Objects/call.c:242
#14 0x0000555555f165c8 in _PyObject_VectorcallTstate (tstate=0x5555568f7b18 <_PyRuntime+360664>, callable=0x7c6ff76084d0, args=0x7fffffffff01, nargsf=<optimized out>, kwnames=0x0)
    at ./Include/internal/pycore_call.h:134
#15 context_run (self=0x7c7ff737bec0, args=args@entry=0x7c6ff70b2c30, nargs=nargs@entry=1, kwnames=kwnames@entry=0x0) at Python/context.c:727
#16 0x0000555555bde65c in cfunction_vectorcall_FASTCALL_KEYWORDS (func=func@entry=0x7c7ff737c040, args=0x7c6ff70b2c30, nargsf=1, kwnames=kwnames@entry=0x0) at Objects/methodobject.c:465
#17 0x0000555555abc5a0 in _PyVectorcall_Call (tstate=<optimized out>, func=<optimized out>, callable=<optimized out>, tuple=0x7c6ff70b2c10, kwargs=<optimized out>) at Objects/call.c:273
#18 0x0000555555e904e2 in _PyEval_EvalFrameDefault (tstate=<optimized out>, frame=<optimized out>, throwflag=<optimized out>) at Python/generated_cases.c.h:2937
#19 0x0000555555e57778 in _PyEval_EvalFrame (tstate=0x5555568f7b18 <_PyRuntime+360664>, frame=0x7e8ff6fe5220, throwflag=0) at ./Include/internal/pycore_ceval.h:118
#20 _PyEval_Vector (tstate=<optimized out>, func=<optimized out>, locals=<optimized out>, args=<optimized out>, argcount=<optimized out>, kwnames=0x0) at Python/ceval.c:2134
#21 0x0000555555e57195 in PyEval_EvalCode (co=<optimized out>, globals=<optimized out>, locals=0x7c7ff70884c0) at Python/ceval.c:681
#22 0x0000555556061fb0 in run_eval_code_obj (tstate=tstate@entry=0x5555568f7b18 <_PyRuntime+360664>, co=co@entry=0x7d1ff701bd50, globals=globals@entry=0x7c7ff70884c0,
    locals=locals@entry=0x7c7ff70884c0) at Python/pythonrun.c:1368
#23 0x000055555606117c in run_mod (mod=<optimized out>, filename=<optimized out>, globals=<optimized out>, locals=<optimized out>, flags=<optimized out>, arena=<optimized out>,
    interactive_src=<optimized out>, generate_new_source=<optimized out>) at Python/pythonrun.c:1471

Found using cpython-review-toolkit with Claude Opus 4.6, using the /cpython-review-toolkit:explore Modules/_asynciomodule.c all deep command.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

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

Python 3.15.0a7+ (heads/main:99e2c5eccd2, Mar 17 2026, 08:26:50) [Clang 21.1.2 (2ubuntu6)]

Linked PRs
  • gh-146304

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Comienza en Modules/_asynciomodule.c, en FutureIter_am_send, y revisa las rutas existentes de throw() y close() descritas en el informe. Reproduce el MRE en CPython main, añade después cobertura para el envío una vez vaciado el iterador y confirma que termina con StopIteration en lugar de bloquearse.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
c, python
Área
backend
Tipo de issue
Error
Dificultad
2/5
Tiempo estimado
1-3 horas
Estado de actividad
Estancado
Claridad
Bien especificado
Aptitud para principiantes
35/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.