Repository navigation
Segmentation fault, possibly due to a GC issue (tp_subclasses) #135552
Copy link
Copy link
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?
from typing import Union
class BaseNode:
next: Union["BaseNode", None] = None
@staticmethod
def add(node: "BaseNode") -> None:
if BaseNode.next is None:
BaseNode.next = node
return
current = BaseNode.next
while current.next is not None:
current = current.next
current.next = node
@staticmethod
def remove(node: "BaseNode") -> None:
if BaseNode.next is None:
return
current = BaseNode.next
prev = BaseNode
while True:
if current is None:
return
if current == node:
if current.next is not None:
prev.next = current.next
else:
prev.next = None
return
prev = current
current = current.next
class Node(BaseNode):
def __init__(self) -> None:
self.next = None
BaseNode.add(self)
def __del__(self) -> None:
BaseNode.remove(self)
def main() -> None:
Node()
Node()
if __name__ == "__main__":
main()(Edited by @ZeroIntensity) Shortened repro:
class BaseNode:
next = None
class Node(BaseNode):
def __init__(self) -> None:
if BaseNode.next is None:
BaseNode.next = self
return
BaseNode.next.next = self
def __del__(self) -> None:
BaseNode.next = BaseNode.next.next
Node()
Node()(Edited by @fxeqxmulfx) Use after free example:
class BaseNode:
def __del__(self):
print("next", BaseNode.next)
print("del", self)
BaseNode.next = BaseNode()
BaseNode.next.next = BaseNode()next <__main__.BaseNode object at 0x717fb2d23a10>
del <__main__.BaseNode object at 0x717fb2d23a10>
next <__main__.BaseNode object at 0x717fb2d23a10> use after free
del <__main__.BaseNode object at 0x717fb2d23a50>
CPython versions tested on:
3.14
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
Python 3.14.0b2 (main, Jun 12 2025, 12:41:01) [Clang 20.1.4 ]
Linked PRs
- gh-135552: Clear weakrefs to types in GC after garbage finalization not before #135728
- gh-135552: Skip clearing of tp_subclasses weakrefs in GC #136147
- gh-135552: Don't clear weakref if wr_object is a type. #136151
- gh-135552: Make the GC clear weakrefs later #136189
- gh-135552: Add tests that check if weakref for tp_subclasses cleared after finalization #136304
Reactions are currently unavailable
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
fxeqxmulfx commentedon Jun 16, 2025
This also affects:
ZeroIntensity commentedon Jun 16, 2025
Confirmed on main back to 3.13, but interestingly, this doesn't affect free-threading. Given that this is caused by
__del__, this is probably one of those weird bugs where a borrowed reference is cleared. Thanks for the report.ZeroIntensity commentedon Jun 16, 2025
(Nevermind, not related to
typing.)ZeroIntensity commentedon Jun 16, 2025
Shortened repro:
Looks like a garbage collection problem.
vstinner commentedon Jun 16, 2025
Python 3.14 trace:
Python 3.10 trace:
efimov-mikhail commentedon Jun 16, 2025
Cc @Eclips4
Eclips4 commentedon Jun 17, 2025
FYI, this code still crashes even with the
gc.disable()in the beginning of the codeZeroIntensity commentedon Jun 17, 2025
That won't fully fix it, the GC still runs at some point (such as finalization).
gc.freeze()does indeed prevent the crash.I suspect this is an issue with the garbage collector itself (and not the object model), because this doesn't crash under free-threading, where there's a different garbage collector.
18 remaining items
[-]Segmentation fault, possibly due to a GC issue[/-][+]Segmentation fault, possibly due to a GC issue (tp_subclasses)[/+]nascheme commentedon Jul 1, 2025
Not clearing the weakrefs would re-introduce a bug like bpo-38006 (see commit 392a13b for a unit test). I was mistakenly thinking that with PEP 442 we didn't have to worry about finalizers running during the
delete_garbage()phase. That's not true. They can run if some objects are missingtp_traversemethods or those methods are not accurate. We need to clear weakrefs so those finalizers cannot access an object that hastp_clearcalled on it.Merge 'origin/main' into pythongh-135552-wr-clear-later
Merge 'origin/main' into pythongh-135552-wr-clear-later
Defer clear for weakrefs without callbacks.
Merge 'origin/main' into pythongh-135552-wr-clear-later
Merge 'origin/main' into pythongh-135552-wr-clear-later
Merge branch 'origin/main' into pythongh-135552-wr-clear-later
GH-135552: Make the GC clear weakrefs later (GH-136189)
Merge branch 'main' into pythongh-135552-add-tests-gc-weakref-tp_subc…
GH-135552: Add tests to check weakref clearing (GH-136304)
sergey-miryanov commentedon Aug 8, 2025
This can be closed now.
pythonGH-135552: Make the GC clear weakrefs later (pythonGH-136189)
pythonGH-135552: Add tests to check weakref clearing (pythonGH-136304)