Skip to content

fix(file): use the sync xattr API, the async path of fs-xattr leaks - #1357

Merged
ferhatelmas merged 2 commits into
supabase:masterfrom
guillaume-flambard:fix/file-backend-xattr-leak
Sep 2, 2026
Merged

ferhatelmas merged 2 commits into
supabase:masterfrom
guillaume-flambard:fix/file-backend-xattr-leak

Conversation

@guillaume-flambard

Copy link
Copy Markdown
Contributor

Fixes #1349 on the storage-api side. The native fix itself is proposed upstream at LinusU/fs-xattr#48.

Credit for the diagnosis goes to @djonua, in this issue and in fs-xattr#47: every async fs-xattr call leaks the value buffer, the per-call struct on error branches, and the napi_async_work handle. The file backend reads two xattrs on every served object, so the leak lands straight on the serve path (their numbers: 0.46 kB per request, about 0.6 GB per day on a 1.3M requests per day instance).

Until an fs-xattr release ships the upstream fix, this switches the file backend to the sync API, which does not leak:

  • getAttribute, setAttribute, removeAttribute become getAttributeSync, setAttributeSync, removeAttributeSync in src/storage/backend/file.ts
  • the protected method signatures are unchanged, the unit test mocks move to the sync names

Tradeoff, already discussed in #1349: the sync calls block the loop for the duration of a local getxattr/setxattr syscall. These are small metadata lookups on local files (cache-control, content-type, etag), and the reporter's own suggestion notes that this is acceptable at this size. If the upstream fix merges and releases, the async calls can come back and this change reverts cleanly.

Tests: 30/30 in file.test.ts. Full unit suite 1759/1760, the one failure (admin-app.test.ts, "registers shared Blob response handling") is pre-existing on master.

@guillaume-flambard
guillaume-flambard requested a review from a team as a code owner September 2, 2026 08:04
@ferhatelmas
ferhatelmas force-pushed the fix/file-backend-xattr-leak branch from bed5f18 to c44f02c Compare September 2, 2026 18:21
@coveralls

coveralls commented Sep 2, 2026 •

Copy link
Copy Markdown

Coverage Report for CI Build 33672207234

Coverage decreased (-0.08%) to 81.766%

Details

  • Coverage decreased (-0.08%) from the base build.
  • Patch coverage: 3 of 3 lines across 1 file are fully covered (100%).
  • 17 coverage regressions across 1 file.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

17 previously-covered lines in 1 file lost coverage.

File Lines Losing Coverage Coverage
src/internal/http/agent.ts 17 32.56%

Coverage Stats

Coverage Status
Relevant Lines: 13275
Covered Lines: 11292
Line Coverage: 85.06%
Relevant Branches: 7883
Covered Branches: 6008
Branch Coverage: 76.21%
Branches in Coverage %: Yes
Coverage Strength: 614.05 hits per line

💛 - Coveralls

guillaume-flambard and others added 2 commits September 2, 2026 22:15
fs-xattr's async path leaks about 0.5 kB per call: the value buffer, the
per-call struct on error branches and the napi_async_work handle are never
freed (fs-xattr#47, fix proposed upstream). Measured on this backend with
production-shaped load: 0.46 to 0.59 kB per served file.

The file backend reads two xattrs on every served object, so self-hosted
instances grow unreclaimable memory all day (supabase#1349:
0.6 GB/day on a 1.3M requests/day instance).

Until fs-xattr ships a fixed release, switch the file backend to the sync
API, which does not leak. Reads are small metadata lookups on local files
(cache-control, content-type, etag), so blocking is acceptable here.
Method signatures are unchanged.
Signed-off-by: Ferhat Elmas <elmas.ferhat@gmail.com>
@ferhatelmas
ferhatelmas force-pushed the fix/file-backend-xattr-leak branch from c44f02c to 4c51b85 Compare September 2, 2026 19:15
@ferhatelmas
ferhatelmas merged commit 0f1f323 into supabase:master Sep 2, 2026
24 of 26 checks passed
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.

Storage file backend leaks ~0.46 kB per served file via abandoned fs-xattr

3 participants