Skip to content

wasip2: build uucore and env standalone, don't trap on empty argv - #14562

Open
Aditya1404Sal wants to merge 15 commits into
uutils:mainfrom
Aditya1404Sal:wasip2-fixes
Open

Aditya1404Sal wants to merge 15 commits into
uutils:mainfrom
Aditya1404Sal:wasip2-fixes

Conversation

@Aditya1404Sal

@Aditya1404Sal Aditya1404Sal commented Sep 14, 2026 •

Copy link
Copy Markdown

Fixes #14561.

Use stable byte conversions for env on WASI Preview 2 and restore it to feat_common_core. Handle empty WASI argv in embedded use without panicking, with regression tests and a Preview 2 CI step.

Upstream commit 17f1a5d already enables rustix/std through uucore's fs feature, so this PR no longer needs a dependency change.

Verified native uucore/env tests, Preview 2 conversion and argv tests, feat_wasm checks for both WASI targets, and a standalone Preview 2 uucore --features fs check.

@Aditya1404Sal
Aditya1404Sal marked this pull request as ready for review September 14, 2026 19:20
Copilot AI lite review requested due to automatic review settings September 14, 2026 19:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Add WASI Preview 2 coverage and regression tests for the new conversion and empty-argv paths.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Enables standalone wasm32-wasip2 builds for uucore and env, while preventing empty-WASI-argv traps.

Changes:

  • Enables rustix/std for uucore.
  • Adds WASI Preview 2 encoded-byte conversions for env.
  • Restores env to common/WASI features and adds an empty-argv fallback.
File summaries
File Description
src/uucore/src/lib/lib.rs Prevents empty-argv indexing on WASI.
src/uucore/Cargo.toml Enables required rustix standard-library APIs.
src/uu/env/src/native_int_str.rs Adds WASI Preview 2 string conversions.
Cargo.toml Includes env in common/WASI features.
Review details

Suppressed comments (1)

Cargo.toml:140

  • This move does not provide the wasip2 CI coverage claimed in the PR description: .github/workflows/wasi.yml gates the feat_wasm build to wasip1 and excludes env from the wasip2 package-test list. Add a wasip2 compile/test step or correct the description before relying on this feature move for regression protection.
  "env",
  • Files reviewed: 4/4 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/uu/env/src/native_int_str.rs
Comment thread src/uucore/src/lib/lib.rs Outdated
@sylvestre

Copy link
Copy Markdown
Contributor

please address what copilot said

Run env encoded-byte conversion tests under wasm32-wasip2, and factor the WASI argv fallback so its empty-input behavior is covered on host and target tests.
Copilot AI review requested due to automatic review settings September 19, 2026 19:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

Review effort: Lite
Findings: 1 High severity · 2 Medium severity

Open (3)

Comment thread Cargo.toml
"dircolors",
"dirname",
"echo",
"env",
Copilot AI review requested due to automatic review settings September 19, 2026 20:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

Review effort: Lite
Findings: 1 High severity · 2 Medium severity

Open (3)

@sylvestre

Copy link
Copy Markdown
Contributor

i am sorry but nobody will read such a long comment 0
Please make it shorter

Comment thread src/uu/env/src/native_int_str.rs Outdated
Comment on lines +26 to +30
// On wasm32-wasip2 `std::os::wasi::ffi` is behind the unstable `wasip2` library feature, so the
// byte views come from the stable encoded-bytes API instead. The component model defines every
// string the host hands a guest as UTF-8, so on this target the encoded bytes *are* the bytes, and
// the reverse direction can go through `str` without `unsafe` — the same approach as
// `uucore::os_str_from_bytes` / `os_string_from_vec` on this target.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please make this comment shorter

Comment thread src/uucore/src/lib/lib.rs Outdated
argv
}

// `std::env::args_os()` can be empty on wasi when the component is not invoked as a CLI

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please make this comment shorter

@github-actions

github-actions Bot commented Sep 20, 2026 •

Copy link
Copy Markdown

GNU testsuite comparison:

Skip an intermittent issue tests/date/resolution (fails in this run but passes in the 'main' branch)

Copilot AI review requested due to automatic review settings September 20, 2026 11:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

Review effort: Lite
Findings: 2 High severity · 2 Medium severity

Open (4)

Comment thread Cargo.toml
"dircolors",
"dirname",
"echo",
"env",
Copilot AI review requested due to automatic review settings September 21, 2026 07:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The new Preview 2 CI step does not exercise the standalone uucore --features fs build that motivated the fix.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 2 High severity · 1 Medium severity

Open (3)
Resolved since last review (2)

Comment thread .github/workflows/wasi.yml Outdated
Copilot AI review requested due to automatic review settings September 21, 2026 07:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The changes are scoped, tested, and align with the stated WASI Preview 2 build and runtime fixes.

Review effort: Lite
Findings: 2 High severity

Open (2)
Resolved since last review (1)

Comment thread .github/workflows/wasi.yml Outdated
run: |
cargo test --target wasm32-wasip2 --no-default-features -p uu_env
cargo check --target wasm32-wasip2 --no-default-features -p uucore --features fs
cargo test --target wasm32-wasip2 --no-default-features -p uucore --lib \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a dedicated CI step to run one test on a 4 lines helper seems a lot, the cargo check lines are the useful part here, no?

Comment thread src/uu/env/src/native_int_str.rs Outdated
match String::from_utf8(vec) {
Ok(s) => s.into(),
// Cannot have come from the host; keep going rather than abort the component.
Err(e) => String::from_utf8_lossy(e.as_bytes()).into_owned().into(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this silently replaces bytes with U+FFFD, so env would hand a corrupted value to the child. i'd rather keep the bytes than mangle them. also the comment doesn't really explain the why.

Comment thread src/uucore/src/lib/lib.rs Outdated
#[cfg(any(test, target_os = "wasi"))]
fn with_wasi_argv_fallback(mut argv: Vec<OsString>) -> Vec<OsString> {
if argv.is_empty() {
argv.push(OsString::from("uu"));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why "uu"? it shows up in error messages and --version, "coreutils" would be less cryptic.

Copilot AI review requested due to automatic review settings September 23, 2026 12:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Add the requested SAFETY comments before both unchecked conversions.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 2 High severity · 1 Low severity

Open (3)

Comment thread src/uu/env/src/native_int_str.rs
@codspeed

codspeed Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Merging this PR will regress 1 benchmark

⚠️ 122 benchmarks spent significant time in system calls

System calls cannot be consistently instrumented, so they are not included in the measure, which understates the real cost. Please switch to the Walltime instrument to accurately measure system calls.

Measurement and system calls

ℹ️ 1 benchmark has no flame graph

The flamegraph could not be generated because too much time was spent in runtime internals, making the visualization not useful for performance analysis.

⚡ 1 improved benchmark
❌ 1 regressed benchmark
✅ 399 untouched benchmarks
⏩ 70 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
❌ Simulation factor_five_38_bit_primes 1.8 s 2.1 s -14.88%
⚡ Simulation factor_three_39_bit_primes 942.2 ms 529.5 ms +77.97%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing Aditya1404Sal:wasip2-fixes (b234415) with main (774cca5)2

Open in CodSpeed

Footnotes

  1. 70 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

  2. No successful run was found on main (fb68e6c) during the generation of this report, so 774cca5 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

Copilot AI review requested due to automatic review settings September 23, 2026 14:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Add the requested WASI-target regression test for the public argv path.

Review effort: Lite
Findings: 2 High severity

Open (2)
Resolved since last review (1)

@eduardomourar eduardomourar left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just very small suggestions.

Comment thread src/uucore/src/lib/lib.rs Outdated
Comment on lines +401 to +406
static UTIL_NAME: LazyLock<String> = LazyLock::new(|| {
let base_index = usize::from(get_utility_is_second_arg());
// `ARGV` may be shorter than the multicall layout assumes (e.g. the WASI fallback).
let last = ARGV.len().saturating_sub(1);
let base_index = usize::from(get_utility_is_second_arg()).min(last);
let is_man = usize::from(ARGV[base_index].eq("manpage"));
let argv_index = base_index + is_man;
let argv_index = (base_index + is_man).min(last);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previous fixes to this indexing (e.g. 6699eaad6) corrected the arithmetic to be exactly right rather than clamping around it. The .min(last) here means that if get_utility_is_second_arg() is true but ARGV only has one element (the WASI empty-argv fallback), base_index silently falls back to 0 instead of the intended 1 — i.e. a wrong-but-plausible value instead of a panic.

In the current call graph this looks unreachable: coreutils.rs's multicall path only sets get_utility_is_second_arg() after consuming an argv entry, so by the time it's true, ARGV already has ≥2 elements and the clamp is a no-op. But that's an invariant of the caller, not something enforced where the clamp lives — if that assumption ever changes, this would silently produce a misleading utility name instead of failing loudly. Would a comment noting why the clamp is always a no-op in practice (or asserting it) be worth adding here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went one step further and removed the clamp instead of documenting it, since it was dead code. UTIL_NAME is only read inside a utility's uumain, which the multicall path reaches only after consuming argv[1]; with the flag set and no second argument it exits with "missing argument" without reading the name. The indexing is back to upstream's exact arithmetic.

Comment thread src/uucore/src/lib/lib.rs
Comment on lines 381 to +399
// args_os() can be expensive to call, it copies all of argv before iterating.
// So if we want only the first arg or so it's overkill. We cache it.
#[cfg(windows)]
static ARGV: LazyLock<Vec<OsString>> = LazyLock::new(|| wild::args_os().collect());
#[cfg(not(windows))]
#[cfg(all(not(windows), not(target_os = "wasi")))]
static ARGV: LazyLock<Vec<OsString>> = LazyLock::new(|| std::env::args_os().collect());

#[cfg(any(test, target_os = "wasi"))]
fn with_wasi_argv_fallback(mut argv: Vec<OsString>) -> Vec<OsString> {
if argv.is_empty() {
argv.push(OsString::from("coreutils"));
}
argv
}

// WASI embeddings may omit argv; provide a stable utility-name fallback.
#[cfg(all(not(windows), target_os = "wasi"))]
static ARGV: LazyLock<Vec<OsString>> =
LazyLock::new(|| with_wasi_argv_fallback(std::env::args_os().collect()));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with_wasi_argv_fallback guarantees ARGV is never empty on target_os = "wasi", which is what makes the existing unguarded ARGV[0] access in EXECUTION_PHRASE (L423-L433) safe on WASI too — a nice side benefit. But that "ARGV is always non-empty" guarantee isn't stated anywhere near the ARGV static itself, so a future change to with_wasi_argv_fallback (or a new platform cfg arm) could reintroduce the panic in EXECUTION_PHRASE or UTIL_NAME without anything pointing back at this invariant. A one-line comment on the ARGV static ("always non-empty — relied on by UTIL_NAME/EXECUTION_PHRASE") would make that dependency explicit for the next person touching this code.

Copilot AI lite review requested due to automatic review settings October 9, 2026 22:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/uucore/src/lib/lib.rs
Comment thread src/uu/env/src/native_int_str.rs
Comment thread src/uu/env/src/native_int_str.rs
Comment thread src/uucore/src/lib/lib.rs
Comment thread src/uucore/src/lib/lib.rs Outdated
}

// Always non-empty on WASI (embeddings may omit argv); `UTIL_NAME`/`EXECUTION_PHRASE` rely on it.
#[cfg(all(not(windows), target_os = "wasi"))]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not(windows) is redundant here, target_os = "wasi" is enough
can be done in a different PR

Copilot AI lite review requested due to automatic review settings October 12, 2026 21:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


// `std::os::wasi::ffi` is still unstable on WASI Preview 2, so provide the same traits here.
// On WASI an `OsStr` is a plain byte string, so these conversions keep every byte.
#[cfg(all(target_os = "wasi", not(target_env = "p1")))]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uucore's os_str_from_bytes/os_string_from_vec still reject non-UTF-8 on p2, so env and uucore now disagree.
could this shim live in uucore so both use it? can be done in a different PR

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thats a fair point, I can migrate that in a follow-up PR very soon (today?)

This branch has not been deployed

No deployments
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.

uucore and env do not build for wasm32-wasip2 when used as a library / standalone

4 participants