Skip to content

Commit

Permalink
Avoid creating ref cycles
Browse files Browse the repository at this point in the history
By storing previously raised exceptions inside a local, this code created ref cycles that kept all locals in all calling stack frames alive.

This is because exceptions hold references to their tracebacks, which hold references to the relevant frames, which holds a reference to the local errors dict that holds references to the exceptions. See https://peps.python.org/pep-0344/#open-issue-garbage-collection and https://peps.python.org/pep-3110/#rationale

This breaks the cycle by deleting the local when we raise, so frames are destroyed by the normal reference counting mechanism.

This fixes some resource exhaustion issues I encountered at work.
  • Loading branch information
hauntsaninja authored Sep 23, 2023
1 parent b29e6f4 commit f165e56
Showing 1 changed file with 4 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/typeguard/_checkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,10 @@ def check_union(
formatted_errors = indent(
"\n".join(f"{key}: {error}" for key, error in errors.items()), " "
)
raise TypeCheckError(f"did not match any element in the union:\n{formatted_errors}")
try:
raise TypeCheckError(f"did not match any element in the union:\n{formatted_errors}")
finally:
del errors


def check_uniontype(
Expand Down

0 comments on commit f165e56

Please sign in to comment.