Skip to content

Let a MountCore handle go when its landing at release fails - #1637

Merged
zechengz merged 1 commit into
mainfrom
claude/mountcore-release-leak
Oct 17, 2026
Merged

zechengz merged 1 commit into
mainfrom
claude/mountcore-release-leak

Conversation

@bytecii

@bytecii bytecii commented Oct 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

MountCore.release flushed the handle and then popped it, on both hosts. If the flush raised, the pop never ran. That happens when a pwrite is refused by a policy or a mount mode (opening an existing file for write without O_TRUNC checks neither), or when the backend fails. The handle and its buffered bytes then stayed in the table until the core went away, because no adapter retries a release:

  • FUSE: the kernel ignores the error a RELEASE returns.
  • SFTP: asyncssh and the TS server forget the SFTP handle before calling release, and sshfs never waits for the FXP_CLOSE reply.
  • codex-exec: releases once, in a finally.

release now pops the handle in a finally and still raises the failure to the adapter. This follows Linux close(2), which frees the descriptor even when it reports an error.

Found while working on #1636. Its MountCore.sync runs at the end of every sandbox line, and it would otherwise have retried such a leaked handle and logged a warning after every line. This change is independent of #1636 and is based on main.

Test plan

  • New tests, Python tests/mount/test_core.py and TS core.test.ts: on a read-only workspace, a release whose landing is refused raises, the handle is gone, and the file still holds its old bytes. Both tests fail on main.
  • pytest for mount/fuse/server/runtime; vitest for node mount/fuse and server ssh; tsc for node.
  • Symbol and layout parity (strict), pre-commit, mypy.

🤖 Generated with Claude Code

MountCore.release flushed and then popped the handle, so a flush that
raised (a pwrite a policy or mount mode refuses, a backend error) left
the handle in the table for good. No adapter retries a release: the
kernel ignores a RELEASE error, sshfs never waits for its FXP_CLOSE
reply, and codex releases once in a finally. The handle and its bytes
stayed until the core went away.

Release now pops the handle whatever the flush did, as close(2) frees
its descriptor even when it reports an error, and still raises the
failure to the adapter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bytecii
bytecii requested a review from zechengz as a code owner October 17, 2026 01:42
@greptile-apps

greptile-apps Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5 Tier: apex

[Medium impact] The PR appears safe to merge; failed releases free their handles while preserving error reporting.

Summary

MountCore.release now removes the handle in finally in both languages, while still passing any write failure to the caller.

  • Mount releases drop handles even when buffered writes fail.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A["release(handle)"] --> B["Attempt flush"]
  B -->|Success| C["finally: remove handle"]
  B -->|Failure| C
  C --> D{"Did flush fail?"}
  D -->|No| E["Return"]
  D -->|Yes| F["Pass error to caller"]
Loading

Reviews (1) · Last reviewed commit: "Let a MountCore handle go when its landi..." · Reviewed by Greptile

@zechengz
zechengz merged commit 558a1fa into main Oct 17, 2026
66 checks passed
@zechengz
zechengz deleted the claude/mountcore-release-leak branch October 17, 2026 02:12
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