@@ -3040,6 +3040,18 @@ class catch_unraisable_exception:
30403040 """
30413041 Context manager catching unraisable exception using sys.unraisablehook.
30423042
3043+ If the *object* attribute of the unraisable hook is set and the object is
3044+ being finalized, the object is resurrected because the context manager
3045+ stores a strong reference to it (cm.unraisable.object).
3046+
3047+ Storing the exception value (cm.unraisable.exc_value) creates a reference
3048+ cycle. The reference cycle is broken explicitly when the context manager
3049+ exits.
3050+
3051+ Exiting the context manager clears the stored unraisable exception. It can
3052+ trigger a new unraisable exception (ex: the resurrected object is finalized
3053+ again and raises the same exception): it is silently ignored in this case.
3054+
30433055 Usage:
30443056
30453057 with support.catch_unraisable_exception() as cm:
@@ -3058,6 +3070,8 @@ def __init__(self):
30583070 self ._old_hook = None
30593071
30603072 def _hook (self , unraisable ):
3073+ # Storing unraisable.object can resurrect an object which is being
3074+ # finalized. Storing unraisable.exc_value creates a reference cycle.
30613075 self .unraisable = unraisable
30623076
30633077 def __enter__ (self ):
@@ -3066,6 +3080,10 @@ def __enter__(self):
30663080 return self
30673081
30683082 def __exit__ (self , * exc_info ):
3069- # Clear the unraisable exception to explicitly break a reference cycle
3070- del self .unraisable
3083+ # Clear the unraisable exception to explicitly break a reference cycle.
3084+ # It can call _hook() again: ignore the new unraisable exception in
3085+ # this case.
3086+ self .unraisable = None
3087+
30713088 sys .unraisablehook = self ._old_hook
3089+ del self .unraisable
0 commit comments