python / python/cpython

Segfault: dealloc of uninitialized iterator in template_iter (Objects/templateobject.c:232)

Abierto
#151,815 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

interpreter-core 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

Segfault: dealloc of uninitialized iterator in template_iter (Objects/templateobject.c:232)

template_iter() allocates the t-string iterator with PyObject_GC_New (which does not zero the new object) and only assigns iter->stringsiter and iter->interpolationsiter after both PyObject_GetIter calls succeed. If either PyObject_GetIter fails under memory pressure, the error-path Py_DECREF(iter) runs templateiter_dealloctemplateiter_clear, which Py_CLEARs the still-uninitialized (garbage / ASan-poisoned) pointers, causing a segfault.

Reproducer

(needs CPython 3.14+ for t-string / PEP 750 syntax)

from _testcapi import set_nomemory, remove_mem_hooks

t = t"x{1}y{2}z"

for start in range(1, 1000):
    set_nomemory(start, 0)
    try:
        try:
            iter(t)
        finally:
            remove_mem_hooks()
    except MemoryError:
        pass
Backtrace
#0  _Py_atomic_load_uint32_relaxed
#1  Py_DECREF
#2  templateiter_clear           Objects/templateobject.c:53   # Py_CLEAR(self->stringsiter), uninitialized
#3  templateiter_dealloc         Objects/templateobject.c:45
#4  _Py_Dealloc
#5  Py_DECREF
#6  template_iter                Objects/templateobject.c:232  # Py_DECREF(iter) on the error path
#7  PyObject_GetIter

Crashes deterministically on debug+ASan and JIT debug+ASan builds. On non-ASan release builds it usually exits cleanly within the swept budget (the uninitialized memory often happens to be zero), but the underlying access of uninitialized fields is still incorrect.

Root cause

Objects/templateobject.c, template_iter:

templateiterobject *iter = PyObject_GC_New(templateiterobject, &_PyTemplateIter_Type);  /* no zeroing */
if (iter == NULL) {
    return NULL;
}

PyObject *stringsiter = PyObject_GetIter(self->strings);
if (stringsiter == NULL) {
    Py_DECREF(iter);   /* iter->stringsiter / ->interpolationsiter are uninitialized */
    return NULL;
}

PyObject *interpolationsiter = PyObject_GetIter(self->interpolations);
if (interpolationsiter == NULL) {
    Py_DECREF(iter);   /* same: iter->interpolationsiter is uninitialized */
    Py_DECREF(stringsiter);
    return NULL;
}
Suggested fix

Initialize iter->stringsiter and iter->interpolationsiter to NULL immediately after PyObject_GC_New, so the partial-construction error paths can safely run templateiter_clear (which uses Py_CLEAR, NULL-safe):

templateiterobject *iter = PyObject_GC_New(templateiterobject, &_PyTemplateIter_Type);
if (iter == NULL) {
    return NULL;
}
iter->stringsiter = NULL;
iter->interpolationsiter = NULL;
Notes

Part of #151763 (umbrella tracking 35 OOM-related crash findings); OOM-0024 in that table.

CPython versions tested on:

CPython main branch (3.16.0a0)

Operating systems tested on:

Linux, Windows

Linked PRs
  • gh-151821
  • gh-154714

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

Empieza en Objects/templateobject.c, en template_iter, y luego lee templateiter_clear y templateiter_dealloc para entender la ruta de limpieza que falla. Ejecuta el reproductor de presión de memoria de t-string proporcionado en una compilación debug+ASan y verifica que las rutas de error del iterador ya no accedan a campos no inicializados ni provoquen un fallo.

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

Evaluación

Stack tecnológico
python
Área
backend
Tipo de issue
Error
Dificultad
1/5
Tiempo estimado
Menos de una hora
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.