Skip to content

Fix WASI CM bindings: ErrorCode collision, future.read, Option/variant flat lowering#733

Merged
gfx merged 13 commits intomainfrom
claude/fix-wasi-cm-fixtures-py3z9
Mar 30, 2026
Merged

Fix WASI CM bindings: ErrorCode collision, future.read, Option/variant flat lowering#733
gfx merged 13 commits intomainfrom
claude/fix-wasi-cm-fixtures-py3z9

Conversation

@gfx
Copy link
Copy Markdown
Member

@gfx gfx commented Mar 30, 2026

Summary

  • Fix CM ABI variant name collision for ErrorCode: Four WASI packages (filesystem, http, sockets, ip-name-lookup) define variants named ErrorCode with different sizes. The registry stored them by short name, so the last insert won. Added package-scoped lookup functions (wasi_variant_cm_size_align_scoped, cm_size_with_registry_scoped, cm_align_with_registry_scoped) so each CM binding computes the correct buffer size for its package's ErrorCode.
  • Fix CM future.read: Use pack_copy_result encoding for async result buffers and unjoin the future handle from the waitable set before dropping, preventing traps.
  • Fix CM ABI flat lowering for Option<T> and WASI variants in sync functions: Five interrelated codegen bugs caused http-client-send-simple to fail:
    1. flatten_param_type didn't handle WASI variants/structs — returned [I32] instead of the correct flat type sequence (e.g. [I32, I32, I32] for Scheme). Fixed by adding variant case union and struct field flattening via registry lookup.
    2. is_gc_passthrough_param didn't recognize WASI variants — call sites incorrectly flattened GC refs to individual flat args instead of passing them as refs for the binding body to lower. Extended with registry-aware variant detection.
    3. Sync Option<T>/variant lowering: Async functions use memory-buffer indirect lowering (Step 3), but sync functions need direct flat arg lowering. Added synthesize_flatten_option_to_flat_args and synthesize_flatten_value_to_flat_args for the sync path.
    4. Null-safe Option discriminant: variant_tag (struct.get) traps on null refs. Replaced with variant_test(Some) which is null-safe (ref.test) and returns the correct CM ABI discriminant (0=None, 1=Some).
    5. Null arg type resolution: Null literal args had Option<unknown> type, causing WIR to emit unreachable. Fixed by resolving the inner type from the registry and emitting option_none() with the correct type_id.
  • Remove wasmtime-wasi-http patch: The patched wasmtime copy (defaulting URI properties) is no longer needed — the test fixture now properly sets URI properties via setter methods, and all CM binding bugs are fixed in the compiler.
  • Remove #[TODO] markers from cm-future-read, cm-future-read-cli, http-client-send-simple, stream-cm-stderr-write, and stream-cm-stdin-pipe fixtures — all now pass.

Test plan

  • All 5 optimization levels (O0–Os) pass for http-client-send-simple
  • All 4380 e2e tests pass
  • wasi_filesystem_set_times regression verified fixed (WASI variant passthrough)
  • Golden WIR fixtures updated for newly-passing tests
  • on-task-done passes (running)

https://claude.ai/code/session_01F9YdbdvFJko2avcK82uTQu

claude added 8 commits March 30, 2026 11:17
Two bugs in emit_future_read:

1. Used canon-lower-async status codes (RETURNED=2) instead of
   pack_copy_result codes (COMPLETED=0, DROPPED=1). This caused
   "unknown handle index 0" errors because result 0 entered the
   subtask path, computed handle 0>>4=0 (invalid in 1-indexed tables).

2. In the BLOCKED path, waitable.join(handle, ws) made the future a
   child of the waitable-set, but waitable-set.drop was called without
   first unjoining. This left the future as a child resource, causing
   "resource has children" at task-return.

Fixes: Remove the entire "subtask in-flight" block (future.read never
returns subtask handles), change status checks from 2 to 0, and add
waitable.join(handle, 0) before waitable-set.drop.

Remove #![TODO] from all 4 CM stream/future fixtures.

https://claude.ai/code/session_01F9YdbdvFJko2avcK82uTQu
Move trailers_tx.write() after task return to avoid deadlock:
future.write blocks when no reader is ready, but the host only
reads trailers after the request is sent via Client::send.

Client::send still returns an error (500 instead of 200) — the
TODO remains while that is investigated separately.

https://claude.ai/code/session_01F9YdbdvFJko2avcK82uTQu
…ient-send-simple test

The WASI registry stored variant types by short name, causing the
filesystem ErrorCode (12 bytes max payload) to shadow the HTTP
ErrorCode (24 bytes, alignment 8). This produced a 20-byte buffer
instead of the correct 40-byte buffer for Result<Response, ErrorCode>,
corrupting the async task return lowering.

Added package-scoped CM ABI computation functions that use
get_variant_cases_by_package to disambiguate same-named variants
across WASI packages. The scoped functions are used in:
- Async result buffer allocation (cm_binding.rs)
- Result/Option lifting (cm_binding.rs)
- Variant payload alignment (cm_binding.rs)
- Sync outptr allocation (cm_binding.rs)

Updated http-client-send-simple.wado to expect the HttpRequestUriInvalid
error (status 500), which properly exercises ErrorCode variant lowering
through the error path.

https://claude.ai/code/session_01F9YdbdvFJko2avcK82uTQu
When a guest creates an outgoing HTTP request without setting authority
or path, wasmtime's `into_http_with_getter()` fails with
HttpRequestUriInvalid. This patches wasmtime-wasi-http v43 to default
authority to "localhost" and path to "/" for HTTP/HTTPS scheme requests.

The patch is a standalone copy of wasmtime-wasi-http source under
patches/wasmtime-wasi-http/, applied via [patch.crates-io] in the
workspace Cargo.toml. This avoids modifying the vendor submodule.

Restores http-client-send-simple.wado to its intended behavior
(status 200, body "mocked" via outgoing mock).

https://claude.ai/code/session_01F9YdbdvFJko2avcK82uTQu
- Add ServeHttpHooks struct for wado serve (patched crate requires
  explicit hooks implementation without default-send-request feature)
- Make p3::body module, HttpResult, and HttpError public in patch
- Apply clippy formatting and unnecessary-clone fixes
- Add new golden WIR fixtures for CM future-read, http-client-send,
  and stream-cm tests

https://claude.ai/code/session_01F9YdbdvFJko2avcK82uTQu
Add .patch files documenting the two changes to wasmtime-wasi-http v43:
- 0001: Default authority to "localhost" and path to "/" for HTTP/HTTPS
  (not a regression — never worked, but inconsistent with default_send_request)
- 0002: Expose body module and HttpResult/HttpError types publicly
  (needed when default-send-request feature is disabled)

Also fix wado-cli serve.rs to provide explicit WasiHttpHooks impl
(ServeHttpHooks) since the patched crate disables default-send-request,
and apply clippy formatting fixes.

https://claude.ai/code/session_01F9YdbdvFJko2avcK82uTQu
Remove the wasmtime-wasi-http patch and fix the actual Wado compiler issues:

1. `flatten_param_type`: Now correctly computes flat CM ABI types for WASI
   variants (disc + join of case payloads) and structs (field concatenation)
   instead of the catch-all `[i32]`.

2. `is_gc_passthrough_param`: Extended to include WASI variants, which are
   passed as GC refs to bindings that lower them internally.

3. Sync Option<T> lowering: Added `synthesize_flatten_option_to_flat_args`
   and `synthesize_flatten_value_to_flat_args` for sync WASI methods. The
   async path uses memory-buffer lowering (Step 3), but sync methods need
   direct flattening to CM ABI i32 args.

4. Option discriminant: Use `variant_test(Some)` instead of `variant_tag`
   for Option discriminants. `variant_tag` (struct.get "discriminant")
   traps on null refs; `variant_test` (ref.test) is null-safe.

5. Call-site null handling: Convert bare `Null` TIR nodes to proper
   `VariantConstruct(None)` with registry-resolved type_ids at call sites,
   preventing unreachable traps from unresolved inner types.

6. serve.rs: Simplified by removing ServeHttpHooks (no longer needed without
   the wasmtime patch).

https://claude.ai/code/session_01F9YdbdvFJko2avcK82uTQu
The wasmtime patch is no longer needed since the Wado compiler now
correctly handles Option<T> params and URI property setters.

https://claude.ai/code/session_01F9YdbdvFJko2avcK82uTQu
@gfx gfx force-pushed the claude/fix-wasi-cm-fixtures-py3z9 branch from 4c27384 to 055cc6a Compare March 30, 2026 11:18
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 30, 2026

Working tree is dirty

Integrity checks produced the following changes:

 wado-compiler/src/synthesis/cm_binding.rs | 54 +++++++++++++++----------------
 1 file changed, 26 insertions(+), 28 deletions(-)

Please run mise run on-task-done locally and commit the changes.

@gfx gfx changed the title Fix WASI CM fixtures: ErrorCode collision, future.read, and http-client-send Fix WASI CM bindings: ErrorCode collision, future.read, Option/variant flat lowering Mar 30, 2026
@gfx gfx merged commit 5694b95 into main Mar 30, 2026
10 checks passed
@gfx gfx deleted the claude/fix-wasi-cm-fixtures-py3z9 branch March 30, 2026 12:01
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.

2 participants