feat(wasi): normalize wasi error codes and exit-code propagation - #13625
feat(wasi): normalize wasi error codes and exit-code propagation#13625eduardomourar wants to merge 7 commits into
Conversation
|
GNU testsuite comparison: |
|
Can we avoid introducing many code with |
Merging this PR will not alter performance
Comparing Footnotes
|
ecc7c96 to
650e875
Compare
I had to create 3 separate functions to deal with normalizing the WASI errors, but I think it does what you asked. |
f0f8959 to
60f692a
Compare
On wasm32-wasip2, std::process::exit goes through WASI's stable wasi:cli/exit#exit, which only carries a success/failure bit and collapses every nonzero exit code to 1. This adds uucore::error::process_exit and an opt-in wasip2-exit-with-code feature that, when enabled, instead calls the unstable wasi:cli/exit#exit-with-code so real exit codes propagate; the feature requires a WASI host that explicitly supports it (e.g. wasmtime's -S cli-exit-with-code=y) and is off by default.
Route every direct std::process::exit call in the multi-call binary, uucore's #[uucore::main] macro, and per-util fatal-exit paths (cat, more, shred, sort, tail, tr, tty) through the new process_exit wrapper so they pick up correct wasip2 exit-code propagation when the wasip2-exit-with-code feature is enabled, with no behavior change on other targets.
WASI reports several conditions with different (or no) ErrorKind than native Unix: opening/removing a directory surfaces raw EBADF instead of EISDIR, reading from a directory-backed descriptor surfaces EISDIR under a different errno per preview version, and preview2 reports a broken pipe as raw EIO. This adds wasi_normalize_open_error, wasi_normalize_read_error, and wasi_is_broken_pipe to uucore::error so call sites can convert these to the same ErrorKind/behavior used on Unix; all three are no-ops off WASI. Also fixes read_os_string_lines to return an io::Error on invalid UTF-8 instead of panicking, since argv/filenames aren't guaranteed valid UTF-8 on WASI.
Route open/read errors through the new uucore::error normalization helpers so cat, rm, wc, csplit, tee, sort, seq, tr, tsort, and split report the same ErrorKind/message on WASI as on native Unix: opening or reading a directory now surfaces IsADirectory instead of a raw EBADF/EISDIR errno, and seq's broken-pipe short-circuit also catches preview2's raw EIO. rm and tsort gain small WASI-specific fallbacks (readability probing via read_dir, directory detection via stat) where the platform lacks the Unix APIs those checks normally use.
FileInformation previously fell back to a std::fs::Metadata-based heuristic (comparing file type and size) on WASI, since it lacked access to nix::sys::stat. Switch it to rustix::fs::Stat, the same backing type used on Unix, giving WASI real inode/device identity, nlink, and equality checks instead of an approximation. Also add WASI implementations of are_hardlinks_to_same_file and are_hardlinks_or_one_way_symlink_to_same_file via rustix::fs::stat/ lstat, since std::os::unix::fs::MetadataExt is unavailable there.
Several per-util operations relied on APIs unavailable or nightly-only on WASI: cp now treats ENOSYS like EOPNOTSUPP when skipping optional attribute preservation (WASI has no chmod/chown at all), reads timestamps via Metadata::accessed/modified instead of the filetime crate (which panics there), creates symlinks via rustix::fs::symlink, and only errors out of --reflink when explicitly requested rather than whenever it isn't Never. touch applies the same filetime-avoidance and uses rustix::fs::utimensat for symlink timestamps. date implements get_clock_resolution and set_system_datetime for WASI (the latter reporting "not supported", since the sandbox has no wall-clock-set syscall). sort's ordering check runs single-threaded on WASI, which has no thread support, and its external-merge path inserts a missing separator between concatenated files so lines don't merge across file boundaries.
60f692a to
9752428
Compare
Adds and retargets integration tests across most utilities to verify the WASI-specific behavior introduced in prior commits (error codes, symlink/hardlink handling, cp attribute preservation, sort ordering, touch timestamps, etc.), and tags tests that can't run under the WASI sandbox with #[cfg_attr(wasi_runner/wasip2_runner, ignore = "..")] (host paths, real threads, chmod/chown, and similar gaps). The uutests harness's symlink helpers now build relative targets under the WASI runner instead of absolute host paths, and gain a UUTESTS_WASM_RUNNER_ARGS env var. wasi.yml now runs the wasip2 integration suite (previously wasip1-only) with the wasip2_exit_with_code feature and wasmtime's cli-exit-with-code flag, and expands the tested utility list as WASI coverage grows. docs/src/wasi-test-gaps.md is expanded to catalog every ignore reason.
9752428 to
d311b90
Compare
|
I have put this one back to draft. It had too many files that were changed so I created the following spinoff PRs that need to be merged first:
|
Continuation of #12653. Aligns error handling and exit codes on wasm32-wasip1/wasm32-wasip2 with native Unix behavior, and enables the wasip2 integration test suite.