Skip to content

uucore: fix OsStr byte conversions on wasip2 and wasip3 - #13755

Open
GamePad64 wants to merge 2 commits into
uutils:mainfrom
GamePad64:uucore-wasi-non-p1-osstr
Open

uucore: fix OsStr byte conversions on wasip2 and wasip3#13755
GamePad64 wants to merge 2 commits into
uutils:mainfrom
GamePad64:uucore-wasi-non-p1-osstr

Conversation

@GamePad64

Copy link
Copy Markdown

target_os = "wasi" is true for p1, p2 and p3, but std::os::wasi is unstable on p2 and not compiled at all on p3. The helpers gating on target_env = "p1" therefore misbehaved on the other two:

  • os_str_from_bytes, os_string_from_vec and os_string_to_vec took the UTF-8-validating path and rejected byte strings that are valid on WASI, even though os_str_as_bytes already returned raw bytes there.
  • path_ends_with_terminator gated its as_encoded_bytes branch to exactly p2, so on p3 it used as_bytes with no OsStrExt in scope and did not compile.

Use the OsStr::as_encoded_bytes family instead: stable since 1.74 and uniform across p1/p2/p3. On WASI OsStr is byte-based, so from_encoded_bytes_unchecked is sound. unix and Windows are unchanged.

Verified with a non-UTF-8 round-trip built for wasm32-wasip2 and run under wasmtime: rejected before, preserved after. wasip3 is not compile-tested, as std does not yet build for that target.

`target_os = "wasi"` is true for p1, p2 and p3, but `std::os::wasi` is
unstable on p2 and not compiled at all on p3. The helpers gating on
`target_env = "p1"` therefore misbehaved on the other two:

- `os_str_from_bytes`, `os_string_from_vec` and `os_string_to_vec` took
  the UTF-8-validating path and rejected byte strings that are valid on
  WASI, even though `os_str_as_bytes` already returned raw bytes there.
- `path_ends_with_terminator` gated its `as_encoded_bytes` branch to
  exactly p2, so on p3 it used `as_bytes` with no `OsStrExt` in scope
  and did not compile.

Use the `OsStr::as_encoded_bytes` family instead: stable since 1.74 and
uniform across p1/p2/p3. On WASI `OsStr` is byte-based, so
`from_encoded_bytes_unchecked` is sound. unix and Windows are unchanged.

Verified with a non-UTF-8 round-trip built for wasm32-wasip2 and run
under wasmtime: rejected before, preserved after. wasip3 is not
compile-tested, as std does not yet build for that target.
Assert that `os_string_from_vec`/`os_string_to_vec` and
`os_str_from_bytes`/`os_str_as_bytes` round-trip non-UTF-8 bytes on
byte-oriented platforms, which is unix and every WASI environment.

Built for wasm32-wasip2 and run under wasmtime, they fail before the
preceding commit and pass after it:

    before: Unable to transform bytes into OsStr
    after:  2 passed

On unix they pass either way and guard against a future regression.
@codspeed-hq

codspeed-hq Bot commented Aug 5, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 18.29%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

❌ 1 regressed benchmark
✅ 346 untouched benchmarks
⏩ 46 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation df_with_path 571.4 µs 699.4 µs -18.29%

Tip

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


Comparing GamePad64:uucore-wasi-non-p1-osstr (d8e25d8) with main (21d4e96)

Open in CodSpeed

Footnotes

  1. 46 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.

Comment thread src/uucore/src/lib/lib.rs
#[cfg(target_os = "wasi")]
// SAFETY: on WASI `OsString` is a plain byte string with no encoding
// invariant, so every byte sequence is a valid `OsString`.
return Ok(unsafe { OsString::from_encoded_bytes_unchecked(vec) });

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.

can we avoid the unsafe ?

Comment thread src/uucore/src/lib/lib.rs
return Ok(Cow::Borrowed(
// SAFETY: on WASI `OsStr` is a plain byte string with no encoding
// invariant, so every byte sequence is a valid `OsStr`.
unsafe { OsStr::from_encoded_bytes_unchecked(bytes) },

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.

same for the unsafe

@sylvestre

Copy link
Copy Markdown
Contributor

please add tests showing that the issue is fixed

@GamePad64
GamePad64 force-pushed the uucore-wasi-non-p1-osstr branch from aec25de to d8e25d8 Compare August 5, 2026 10:25
@xtqqczze

xtqqczze commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Once the wasip2/wasip3 features are stabilised, we can use OsStr::from_bytes on WASI. For now, I think it is reasonable to keep the unsafe block and add a TODO to address this later.

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.

3 participants