Skip to content

fix: free value buffer, data struct and async work in the async path - #48

Open
guillaume-flambard wants to merge 1 commit into
LinusU:masterfrom
guillaume-flambard:fix/async-memory-leak
Open

guillaume-flambard wants to merge 1 commit into
LinusU:masterfrom
guillaume-flambard:fix/async-memory-leak

Conversation

@guillaume-flambard

Copy link
Copy Markdown

Fixes #47. Also fixes the leak reported against storage-api in supabase/storage#1349.

Credit for the diagnosis goes to @djonua: #47 pins the exact faulty lines, isolates the bug against the sync path, and carries the production numbers. This PR implements the fix outlined there.

What leaked on every async call:

  • the value buffer in xattr_get_execute and the result buffer in xattr_list_execute were never freed
  • the error branch of each complete callback returned without freeing the data struct
  • the napi_async_work handle lived in a function-local and napi_delete_async_work was never called, so one work object leaked per call

Changes, same shape across all four operations:

  • keep the work handle in the per-call struct
  • delete the async work and free every buffer plus the struct on a single exit path
  • allocate the per-call struct with calloc, so a failed size probe cannot leave an uninitialized pointer behind

Regression test: 300k async set/get/remove calls, bounded at 20 MB of rss growth. On the unfixed build it fails at ~150 MB (about 0.5 kB per call, matching the numbers in #47). With the fix it passes. A direct 200k async get run on this machine measured 7.5 MB total growth (0.04 kB per call).

Happy to adjust if you would rather see the struct freed before the work is deleted, or any other ordering.

Every async call leaked the value buffer (get/list), the data struct on
error branches, and the napi_async_work handle (never deleted). The sync
path was already correct.

- keep the async work handle in the per-call struct so it can be deleted
- delete the async work and free all buffers/struct on every exit path
- zero-initialise the per-call struct so failed size probes do not leave
  garbage pointers behind

Regression test: 300k async set/get/remove calls bounded at 20 MB rss
growth (fails at ~150 MB without the fix).
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.

Memory leak in async get/set/list/remove: value buffer and async work are never freed

1 participant