fix(wasi): component file read returns bytes in a guest-owned buffer (SR-38, #405) - #407
Merged
Merged
Conversation
…(SR-38, #405) After SR-37 (get-directories) a preview2 component could open+stat a file under --wasi-fs but not READ it: wasi:io/streams input-stream.blocking-read wrote the returned list<u8> to a FIXED raw address (0x100000 + handle*0x10000) the guest never allocated. The guest copies then FREES that list (wasi-libc), so freeing an unallocated pointer corrupted the guest allocator, causing a bad indirect call and [Runtime][E07DA] Function not found in exports. It also re-read the whole file from offset 0 each call with no EOF, so the read loop never terminated. The fix (the component WASI path is dispatch_canon_lowered, which auto-lowers a handler's returned core values to the retptr via lower_results_to_retptr): - blocking-read/read now return core values [I32(0), buf_ptr, n] for ok and [I32(1), I32(1)] for stream-error::closed, matching the Result(ListU8, stream-error) signature, with no manual retptr write. - The list<u8> bytes live in a fresh cabi_realloc'd buffer allocated per read (allocate_wasi_read_buffer, sized to the requested len, capped 1 MiB), set on the dispatcher via new HostImportHandler::set_read_buffer_allocation. On-demand allocation is added in dispatch_canon_lowered (component path) and call_wasi_function (core-module path), before delegating to the handler. - A per-stream read offset (HashMap) advances by bytes returned and yields closed once the file is exhausted, which is the guest's EOF signal. Confirmed by a read-only preview2 component that now prints READ:CANARY and completes cleanly, matching `wasmtime run --dir .::.`. Two unit oracles assert the read returns bytes in the owned buffer and EOFs, and fails loud without one. #405 stays open: directory enumeration (read-directory / read-directory-entry) is still unimplemented, filed as SR-39. v0.4.1 cuts when that lands and closes #405 end-to-end. Trace: SR-38
🔍 Build Diagnostics ReportSummary
🎯 Impact AnalysisIssues in Files You Modified
Cascading Issues (Your Changes Breaking Other Files)
✅ No Issues DetectedPerfect! Your changes don't introduce any new errors or warnings, and don't break any existing code. 📊 Full diagnostic data available in workflow artifacts 🔧 To reproduce locally: # Install cargo-kiln
cargo install --path cargo-kiln
# Analyze your changes
cargo-kiln build --output json --filter-severity error
cargo-kiln check --output json --filter-severity warning |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This was referenced Jul 10, 2026
avrabe
added a commit
that referenced
this pull request
Jul 10, 2026
…) (#410) Version bump 0.4.0 → 0.4.1. Ships the complete component filesystem read/list fix for WASI Preview2 components under kilnd --wasi --component --wasi-fs: - SR-37 (#406): get-directories returns a guest-usable preopen list. - SR-38 (#407): file read (blocking-read) returns bytes in a guest-owned buffer with offset/EOF tracking. - SR-39 (#409): directory enumeration (read-directory / read-directory-entry). Together these make a preview2 component read and list files under a preopen, matching `wasmtime run --dir`. Closes #405. Trace: SR-39
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Second layer of #405. After SR-37 (#406) a preview2 component could open+stat a file under
--wasi-fsbut reading it crashed with[Runtime][E07DA] Function not found in exports.Root cause (measured, trace-driven)
wasi:io/streamsinput-stream.blocking-readwrote the returnedlist<u8>to a fixed raw address (0x100000 + handle*0x10000) the guest never allocated. wasi-libc copies then frees the returned list — freeing an unallocated pointer corrupted the guest allocator → bad indirect call → E07DA. It also re-read the whole file from offset 0 every call with no EOF, so the read loop never terminated.Fix
The component WASI path is
dispatch_canon_lowered, which auto-lowers a handler's returned core values to the retptr vialower_results_to_retptrusing theResult(ListU8, stream-error)signature. So:blocking-read/readnow return core values[I32(0), buf_ptr, n](ok) /[I32(1), I32(1)](stream-error::closed) — no manual retptr write.cabi_realloc'd buffer per read (allocate_wasi_read_buffer, sized to the requested len, capped 1 MiB), set via newHostImportHandler::set_read_buffer_allocation. On-demand allocation added indispatch_canon_lowered(component path) andcall_wasi_function(core-module path).closedat EOF.Verification
READ:CANARYand completes cleanly, matchingwasmtime run --dir .::..// rivet: verifies SR-38): read returns bytes in the owned buffer + EOFs; fails loud without a buffer.Scope
#405 stays open — directory enumeration (
read-directory/read-directory-entry) is still unimplemented, filed as SR-39. v0.4.1 cuts when that lands and closes #405 end-to-end.Trace: SR-38
🤖 Generated with Claude Code