Crash report
What happened?
When in memory-constrained situations, the following code generates a segfault on main:
b = 9
while True:
b = (b, None)
Clearly, b grows to be an unbounded nested tuple, which eventually exhausts the memory.
A MemoryError is correctly thrown, but during unwind, python tries to clean up the object, and this triggers a stack overflow.
Example stack
Process 369 stopped
Thread 1 "fuzz_python" stop reason = signal SIGSEGV
frame #0: frame #0: 0x0000aaaaaea31648 fuzz_python`tuple_dealloc(self=0x0000ffff9fa045e0) at tupleobject.c:256
frame #1: frame #1: 0x0000aaaaae9ccd54 fuzz_python`_Py_Dealloc(op=0x0000ffff9fa045e0) at object.c:3303:5
frame #2: frame #2: 0x0000aaaaaea3182c fuzz_python`Py_DECREF(op=<unavailable>) at refcount.h:427:9 [inlined]
frame #3: frame #3: 0x0000aaaaaea3180c fuzz_python`Py_XDECREF(op=<unavailable>) at refcount.h:520:9 [inlined]
frame #4: frame #4: 0x0000aaaaaea31804 fuzz_python`tuple_dealloc(self=0x0000ffff9fa04630) at tupleobject.c:277:9
frame #5: frame #5: 0x0000aaaaae9ccd54 fuzz_python`_Py_Dealloc(op=0x0000ffff9fa04630) at object.c:3303:5
frame #6: frame #6: 0x0000aaaaaea3182c fuzz_python`Py_DECREF(op=<unavailable>) at refcount.h:427:9 [inlined]
frame #7: frame #7: 0x0000aaaaaea3180c fuzz_python`Py_XDECREF(op=<unavailable>) at refcount.h:520:9 [inlined]
...
frame #2709: frame #2709: 0x0000aaaaae9ccd54 fuzz_python`_Py_Dealloc(op=0x0000ffff9fa11cd0) at object.c:3303:5
frame #2710: frame #2710: 0x0000aaaaaea3182c fuzz_python`Py_DECREF(op=<unavailable>) at refcount.h:427:9 [inlined]
frame #2711: frame #2711: 0x0000aaaaaea3180c fuzz_python`Py_XDECREF(op=<unavailable>) at refcount.h:520:9 [inlined]
frame #2712: frame #2712: 0x0000aaaaaea31804 fuzz_python`tuple_dealloc(self=0x0000ffff9fa11d20) at tupleobject.c:277:9
frame #2713: frame #2713: 0x0000aaaaae9ccd54 fuzz_python`_Py_Dealloc(op=0x0000ffff9fa11d20) at object.c:3303:5
frame #2714: frame #2714: 0x0000aaaaaea3182c fuzz_python`Py_DECREF(op=<unavailable>) at refcount.h:427:9 [inlined]
frame #2715: frame #2715: 0x0000aaaaaea3180c fuzz_python`Py_XDECREF(op=<unavailable>) at refcount.h:520:9 [inlined]
frame #2716: frame #2716: 0x0000aaaaaea31804 fuzz_python`tuple_dealloc(self=0x0000ffff9fa11d70) at tupleobject.c:277:9
frame #2717: frame #2717: 0x0000aaaaae9ccd54 fuzz_python`_Py_Dealloc(op=0x0000ffff9fa11d70) at object.c:3303:5
frame #2718: frame #2718: 0x0000aaaaaea3182c fuzz_python`Py_DECREF(op=<unavailable>) at refcount.h:427:9 [inlined]
frame #2719: frame #2719: 0x0000aaaaaea3180c fuzz_python`Py_XDECREF(op=<unavailable>) at refcount.h:520:9 [inlined]
frame #2720: frame #2720: 0x0000aaaaaea31804 fuzz_python`tuple_dealloc(self=0x0000ffff9fa11dc0) at tupleobject.c:277:9
frame #2721: frame #2721: 0x0000aaaaae9ccd54 fuzz_python`_Py_Dealloc(op=0x0000ffff9fa11dc0) at object.c:3303:5
frame #2722: frame #2722: 0x0000aaaaae98f290 fuzz_python`Py_DECREF(op=<unavailable>) at refcount.h:427:9 [inlined]
frame #2723: frame #2723: 0x0000aaaaae98f26c fuzz_python`Py_XDECREF(op=<unavailable>) at refcount.h:520:9 [inlined]
frame #2724: frame #2724: 0x0000aaaaae98f26c fuzz_python`dictkeys_decref(dk=0x0000ffffbe045210, use_qsbr=false) at dictobject.c:495:17
frame #2725: frame #2725: 0x0000aaaaae98630c fuzz_python`dict_dealloc(self=0x0000ffffbe055f40) at dictobject.c:0
frame #2726: frame #2726: 0x0000aaaaae9ccd54 fuzz_python`_Py_Dealloc(op=0x0000ffffbe055f40) at object.c:3303:5
frame #2727: frame #2727: 0x0000aaaaae7ecb8c fuzz_python`Py_DECREF(op=0x0000ffffbe055f40) at refcount.h:427:9 [inlined]
frame #2728: frame #2728: 0x0000aaaaae7ecb58 fuzz_python`main(argc=1, argv=0x0000fffff67f4238) at fuzz_python.c:226:17
frame #2729: frame #2729: 0x0000ffffbe1e1f9c ld-musl-aarch64.so.1`libc_start_main_stage2(main=(fuzz_python`main at fuzz_python.c:71), argc=1, argv=0x0000fffff67f4238) at __libc_start_main.c:95:2
The following dockerfile reliably reproduces it for me:
Dockerfile
FROM alpine:latest
RUN apk add --no-cache \
git build-base linux-headers openssl-dev zlib-dev bzip2-dev \
xz-dev sqlite-dev readline-dev libffi-dev ncurses-dev gdbm-dev \
tcl-dev tk-dev
WORKDIR /src
RUN git clone --depth=1 https://github.com/python/cpython.git
WORKDIR /src/cpython
RUN ./configure && make -j2
RUN cat > /tc.py <<'PY'
b = 9
while True:
b = (b, None)
PY
RUN cat > /entrypoint.sh <<'SH'
#!/bin/sh
echo "Running test"
# 512 MiB virtual memory limit
ulimit -v 524288
/src/cpython/python /tc.py
echo "Python process exited with code $?"
SH
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
Gives me:
>docker run --rm -it 29apr
Running test
Traceback (most recent call last):
File "/tc.py", line 3, in <module>
object address : 0xffffae809fc0
object refcount : 3
object type : 0xaaaad32175a8
object type name: MemoryError
object repr : MemoryError()
lost sys.stderr
Segmentation fault
Python process exited with code 139
ISTR that stack overflows from recursive objects were at least considered low priority, if not 'not worth fixing' before, but I can't recall where I read that, it was a while ago, so apologies if this isn't a useful report!
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
Python 3.15.0a8+ (heads/main:d4eee16, Apr 29 2026, 11:03:26) [GCC 15.2.0]
Linked PRs
Crash report
What happened?
When in memory-constrained situations, the following code generates a segfault on main:
Clearly, b grows to be an unbounded nested tuple, which eventually exhausts the memory.
A MemoryError is correctly thrown, but during unwind, python tries to clean up the object, and this triggers a stack overflow.
Example stack
The following dockerfile reliably reproduces it for me:
Dockerfile
Gives me:
ISTR that stack overflows from recursive objects were at least considered low priority, if not 'not worth fixing' before, but I can't recall where I read that, it was a while ago, so apologies if this isn't a useful report!
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
Python 3.15.0a8+ (heads/main:d4eee16, Apr 29 2026, 11:03:26) [GCC 15.2.0]
Linked PRs