Skip to content

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

Description

@amruthamodela06

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->interpolationsiterafter 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_testcapiimportset_nomemory, remove_mem_hookst=t"x{1}y{2}z"forstartinrange(1, 1000):
set_nomemory(start, 0)
try:
try:
iter(t)
finally:
remove_mem_hooks()
exceptMemoryError:
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) {
returnNULL;
}
PyObject*stringsiter=PyObject_GetIter(self->strings);
if (stringsiter==NULL) {
Py_DECREF(iter); /* iter->stringsiter / ->interpolationsiter are uninitialized */returnNULL;
}
PyObject*interpolationsiter=PyObject_GetIter(self->interpolations);
if (interpolationsiter==NULL) {
Py_DECREF(iter); /* same: iter->interpolationsiter is uninitialized */Py_DECREF(stringsiter);
returnNULL;
}

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) {
returnNULL;
}
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

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)type-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions