commit 1ccc87363a6436da293dbb1bc7bc8db2aa4d7bf7 (tree)
parent 50e185b71822c180fccd07826a8dd5e3ec641cc1
Author: Andrew Kelley <andrew@ziglang.org>
Date: Thu, 1 Jan 2026 18:39:22 -0800
std: fixes for WASI
Diffstat:
5 files changed, 26 insertions(+), 17 deletions(-)
diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig
@@ -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);
diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig
@@ -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);
diff --git a/lib/std/process/Args.zig b/lib/std/process/Args.zig
@@ -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;
diff --git a/lib/std/process/Environ.zig b/lib/std/process/Environ.zig
@@ -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"));
diff --git a/lib/std/start.zig b/lib/std/start.zig
@@ -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) {