Repository navigation
Closed
Labels
3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Description
Crash report
What happened?
It's possible to segfault the interpreter by corrupting a set, then calling repr() on it.
MRE:
tasks = set()
class Dummy(object):
def __hash__(self):
return 0
class CorrupTrigger():
counter = 0
def __hash__(self):
return 0
def __eq__(self,other):
if self.counter < 1:
self.counter += 1
tasks.add(self)
return False
tasks.add(Dummy())
tasks.add(Dummy())
tasks.pop()
tasks.add(CorrupTrigger())
repr(tasks)Backtrace:
Program received signal SIGSEGV, Segmentation fault.
0x0000555555b5b1e7 in Py_INCREF (op=0x0) at ./Include/refcount.h:281
281 PY_UINT32_T cur_refcnt = op->ob_refcnt;
(gdb) bt
#0 0x0000555555b5b1e7 in Py_INCREF (op=0x0) at ./Include/refcount.h:281
#1 _Py_NewRef (obj=0x0) at ./Include/refcount.h:529
#2 list_repr_impl (v=0x7c6ff6e72f60) at Objects/listobject.c:598
#3 list_repr (self=0x7c6ff6e72f60) at Objects/listobject.c:638
#4 0x0000555555bea219 in PyObject_Repr (v=v@entry=0x7c6ff6e72f60) at Objects/object.c:779
#5 0x0000555555c3c4b7 in set_repr_lock_held (so=0x7d0ff6eb17a0) at Objects/setobject.c:594
#6 set_repr (self=0x7d0ff6eb17a0) at Objects/setobject.c:622
#7 0x0000555555bea219 in PyObject_Repr (v=0x7d0ff6eb17a0) at Objects/object.c:779
#8 0x0000555555bd9b13 in cfunction_vectorcall_O (func=func@entry=0x7c7ff6e35d40, args=args@entry=0x7bfff5f70208, nargsf=nargsf@entry=9223372036854775809, kwnames=kwnames@entry=0x0)
at Objects/methodobject.c:536
#9 0x0000555555aba6a0 in _PyObject_VectorcallTstate (tstate=0x555556aebf00 <_PyRuntime+358560>, callable=0x7c7ff6e35d40, args=0x7bfff5f70208, nargsf=9223372036854775809, kwnames=0x0)
at ./Include/internal/pycore_call.h:169
#10 0x0000555555e8cf61 in _PyEval_EvalFrameDefault (tstate=<optimized out>, frame=<optimized out>, throwflag=<optimized out>) at Python/generated_cases.c.h:1620
#11 0x0000555555e4a67b in _PyEval_EvalFrame (tstate=0x555556aebf00 <_PyRuntime+358560>, frame=0x7e8ff6de5220, throwflag=0) at ./Include/internal/pycore_ceval.h:121
It's also possible to get set_pop_impl into an infinite loop by changing the last code block to:
tasks.add(Dummy())
tasks.add(Dummy())
tasks.pop()
tasks.add(CorrupTrigger())
tasks.pop()
tasks.pop()
tasks.pop()Found when trying to simplify the MRE in #139071.
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
Python 3.15.0a2+ (heads/main-dirty:41b9ad5b38e, Nov 20 2025, 11:03:41) [Clang 21.1.2 (2ubuntu6)]
Linked PRs
- gh-141805: avoid increase the set->used twice when the __eq__ trigger another add #142007
- gh-141805: Fix crash after concurrent addition objects with the same hash to set #143815
- [3.14] gh-141805: Fix crash after concurrent addition objects with the same hash to set (GH-143815) #143849
- [3.13] gh-141805: Fix crash after concurrent addition objects with the same hash to set (GH-143815) #143853
Metadata
Metadata
Assignees
Labels
3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Activity
devdanzin commentedon Nov 20, 2025
I guess all sorts of shenanigans are possible with the corrupted set. Here's a heap-buffer-overflow:
ASan output:
rhettinger commentedon Nov 21, 2025
Confirmed that this crashes on Py3.13 and later but worked fine on Py3.12 and prior.
yihong0618 commentedon Nov 21, 2025
the first segment fault commit 3de0f55
but its not the root cause
the root cause is we count the so->old wrong in the first 3.13
cat ttt.py
{<__main__.CorrupTrigger object at 0x105956900>, <__main__.Dummy object at 0x105a94b90>, <NULL>} ➜ cpython git:(3a130c1786) ✗ cat ttt.py tasks = set() class Dummy(object): def __hash__(self): return 0 class CorrupTrigger(): counter = 0 def __hash__(self): return 0 def __eq__(self,other): if self.counter < 1: self.counter += 1 tasks.add(self) return False tasks.add(Dummy()) tasks.add(Dummy()) tasks.pop() tasks.add(CorrupTrigger()) print(repr(tasks))the third one is NULL in the good commit
but for 3.12
➜ cpython git:(3a130c1) ✗ python3.12 ttt.py
{<main.CorrupTrigger object at 0x1007336e0>, <main.Dummy object at 0x100733680>}
yihong0618 commentedon Nov 21, 2025
this is the source cause the issue commit 3325699
from
to
some dig
yihong0618 commentedon Nov 22, 2025
try to solve with the root cause
this diff can fix the problem but I am not sure the fix is good enough and maybe lower the performance
so left comment here
update
the latest comment is the real root cause fix!
kemingy commentedon Nov 27, 2025
By using the GDB, I found that this is caused by the improper handled freeslot in
set_add_entry_takeref.tasks.pop()this leave a dummy slot in the 0-indextasks.add(Corrupt())this found this freeslot, but the logic goes into next iteration, and trigger the__eq__byPyObject_RichCompareBool__eq__trigger anothertasks.add(self)defined inside theCorruptso->used, returnFalseto the__eq__so->used(twice for this elem)Merge branch 'main' into pythongh-141805
Merge branch 'main' into pythongh-141805
pythongh-141805: Fix crash after concurrent addition objects with the…
serhiy-storchaka commentedon Jan 13, 2026
Unfortunately, solution in #142007 is not correct. Surprisingly, there was no test for this case. #143781 adds a test which will fail with such change.
The right solution is to check if
freeslotstill points to a dummy entry before replacing it. #143815 implements this.gh-141805: Fix crash after concurrent addition objects with the same …
pythongh-141805: Fix crash after concurrent addition objects with the…
[3.13] pythongh-141805: Fix crash after concurrent addition objects w…
[3.14] gh-141805: Fix crash after concurrent addition objects with th…
[3.13] gh-141805: Fix crash after concurrent addition objects with th…
pythongh-141805: Fix crash after concurrent addition objects with the…