Skip to content

fix: prevent filehandle reference leak in stat override#25

Merged
atoomic merged 1 commit intocpanel:masterfrom
atoomic:koan.atoomic/fix-fh-ref-leak
Feb 22, 2026
Merged

fix: prevent filehandle reference leak in stat override#25
atoomic merged 1 commit intocpanel:masterfrom
atoomic:koan.atoomic/fix-fh-ref-leak

Conversation

@Koan-Bot
Copy link
Contributor

Summary

  • Fix $_last_call_for in _check() to only cache string filenames, not filehandle references
  • Prevents filehandle garbage collection being blocked by a retained reference
  • Adds regression test for the leak

Root Cause

_check() stored its $file argument in $_last_call_for for -X _ caching support. When the argument was a filehandle reference (e.g. from -S $fh), this prevented the filehandle from being garbage collected, keeping the underlying file descriptor open.

This caused "spooky action-at-a-distance" bugs: a socketpair read could hang because a dup'd write-end filehandle was kept alive by the leaked reference.

Fix

# Before:
$_last_call_for = $file;

# After:
$_last_call_for = ref($file) ? undef : $file;

Only string filenames are cached. Filehandle references pass through without being retained.

Test plan

  • New test t/fh-ref-leak.t verifies filehandles are GC'd after file checks
  • Existing -X _ tests still pass (string filename caching preserved)

Ref: cpanel/Test-MockFile#179


🤖 Generated with Claude Code

_check() stored the file argument in $_last_call_for for -X _ caching.
When the argument was a filehandle reference (not a string path), this
prevented the filehandle from being garbage collected, keeping the
underlying file descriptor open.

This caused "spooky action-at-a-distance" bugs: e.g. a socketpair read
hanging because a dup'd write-end filehandle was kept alive by the
leaked reference, even after leaving scope.

Fix: only cache string filenames in $_last_call_for, not references.

Ref: cpanel/Test-MockFile#179

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@atoomic atoomic merged commit a4d1d76 into cpanel:master Feb 22, 2026
21 checks passed
Koan-Bot added a commit to atoomic/Test-MockFile that referenced this pull request Feb 26, 2026
- Remove .claude/worktrees/ submodule entry from tracking
- Add .claude/ to .gitignore
- Remove SKIP wrapper from socketpair test — Overload::FileCheck
  fix (cpanel/Overload-FileCheck#25) is now released

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Koan-Bot added a commit to atoomic/Test-MockFile that referenced this pull request Feb 26, 2026
- Remove .claude/worktrees/ submodule entry from tracking
- Add .claude/ to .gitignore
- Remove SKIP wrapper from socketpair test — Overload::FileCheck
  fix (cpanel/Overload-FileCheck#25) is now released

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
atoomic pushed a commit to cpanel/Test-MockFile that referenced this pull request Feb 26, 2026
- Remove .claude/worktrees/ submodule entry from tracking
- Add .claude/ to .gitignore
- Remove SKIP wrapper from socketpair test — Overload::FileCheck
  fix (cpanel/Overload-FileCheck#25) is now released

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants