Conversation
resolve_size and resolved_size held the same size rules twice. One wrote the offset and size onto the blob, the other returned the pair. The two bodies agree in every arm, and both stat a file store under the same condition. resolve_size now takes the pair from resolved_size and stores it. The Stacked Borrows comment and the FIFO comment move to resolved_size, because the code they describe lives there now. No caller can observe a difference.
|
Updated 8:35 AM PT - Sep 24th, 2026
✅ @robobun, your commit a49a8256e50c09179a7425cec1f18ca19e4f985e passed in 🧪 To try this PR locally: bunx bun-pr 43897That installs a local version of the PR into your bun-43897 --bun |
|
Status: ready for review. This PR is a refactor with no behaviour change, and it is the first of a stack of three. How it was checked:
The bug the stack fixes, on canary 1.4.3+367d939d9 (Linux): const f = Bun.file("/proc/self/status");
f.size; // or: await f.exists()
await f.text(); // "" (a fresh Bun.file(p).text() returns about 1500 bytes)The same cached size makes #4930 write 0 bytes. The next two PRs follow once this one has a green build. |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: oven-sh/bun/.coderabbit.yaml Review profile: ASSERTIVE Plan: Essentials Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 10 included reviews per hour; 0 remain after this review. Walkthrough
ChangesBlob size resolution
Suggested reviewers: Merge Risk: ⚪ Minimal · up to The Blob size-resolution change preserves the inspected behavior, with no actionable merge risk identified. 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.
Beyond the inline comment, I also checked the equivalence claim arm by arm in resolved_size (no store, Bytes with and without a known store size, File with stat known / not seekable / stat failed, S3) against the deleted resolve_size body — each arm returns exactly the pair the old code stored, available is computed against the clamped offset as before, and the new unconditional offset write-back only ever stores the value already in the Cell. resolve_file_stat mutates only the store's File, not the blob's offset/size, so applying the pair after the stat is order-safe.
Extended reasoning...
The change touches only src/runtime/webcore/Blob.rs, collapsing the mutating resolve_size into a wrapper over the existing non-mutating resolved_size. It touches no security-sensitive surface. The refactor is behavior-preserving on every store arm, but one inline finding about the moved Stacked-Borrows comment was reported, so a defer note recording the equivalence check is the appropriate output rather than an approval.
Problem
Blob::resolve_sizeandBlob::resolved_size(src/runtime/webcore/Blob.rs) hold the same size rules twice. One writesoffsetandsizeonto the blob. One returns the pair.ByteBlobLoader::setupdisagree with the nineresolve_sizecallers. A follow-up changes the rules for file stores. It must change them in one place.Fix
resolve_sizetakes the pair fromresolved_sizeand stores it.resolved_sizekeeps the rules.resolved_size, where that code now lives.blob.test.ts,body.test.ts,body-clone.test.ts,wasm-streaming.test.tsandstructured-clone-blob-file.test.tscover this code and pass. More in Notes.Behaviour change: none
Background
Blobis a view (offset,size) onto a store: memory, a file, or an S3 object.sizeisMAX_SIZEwhile unknown. Resolving fills it in from the store. For a file that is onestat, cached on the store.resolve_sizeserves.size,exists(), body streams,FormData, HEADContent-Lengthand structured clone.resolved_sizeexists becauseByteBlobLoader::setupresolves a blob that it cannot mutate.Downsides
statruns under the same condition. No call gains an allocation or a syscall. Arms that stored nothing now store the values already there.Notes
The two bodies, arm by arm. "stores" is what
resolve_sizewrote before this PR. "returns" is whatresolved_sizereturns.resolve_sizestoresresolved_sizereturnssize = 0(offset, 0)offset = min(len, offset),size = window_size(size, len - offset)offset = min(st_size, offset),size = window_size(size, st_size - offset)(offset, size)size = 0(offset, 0)size = 0(offset, 0)Suites run with a debug build:
blob.test.ts,body.test.ts,body-clone.test.ts,wasm-streaming.test.ts,structured-clone-blob-file.test.ts: 1044 pass, 0 fail.fetch.test.ts,bun-file-exists.test.js,bun-file.test.ts,bun-file-read.test.ts,bun-serve-file.test.ts,FormData.test.ts: 663 pass and 21 fail, with this change and withsrc/at main. The set of failing test names is identical in both runs. The 21 need IPv6, the public internet, a non-root user, or more than 5 s under ASAN, and the test machine has none of these.This PR is the first of a stack of two. #43910 is the second, and its base is this branch. It stops
resolve_sizefrom copying a cachedstatsize onto a file blob, which is the cause of #4930 and #23902, and it lets each file reader stop at the size from its ownfstat.no test proof · iteration 0 · the description declares no behaviour change, so there is no failing test to prove; the existing suite in CI is the check