Open
Description
Crash report
What happened?
It's possible to segfault or abort the interpreter of a free-threading build by calling repr(SimpleNamespace)
in threads when the instance has typing.Union
attributes. This seems very similar to #132713.
The MRE will rarely hang and is non-deterministic, but is the best I was able to come up with.
MRE:
from functools import reduce
from operator import or_
from threading import Thread
from types import SimpleNamespace
all_types = []
for x in range(400):
class Dummy: pass
all_types.append(Dummy)
big_union = reduce(or_, all_types, int)
for x in range(500):
s = SimpleNamespace()
def stress_simplenamespace():
for x in range(20):
varying_union = big_union | tuple[int, ...] | list[str, ...] | dict[str, int]
repr(s)
attr_name = f"t_attr_{x}"
setattr(s, attr_name, varying_union)
repr(s)
repr(s)
repr(s)
alive = [Thread(target=stress_simplenamespace) for x in range(8)]
for t in alive:
t.start()
for t in alive:
t.join()
Segfault backtrace 1:
Thread 7 "Thread-6 (stres" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff541b640 (LWP 348490)]
0x000055555567cdcd in setup_ga (args=<unknown at remote 0x7ffff5c20640>, origin=<type at remote 0x555555b11d40>, alias=0x2276a0e0140) at Objects/genericaliasobject.c:837
837 if (!PyTuple_Check(args)) {
#0 0x000055555567cdcd in setup_ga (args=<unknown at remote 0x7ffff5c20640>, origin=<type at remote 0x555555b11d40>, alias=0x2276a0e0140)
at Objects/genericaliasobject.c:837
#1 Py_GenericAlias (origin=<type at remote 0x555555b11d40>, args=<unknown at remote 0x7ffff5c20640>) at Objects/genericaliasobject.c:1015
#2 0x0000555555658dd5 in _PyObject_VectorcallTstate (kwnames=0x0, nargsf=9223372036854775809, args=0x7ffff541a428,
callable=<built-in method __class_getitem__ of type object at remote 0x555555b11d40>, tstate=0x555555c3c6e0)
at ./Include/internal/pycore_call.h:169
#3 PyObject_CallOneArg (func=<built-in method __class_getitem__ of type object at remote 0x555555b11d40>,
arg=arg@entry=<unknown at remote 0x7ffff5c20640>) at Objects/call.c:395
#4 0x0000555555634781 in PyObject_GetItem (o=<type at remote 0x555555b11d40>, key=<unknown at remote 0x7ffff5c20640>) at Objects/abstract.c:193
#5 0x00005555555e2f02 in _PyEval_EvalFrameDefault (tstate=<optimized out>, frame=<optimized out>, throwflag=<optimized out>)
at Python/generated_cases.c.h:62
#6 0x00005555557dd13e in _PyEval_EvalFrame (throwflag=0, frame=<optimized out>, tstate=0x555555c3c6e0) at ./Include/internal/pycore_ceval.h:119
#7 _PyEval_Vector (tstate=0x555555c3c6e0, func=0x2275e37fd80, locals=0x0, args=0x7ffff541a8a8, argcount=<optimized out>, kwnames=<optimized out>)
at Python/ceval.c:1975
Segfault backtrace 2:
Thread 3 "Thread-2 (stres" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff742f640 (LWP 343364)]
clear_freelist (dofree=<optimized out>, is_finalization=<optimized out>, freelist=<optimized out>) at Objects/object.c:904
904 dofree(ptr);
#0 clear_freelist (dofree=<optimized out>, is_finalization=<optimized out>, freelist=<optimized out>) at Objects/object.c:904
#1 _PyObject_ClearFreeLists (freelists=0x555555c30948, is_finalization=is_finalization@entry=1) at Objects/object.c:929
#2 0x000055555585c521 in PyThreadState_Clear (tstate=tstate@entry=0x555555c2cf60) at Python/pystate.c:1703
#3 0x0000555555904a10 in thread_run (boot_raw=0x555555c194a0) at ./Modules/_threadmodule.c:390
#4 0x000055555587e27b in pythread_wrapper (arg=<optimized out>) at Python/thread_pthread.h:232
#5 0x00007ffff7d31ac3 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#6 0x00007ffff7dc3850 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
A backtrace for a segfault I got with a variant of this code, seems more informative but I cannot repro with the MRE:
Thread 185 "asyncio_4" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xffffe31ff060 (LWP 1527140)]
0x0000000000867ce8 in _Py_TYPE (ob=<unknown at remote 0xdddddddddddddddd>) at ./Include/object.h:270
270 return ob->ob_type;
#0 0x0000000000867ce8 in _Py_TYPE (ob=<unknown at remote 0xdddddddddddddddd>) at ./Include/object.h:270
#1 union_repr (self=<unknown at remote 0xffffa425a9d0>) at Objects/unionobject.c:296
#2 0x00000000006e61a8 in PyObject_Repr (v=<unknown at remote 0xffffa425a9d0>) at Objects/object.c:779
#3 0x000000000082ada0 in unicode_fromformat_arg (writer=writer@entry=0xffffe31fb4e0, f=0xd88224 "R", f@entry=0xd88223 "%R", vargs=vargs@entry=0xffffe31fb410)
at Objects/unicodeobject.c:3101
#4 0x000000000082b33c in unicode_from_format (writer=writer@entry=0xffffe31fb4e0, format=format@entry=0xd88220 "%U=%R",
vargs=<error reading variable: Cannot access memory at address 0x1>) at Objects/unicodeobject.c:3220
#5 0x000000000082b68c in PyUnicode_FromFormatV (format=format@entry=0xd88220 "%U=%R", vargs=...) at Objects/unicodeobject.c:3254
#6 0x000000000082b828 in PyUnicode_FromFormat (format=format@entry=0xd88220 "%U=%R") at Objects/unicodeobject.c:3268
#7 0x00000000006e1038 in namespace_repr (ns=<types.SimpleNamespace at remote 0xffffa48e3c60>) at Objects/namespaceobject.c:129
#8 0x000000000075e894 in object_str (self=self@entry=<types.SimpleNamespace at remote 0xffffa48e3c60>) at Objects/typeobject.c:7152
#9 0x0000000000768d18 in wrap_unaryfunc (self=<types.SimpleNamespace at remote 0xffffa48e3c60>, args=<optimized out>, wrapped=0x75e854 <object_str>)
at Objects/typeobject.c:9536
#10 0x00000000005d8ee0 in wrapperdescr_raw_call (kwds=<optimized out>, args=<optimized out>, self=<optimized out>, descr=<optimized out>) at Objects/descrobject.c:532
#11 wrapper_call (self=<optimized out>, args=<optimized out>, kwds=<optimized out>) at Objects/descrobject.c:1437
#12 0x00000000005ab38c in _PyObject_MakeTpCall (tstate=tstate@entry=0xffff48937210,
callable=callable@entry=<method-wrapper '__str__' of types.SimpleNamespace object at 0xffffa48e3c60>, args=args@entry=0xffffe31fbe58, nargs=nargs@entry=0,
keywords=keywords@entry=0x0) at Objects/call.c:242
#13 0x00000000005aba68 in _PyObject_VectorcallTstate (tstate=0xffff48937210, callable=<method-wrapper '__str__' of types.SimpleNamespace object at 0xffffa48e3c60>,
args=0xffffe31fbe58, nargsf=9223372036854775808, kwnames=0x0) at ./Include/internal/pycore_call.h:167
#14 0x00000000005aba98 in PyObject_Vectorcall (callable=callable@entry=<method-wrapper '__str__' of types.SimpleNamespace object at 0xffffa48e3c60>,
args=args@entry=0x0, nargsf=nargsf@entry=9223372036854775808, kwnames=kwnames@entry=0x0) at Objects/call.c:327
Abort backtrace:
*** stack smashing detected ***: terminated
Thread 7 "Thread-6 (stres" received signal SIGABRT, Aborted.
[Switching to Thread 0x7ffff541b640 (LWP 351627)]
__pthread_kill_implementation (no_tid=0, signo=6, threadid=0) at ./nptl/pthread_kill.c:44
#0 __pthread_kill_implementation (no_tid=0, signo=6, threadid=0) at ./nptl/pthread_kill.c:44
#1 __pthread_kill_internal (signo=6, threadid=0) at ./nptl/pthread_kill.c:78
#2 __GI___pthread_kill (threadid=0, signo=signo@entry=6) at ./nptl/pthread_kill.c:89
#3 0x00007ffff7cdf476 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#4 0x00007ffff7cc57f3 in __GI_abort () at ./stdlib/abort.c:79
#5 0x00007ffff7d26677 in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff7e7892e "*** %s ***: terminated\n")
at ../sysdeps/posix/libc_fatal.c:156
#6 0x00007ffff7dd359a in __GI___fortify_fail (msg=msg@entry=0x7ffff7e78916 "stack smashing detected") at ./debug/fortify_fail.c:26
#7 0x00007ffff7dd3566 in __stack_chk_fail () at ./debug/stack_chk_fail.c:24
#8 0x000055555572321d in _Py_type_getattro_impl (type=<optimized out>, name=<optimized out>,
suppress_missing_attribute=suppress_missing_attribute@entry=0x7ffff541a194) at Objects/typeobject.c:6355
#9 0x00005555556db432 in PyObject_GetOptionalAttr (v=v@entry=<type at remote 0x3b2b2e06800>, name=<optimized out>,
result=result@entry=0x7ffff541a1d0) at Objects/object.c:1345
#10 0x000055555572ea38 in _Py_typing_type_repr (writer=writer@entry=0x3b2be090e80, p=<type at remote 0x3b2b2e06800>) at Objects/typevarobject.c:295
#11 0x000055555577ad6e in union_repr (self=<typing.Union at remote 0x3b2c20e0820>) at Objects/unionobject.c:297
#12 0x00005555556d80db in PyObject_Repr (v=<typing.Union at remote 0x3b2c20e0820>) at ./Include/object.h:277
#13 PyObject_Repr (v=<typing.Union at remote 0x3b2c20e0820>) at Objects/object.c:754
#14 0x0000555555765835 in unicode_fromformat_arg (vargs=0x7ffff541a278, f=0x555555937b12 "R", writer=0x7ffff541a300)
at Objects/unicodeobject.c:3101
#15 unicode_from_format (writer=writer@entry=0x7ffff541a300, format=format@entry=0x555555937b0e "%U=%R", vargs=vargs@entry=0x7ffff541a340)
at Objects/unicodeobject.c:3220
#16 0x000055555576fadf in PyUnicode_FromFormatV (vargs=0x7ffff541a340, format=0x555555937b0e "%U=%R") at Objects/unicodeobject.c:3254
#17 PyUnicode_FromFormat (format=format@entry=0x555555937b0e "%U=%R") at Objects/unicodeobject.c:3268
#18 0x00005555556d5802 in namespace_repr (ns=<types.SimpleNamespace at remote 0x3b2b2152310>) at Objects/namespaceobject.c:129
#19 0x00005555556d80db in PyObject_Repr (v=<types.SimpleNamespace at remote 0x3b2b2152310>) at ./Include/object.h:277
#20 PyObject_Repr (v=<types.SimpleNamespace at remote 0x3b2b2152310>) at Objects/object.c:754
#21 0x00005555555e4883 in _PyEval_EvalFrameDefault (tstate=<optimized out>, frame=<optimized out>, throwflag=<optimized out>)
at Python/generated_cases.c.h:2487
#22 0x00005555557dd13e in _PyEval_EvalFrame (throwflag=0, frame=<optimized out>, tstate=0x555555c3c6e0) at ./Include/internal/pycore_ceval.h:119
#23 _PyEval_Vector (tstate=0x555555c3c6e0, func=0x3b2b237fd80, locals=0x0, args=0x7ffff541a8a8, argcount=<optimized out>, kwnames=<optimized out>)
at Python/ceval.c:1975
Found using fusil by @vstinner.
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
Python 3.15.0a0 experimental free-threading build (heads/main:b706ff003c5, Jun 11 2025, 19:34:04) [GCC 11.4.0]