read_file masks setup failures and leaks partial resources
Summary
hf3fs_fuse.io.read_file() assumes every setup step completed when its
finally block runs. If setup fails early, cleanup raises UnboundLocalError,
replaces the useful original exception, and can skip releasing resources that
were already acquired.
Reproduction
The behavior is deterministic without a 3FS mount by replacing the native binding with a stub:
- Make
os.open()raiseFileNotFoundError. - Call
read_file(). - Observe
UnboundLocalErrorfor the unassigned localfdinstead of the original file error.
The same masking happens when register_fd(), SharedMemory(), make_iovec(),
or make_ioring() fails. In the make_iovec() case, del ior raises before
shm.close() and shm.unlink() run, so the partially created shared memory is
not released by this function.
This is separate from #291's underlying os.symlink() failure: a failure from
that call currently enters this broken cleanup path and can be replaced by an
unrelated UnboundLocalError.
Expected behavior
read_file() should preserve the original setup error and release only the
file descriptor, native registration, iovec/ioring, and shared-memory resources
that were successfully acquired.
The regression can be covered with a host-only Python test using stubbed native bindings; no 3FS mount, RDMA device, or external service is required.
Source: deepseek-ai/3FS