std: fixes for WASI

This commit is contained in:
Andrew Kelley 2026-01-01 18:39:22 -08:00
parent 50e185b718
commit 1ccc87363a
5 changed files with 26 additions and 17 deletions

View file

@ -12787,7 +12787,7 @@ const processSpawn = switch (native_os) {
fn processSpawnUnsupported(userdata: ?*anyopaque, options: process.SpawnOptions) process.SpawnError!process.Child {
_ = userdata;
_ = options;
return error.OperationUnsupported;
return error.Unexpected;
}
fn processSpawnPosix(userdata: ?*anyopaque, options: process.SpawnOptions) process.SpawnError!process.Child {
@ -12995,6 +12995,7 @@ fn processSpawnPosix(userdata: ?*anyopaque, options: process.SpawnOptions) proce
}
fn childWait(userdata: ?*anyopaque, child: *std.process.Child) process.Child.WaitError!process.Child.Term {
if (native_os == .wasi) unreachable;
const t: *Threaded = @ptrCast(@alignCast(userdata));
switch (native_os) {
.windows => return childWaitWindows(t, child),
@ -13003,6 +13004,7 @@ fn childWait(userdata: ?*anyopaque, child: *std.process.Child) process.Child.Wai
}
fn childKill(userdata: ?*anyopaque, child: *std.process.Child) void {
if (native_os == .wasi) unreachable;
const t: *Threaded = @ptrCast(@alignCast(userdata));
if (is_windows) {
childKillWindows(t, child, 1) catch childCleanupWindows(child);

View file

@ -22,10 +22,10 @@ const tmpDir = std.testing.tmpDir;
test "check WASI CWD" {
if (native_os == .wasi) {
if (std.options.wasiCwd() != 3) {
const cwd: Dir = .cwd();
if (cwd.handle != 3) {
@panic("WASI code that uses cwd (like this test) needs a preopen for cwd (add '--dir=.' to wasmtime)");
}
if (!builtin.link_libc) {
// WASI without-libc hardcodes fd 3 as the FDCWD token so it can be passed directly to WASI calls
try expectEqual(3, posix.AT.FDCWD);

View file

@ -10,8 +10,14 @@ const testing = std.testing;
vector: Vector,
/// On WASI without libc, this is `void` because the environment has to be
/// queried and heap-allocated at runtime.
pub const Vector = switch (native_os) {
.windows => []const u16, // WTF-16 encoded
.wasi => switch (builtin.link_libc) {
false => void,
true => []const [*:0]const u8,
},
.freestanding, .other => void,
else => []const [*:0]const u8,
};
@ -457,6 +463,8 @@ pub fn iterateAllocator(a: Args, gpa: Allocator) Iterator.InitError!Iterator {
return .initAllocator(a, gpa);
}
pub const ToSliceError = Iterator.Windows.InitError || Iterator.Wasi.InitError;
/// Returned value may reference several allocations; call `freeSlice` to
/// release.
///
@ -464,19 +472,19 @@ pub fn iterateAllocator(a: Args, gpa: Allocator) Iterator.InitError!Iterator {
/// [WTF-8](https://wtf-8.codeberg.page/).
/// * On other platforms, the result is an opaque sequence of bytes with no
/// particular encoding.
pub fn toSlice(a: Args, gpa: Allocator) Allocator.Error![][:0]u8 {
pub fn toSlice(a: Args, gpa: Allocator) ToSliceError![][:0]u8 {
var it = try a.iterateAllocator(gpa);
defer it.deinit();
var contents = std.array_list.Managed(u8).init(gpa);
defer contents.deinit();
var contents: std.ArrayList(u8) = .empty;
defer contents.deinit(gpa);
var slice_list = std.array_list.Managed(usize).init(gpa);
defer slice_list.deinit();
var slice_list: std.ArrayList(usize) = .empty;
defer slice_list.deinit(gpa);
while (it.next()) |arg| {
try contents.appendSlice(arg[0 .. arg.len + 1]);
try slice_list.append(arg.len);
try contents.appendSlice(gpa, arg[0 .. arg.len + 1]);
try slice_list.append(gpa, arg.len);
}
const contents_slice = contents.items;

View file

@ -757,6 +757,9 @@ test Map {
}
test "convert from Environ to Map and back again" {
if (native_os == .windows) return;
if (native_os == .wasi and !builtin.link_libc) return;
const gpa = testing.allocator;
var map: Map = .init(gpa);
@ -769,11 +772,7 @@ test "convert from Environ to Map and back again" {
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
const environ: Environ = switch (native_os) {
.windows => return error.SkipZigTest,
.wasi => if (!builtin.libc) return error.SkipZigTest,
else => .{ .block = try map.createBlockPosix(arena, .{}) },
};
const environ: Environ = .{ .block = try map.createBlockPosix(arena, .{}) };
try testing.expectEqual(true, environ.contains(gpa, "FOO"));
try testing.expectEqual(false, environ.contains(gpa, "BAR"));

View file

@ -55,7 +55,7 @@ comptime {
if (!@hasDecl(root, wasm_start_sym) and @hasDecl(root, "main")) {
// Only call main when defined. For WebAssembly it's allowed to pass `-fno-entry` in which
// case it's not required to provide an entrypoint such as main.
@export(&wasi_start, .{ .name = wasm_start_sym });
@export(&startWasi, .{ .name = wasm_start_sym });
}
} else if (native_arch.isWasm() and native_os == .freestanding) {
// Only call main when defined. For WebAssembly it's allowed to pass `-fno-entry` in which
@ -90,7 +90,7 @@ fn wasm_freestanding_start() callconv(.c) void {
_ = @call(.always_inline, callMain, .{ {}, {} });
}
fn wasi_start() callconv(.c) void {
fn startWasi() callconv(.c) void {
// The function call is marked inline because for some reason LLVM in
// release mode fails to inline it, and we want fewer call frames in stack traces.
switch (builtin.wasi_exec_model) {