Skip to content

fix: release parser on Init/Final handler exceptions#258

Draft
toddr-bot wants to merge 1 commit intomainfrom
koan.toddr.bot/fix-handler-resource-leak
Draft

fix: release parser on Init/Final handler exceptions#258
toddr-bot wants to merge 1 commit intomainfrom
koan.toddr.bot/fix-handler-resource-leak

Conversation

@toddr-bot
Copy link
Copy Markdown
Collaborator

What

Ensure $expat->release is always called even when Init or Final handlers die.

Why

When an Init or Final handler throws an exception, the release() call is skipped. Since self_sv (the C-side back-reference to the Perl hash) still holds a reference, a circular reference is created. Perl's reference counting GC never collects the object — DESTROY is never called, and the entire parser (C struct, all handler SVs, the Perl hash) leaks permanently.

How

  • Wrap &$init($expat) in eval with release-on-error in both parse() and parse_start()
  • Wrap &$final($expat) in eval with release-after in parse(), capturing wantarray before the eval block (since wantarray doesn't propagate through eval)
  • The exception is always re-thrown after cleanup, preserving existing behavior for callers

Testing

Added 7 tests to t/parser_api.t covering Init/Final die paths and parser reuse after handler failure. Full suite passes (683 tests).

🤖 Generated with Claude Code

When Init or Final handlers die, the expat parser was not released,
creating a circular reference leak (self_sv holds a ref to the Perl
hash, preventing DESTROY from ever being called). The entire C parser
struct, all handler SVs, and the Perl object leaked permanently.

Wrap Init and Final handler calls in eval blocks with release-on-error
cleanup in both parse() and parse_start(). This ensures the parser is
always properly released regardless of handler behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 15, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 75.73%. Comparing base (45216a7) to head (c988dbb).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #258   +/-   ##
=======================================
  Coverage   75.73%   75.73%           
=======================================
  Files           1        1           
  Lines        1092     1092           
  Branches      342      342           
=======================================
  Hits          827      827           
  Misses         59       59           
  Partials      206      206           
Flag Coverage Δ
perl 75.73% <ø> (ø)
xs 75.73% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

1 participant