Skip to content

Fix memory leaks in exception handling for defer, finally, and async join#436

Open
nbeerbower wants to merge 1 commit into
mainfrom
claude/fix-double-free-jkoXl
Open

Fix memory leaks in exception handling for defer, finally, and async join#436
nbeerbower wants to merge 1 commit into
mainfrom
claude/fix-double-free-jkoXl

Conversation

@nbeerbower

Copy link
Copy Markdown
Collaborator

Summary

This PR fixes memory leaks in the interpreter's exception handling by properly retaining and releasing exception values when they are copied between execution contexts or saved across control flow statements.

Key Changes

  • Concurrency (builtin_join): Added VALUE_RETAIN() when re-throwing an exception from a joined task to prevent premature deallocation since both the task context and caller context hold references to the exception value.

  • Defer Stack Execution: Added VALUE_RETAIN() when saving the current exception before defer execution, with corresponding VALUE_RELEASE() calls in both success and failure paths to properly manage the reference count.

  • Try-Finally Statements: Added VALUE_RETAIN() for both saved return and exception values before executing the finally block, with VALUE_RELEASE() calls in both paths (whether finally restores or changes control flow).

  • Test Coverage: Added three new test cases to verify the fixes:

    • defer_exception_leak.hml: Tests defer throwing while exception is pending
    • finally_exception_leak.hml: Tests finally block throwing a new exception
    • join_exception_refcount.hml: Tests joining a task that threw an exception

Implementation Details

The fixes follow a consistent pattern: when an exception value is saved and the execution context may change (through defer execution, finally blocks, or async task joining), the value must be explicitly retained to maintain a reference count that accounts for multiple holders. The corresponding release calls ensure the reference count is decremented when the saved value is either restored or discarded.

This prevents use-after-free errors and memory leaks that occurred when exception values were freed prematurely while still being referenced by other contexts.

https://claude.ai/code/session_01DfpaWxNKzvp8vMc6sEhLjC

Fix three memory management issues:

1. try/finally: When finally block throws/returns, the saved exception
   and return values were lost without being released. Now properly
   retains saved values before finally executes and releases them
   appropriately based on control flow outcome.

2. defer stack: When a deferred call throws while an exception is
   pending, the original exception was lost without being released.
   Now properly retains the saved exception and releases it if the
   defer throws a new exception.

3. task join: When joining a task that threw an exception, the
   exception_state was copied without retaining the exception_value,
   leading to incorrect refcounting. Now retains the exception value
   when copying from task to caller context.

https://claude.ai/code/session_01DfpaWxNKzvp8vMc6sEhLjC
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants