about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/miri/README.md2
-rwxr-xr-xsrc/tools/miri/ci/ci.sh2
-rw-r--r--src/tools/miri/src/shims/wasi/foreign_items.rs68
3 files changed, 70 insertions, 2 deletions
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 517aa343a6d..7094231b902 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -220,7 +220,7 @@ degree documented below):
   - `solaris` / `illumos`: maintained by @devnexen. Supports the entire test suite.
   - `freebsd`: maintained by @YohDeadfall and @LorrensP-2158466. Supports the entire test suite.
   - `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works.
-  - `wasi`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works.
+  - `wasi`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works.
 - For targets on other operating systems, Miri might fail before even reaching the `main` function.
 
 However, even for targets that we do support, the degree of support for accessing platform APIs
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index 6356e33f61e..bcc110f648b 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -153,7 +153,7 @@ case $HOST_TARGET in
     BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator
     UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
     TEST_TARGET=aarch64-linux-android  run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency epoll eventfd
-    TEST_TARGET=wasm32-wasip2          run_tests_minimal $BASIC wasm
+    TEST_TARGET=wasm32-wasip2          run_tests_minimal $BASIC hello wasm
     TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std
     TEST_TARGET=thumbv7em-none-eabihf  run_tests_minimal no_std
     ;;
diff --git a/src/tools/miri/src/shims/wasi/foreign_items.rs b/src/tools/miri/src/shims/wasi/foreign_items.rs
index bfcdbd8130d..ffc02dc986f 100644
--- a/src/tools/miri/src/shims/wasi/foreign_items.rs
+++ b/src/tools/miri/src/shims/wasi/foreign_items.rs
@@ -35,6 +35,74 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_pointer(res, dest)?;
             }
 
+            // Standard input/output
+            // FIXME: These shims are hacks that just get basic stdout/stderr working. We can't
+            // constrain them to "std" since std itself uses the wasi crate for this.
+            "get-stdout" => {
+                let [] =
+                    this.check_shim_sig(shim_sig!(extern "C" fn() -> i32), link_name, abi, args)?;
+                this.write_scalar(Scalar::from_i32(1), dest)?; // POSIX FD number for stdout
+            }
+            "get-stderr" => {
+                let [] =
+                    this.check_shim_sig(shim_sig!(extern "C" fn() -> i32), link_name, abi, args)?;
+                this.write_scalar(Scalar::from_i32(2), dest)?; // POSIX FD number for stderr
+            }
+            "[resource-drop]output-stream" => {
+                let [handle] =
+                    this.check_shim_sig(shim_sig!(extern "C" fn(i32) -> ()), link_name, abi, args)?;
+                let handle = this.read_scalar(handle)?.to_i32()?;
+
+                if !(handle == 1 || handle == 2) {
+                    throw_unsup_format!("wasm output-stream: unsupported handle");
+                }
+                // We don't actually close these FDs, so this is a NOP.
+            }
+            "[method]output-stream.blocking-write-and-flush" => {
+                let [handle, buf, len, ret_area] = this.check_shim_sig(
+                    shim_sig!(extern "C" fn(i32, *mut _, usize, *mut _) -> ()),
+                    link_name,
+                    abi,
+                    args,
+                )?;
+                let handle = this.read_scalar(handle)?.to_i32()?;
+                let buf = this.read_pointer(buf)?;
+                let len = this.read_target_usize(len)?;
+                let ret_area = this.read_pointer(ret_area)?;
+
+                if len > 4096 {
+                    throw_unsup_format!(
+                        "wasm output-stream.blocking-write-and-flush: buffer too big"
+                    );
+                }
+                let len = usize::try_from(len).unwrap();
+                let Some(fd) = this.machine.fds.get(handle) else {
+                    throw_unsup_format!(
+                        "wasm output-stream.blocking-write-and-flush: unsupported handle"
+                    );
+                };
+                fd.write(
+                    this.machine.communicate(),
+                    buf,
+                    len,
+                    this,
+                    callback!(
+                        @capture<'tcx> {
+                            len: usize,
+                            ret_area: Pointer,
+                        }
+                        |this, result: Result<usize, IoError>| {
+                            if !matches!(result, Ok(l) if l == len) {
+                                throw_unsup_format!("wasm output-stream.blocking-write-and-flush: returning errors is not supported");
+                            }
+                            // 0 in the first byte of the ret_area indicates success.
+                            let ret = this.ptr_to_mplace(ret_area, this.machine.layouts.u8);
+                            this.write_null(&ret)?;
+                            interp_ok(())
+                    }),
+                )?;
+            }
+
             _ => return interp_ok(EmulateItemResult::NotSupported),
         }
         interp_ok(EmulateItemResult::NeedsReturn)