fix(wit): export module functions through interfaces so write cannot shadow libc - #20
Conversation
…t shadow libc A world-level `export write` becomes a core-module symbol named `write`, which the linker resolves in place of wasi-libc's `write(2)`. With the current stable Rust, std's wasip2 stdout/stderr go through libc `write`, so any guest that prints (the stdout sink, or a panic message from any module) calls its own export with garbage arguments and corrupts its heap. Symptom: `stdout_sink.wasm!dlfree` trap, reproduced locally and in CI on Linux. Move the exports into `processor-impl` / `sink-impl` interfaces. Core symbols are now `envio:hyperpipe/sink-impl#write` etc. and cannot collide with anything. The host calls `bindings.envio_hyperpipe_sink_impl().call_write(..)`; the SDK macros implement the interface `Guest` trait; the raw-bindgen blackhole sink imports it. Module authors using the SDK see no change. `cargo test -p hp-wasm-host --test integration`: 32/32 (was 30/32). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tj76igEYjgdV7iZ7kaMxN8
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Essentials Run ID: 📒 Files selected for processing (6)
Included review availability: 2 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 5 reviews per hour. 📝 WalkthroughWalkthroughThe WIT contracts now export processor and sink operations through named implementation interfaces. SDK Guest implementations and wasm-host calls use the generated interface-specific bindings. ChangesInterface namespacing
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to The processor and sink exports are consistently namespaced to prevent the libc write-symbol collision. Modules must be rebuilt, but no actionable merge-blocking issue remains. Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 3 files. (3 skipped: 3 unsupported.)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
Warning Some tools did not complete. Review the errors below. 🔧 Clippy (1.97.1)Clippy execution failed Comment |
…orts # Conflicts: # crates/wasm-host/src/lib.rs
Summary
Found while getting CI green:
decoder_then_stdout_roundtripandstdout_and_blackhole_sinks_accept_writes_and_flushesfail onmain, locally and on the Linux runner, with a trap instdout_sink.wasm!dlfree.Cause. The
sinkworld exportedwriteat world level, so the core module carries a symbol literally namedwrite. wasm-ld resolves wasi-libc'swrite(2)to it instead of pulling libc's own. Current stable Rust routes wasip2 stdout/stderr through libcwrite, so the moment a guest prints (the stdout sink, or any module's panic message) it calls its ownwriteexport with libc's arguments and corrupts its heap. The backtrace shows exactly that chain:Stderr::write_all→write→_export_write_cabi→dlfreetrap.Fix. Exports move into
processor-implandsink-implinterfaces (wit/hyperpipe.wit, mirrored inexamples/witand the ARCHITECTURE excerpt). Core symbols becomeenvio:hyperpipe/sink-impl#writeand cannot collide with anything. Host side callsbindings.envio_hyperpipe_sink_impl().call_write(..); the SDK export macros implement the interfaceGuest; the raw-bindgenblackhole-sinkimports it. Modules written against the SDK need no source change, just a rebuild.This is a WIT change, so existing compiled
.wasmartifacts must be rebuilt (./scripts/build-modules.sh,just build-example-module).Test plan
cargo test -p hp-wasm-host: lib 44/44, integration 32/32 (was 30/32)cargo test -p hp-cli,cd modules && cargo testexamples/modules/enrichbuild forwasm32-wasip2Touches
crates/wasm-host/src/lib.rsnear the same lines as #19 (wasmtime bump); whichever merges second gets a trivial conflict.🤖 Generated with Claude Code
https://claude.ai/code/session_01Tj76igEYjgdV7iZ7kaMxN8
Summary by CodeRabbit