Repository navigation
fix(peer): stop leaking pooled buffer memory over structured-clone transports - #145
Conversation
`OctetStreamTransmitter` forwarded each chunk as-is. A chunk that is a view onto a larger ArrayBuffer (Node pooled `Buffer` slices from `Buffer.from`, `Buffer.concat`, `allocUnsafe`, `subarray`) sent over a transport that structured-clones raw messages (Worker, MessagePort, Electron IPC) cloned the whole backing buffer to the receiver, including unrelated pooled data. Copy a chunk when its view doesn't cover its whole buffer. Chunks that already own their buffer are still sent without a copy. The other binary send paths are unaffected: atomic bodies are always Blobs, and `encodePeerMessage` copies into a fresh frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011cCB5ionSFz6U6a1SUr1T8
Drop the `byteOffset === 0` clause (implied by a view covering its whole buffer), shorten the helper's doc comment, and fold the two transmitter tests into one that covers both the copy and the pass-through branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011cCB5ionSFz6U6a1SUr1T8
@standard-server/aws-lambda
@standard-server/core
@standard-server/fastify
@standard-server/fetch
@standard-server/node
@standard-server/peer
@standard-server/shared
commit: |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Merging this PR will not alter performance
Comparing Footnotes
|
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Standalone-bytes copy in
OctetStreamTransmitter—toStandaloneBytes()returns a chunk unchanged when it covers its whole backingArrayBuffer(byteLength === buffer.byteLength, which impliesbyteOffset === 0) and otherwise copies withnew Uint8Array(bytes); applied to every binary chunk intransmit()(packages/peer/src/octet-stream.ts:39,:83). - Regression test — feeds a pooled
Buffer.from('hello')and a whole-bufferUint8Arraythrough aReadableStream, asserting the pooled chunk is copied to an exactly-sized buffer (the discriminatingbuffer.byteLength === byteLengthcheck) while the whole-buffer chunk is passed by identity (packages/peer/src/octet-stream.test.ts:146).
The premise checks out: structuredClone(Buffer.from('hello')) produces a clone with buffer.byteLength === 65536 while byteLength === 5, so raw structured-clone senders do ship the whole pool. StandardBody only surfaces binary as Blob or ReadableStream<Uint8Array>, and encodeAtomicStandardBody never emits a pooled Uint8Array for atomic bodies, so the octet stream is the only pool-exposed path and both peers route it through this transmitter. new Uint8Array(bytes) is the right copy (.slice() on a Buffer returns a view, as the comment notes).
Verified locally: pnpm --filter @standard-server/peer exec vitest run (261 passed) and tsc -b (clean).
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

Summary
This change optimizes octet stream transmission by ensuring that only the actual data being sent is transmitted to remote peers, rather than the entire backing
ArrayBufferwhen chunks are views into larger pooled buffers (common in Node.js).Key Changes
toStandaloneBytes()utility function that detects when aUint8Arrayis a view into a larger buffer and creates a copy containing only the relevant dataOctetStreamTransmitter.transmit()to calltoStandaloneBytes()on all binary chunks before sending, preventing structured-clone from serializing unused buffer memoryImplementation Details
toStandaloneBytes()function checks ifbyteLength === buffer.byteLengthto determine if the array is a standalone viewnew Uint8Array(bytes)to create a copy rather thanbytes.slice()sinceBuffer#slice()returns a view, not a copyhttps://claude.ai/code/session_011cCB5ionSFz6U6a1SUr1T8