Skip to content

_Py_make_parameters recurses without a guard: a self-referential/deeply-nested generic-alias arg crashes the interpreter #154275

Description

@devdanzin

Crash report

What happened?

Computing __parameters__ of a generic alias whose argument is a self-referential (or merely very deeply nested) list/tuple crashes the interpreter with a C-stack overflow. _Py_make_parameters (Objects/genericaliasobject.c) recurses into nested list/tuple args without any recursion guard (Py_EnterRecursiveCall), so a cyclic argument recurses forever.

Minimal reproducer:

L = []
L.append(L)             # L = [L], self-referential
list[L].__parameters__  # SIGSEGV

list[L] on its own is fine — __parameters__ is computed lazily, and the crash is in that computation (anything that triggers it — using the alias as a base class, typing.get_args(), etc. — crashes the same way).

A non-cyclic but deeply nested list crashes it too, which shows the path is simply unguarded rather than something cycle-specific:

x = [0]
for _ in range(500_000):
    x = [x]
list[x].__parameters__  # SIGSEGV (C stack overflow)

Backtrace (debug build); the interpreter dies in _Py_make_parameters self-recursion at genericaliasobject.c:231:

#0  gc_alloc                 Python/gc.c:2013            <- SIGSEGV at the stack guard page
#1  _PyObject_GC_NewVar      Python/gc.c:2055
#2  tuple_alloc              Objects/tupleobject.c:57
#3  PyTuple_FromArray        Objects/tupleobject.c:442
#4  PyList_AsTuple           Objects/listobject.c:3269
#5  _Py_make_parameters      Objects/genericaliasobject.c:192
#6  _Py_make_parameters      Objects/genericaliasobject.c:231   <- unguarded recursion
#7  _Py_make_parameters      Objects/genericaliasobject.c:231
    ... (repeats until the C stack overflows) ...

Analysis

_Py_make_parameters collects type parameters from an alias's arguments. For an argument that is a list/tuple with no __parameters__, it recurses into it:

if (!subparams && (PyTuple_Check(t) || PyList_Check(t))) {
    // Recursively call _Py_make_parameters for lists/tuples and
    // add the results to the current parameters.
    subparams = _Py_make_parameters(t);   // Objects/genericaliasobject.c:231
    ...
}

There is no Py_EnterRecursiveCall / Py_LeaveRecursiveCall in this function — nor anywhere in genericaliasobject.c — so a self-referential argument recurses without bound and overflows the C stack (SIGSEGV) instead of raising RecursionError.

Fix direction: wrap the recursive descent in Py_EnterRecursiveCall(...) / Py_LeaveRecursiveCall(), as other recursive C paths do, so the overflow becomes a catchable RecursionError.

Not free-threading- or JIT-specific: reproduces on GIL and free-threaded, release and debug builds.

(Found via fuzzing with fusil; the same reproducer also crashes RustPython, whose make_parameters_from_slice has the identical unguarded recursion. Reduced and reviewed by hand; draft prepared with Claude Code.)

CPython versions tested on:

3.14, CPython main branch

Operating systems tested on:

Linux

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

Python 3.16.0a0 (heads/main:a1d580430c8, Jul 18 2026, 20:16:15) [Clang 21.1.8 (6ubuntu1)]

Linked PRs

Metadata

Metadata

Assignees

Labels

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

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions