From dda065dbb73ddd326102cb78001f6be93c3f006c Mon Sep 17 00:00:00 2001 From: Noah Baertsch Date: Mon, 29 Dec 2025 17:18:54 -0500 Subject: [PATCH 1/4] fix: Update API calls for Zig 0.15.2 compatibility - ArrayHashMap.put() now requires allocator as first parameter - ArrayList.append() now requires allocator as first parameter These changes are required for Zig 0.15.2 which changed the API for managed data structures to take the allocator explicitly. --- src/instance.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/instance.zig b/src/instance.zig index d252a5a3..eb2bb729 100644 --- a/src/instance.zig +++ b/src/instance.zig @@ -455,7 +455,7 @@ pub const Instance = struct { } pub fn addWasiPreopen(self: *Instance, wasi_fd: wasi.fd_t, name: []const u8, host_fd: posix.fd_t) !void { - return self.wasi_preopens.put(wasi_fd, .{ + return self.wasi_preopens.put(self.alloc, wasi_fd, .{ .wasi_fd = wasi_fd, .name = name, .host_fd = host_fd, @@ -475,7 +475,7 @@ pub const Instance = struct { const args = try std.process.argsAlloc(alloc); for (args) |arg| { - try self.wasi_args.append(arg); + try self.wasi_args.append(alloc, arg); } return args; From 654054a10410fd84eeae2dbcf0b303bbb58586bf Mon Sep 17 00:00:00 2001 From: Noah Baertsch Date: Mon, 29 Dec 2025 19:34:30 -0500 Subject: [PATCH 2/4] bump .minimum_zig_version --- build.zig.zon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.zig.zon b/build.zig.zon index 6ce79c19..248ba622 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -2,7 +2,7 @@ .name = .zware, .version = "0.0.1", .fingerprint = 0xea6cb8e2e9e30e64, - .minimum_zig_version = "0.15.1", + .minimum_zig_version = "0.15.2", .dependencies = .{ .wabt = .{ .url = "https://github.com/WebAssembly/wabt/archive/39f85a791cbbad91a253a851841a29777efdc2cd.tar.gz", From e55c9c257f3083116c09c02e7537efff374e02b3 Mon Sep 17 00:00:00 2001 From: Noah Baertsch Date: Mon, 29 Dec 2025 20:14:05 -0500 Subject: [PATCH 3/4] addWasiPreopen unit tests --- src/instance.zig | 157 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/src/instance.zig b/src/instance.zig index eb2bb729..b8e7390e 100644 --- a/src/instance.zig +++ b/src/instance.zig @@ -488,4 +488,161 @@ pub const WasiPreopen = struct { host_fd: std.posix.fd_t, }; +test "addWasiPreopen registers preopens correctly" { + const testing = std.testing; + const ArenaAllocator = std.heap.ArenaAllocator; + var arena = ArenaAllocator.init(testing.allocator); + defer arena.deinit(); + + const alloc = arena.allocator(); + + var store = Store.init(alloc); + + // Create a minimal module (empty wasm with just the header) + const empty_wasm = &[_]u8{ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00 }; + var module = Module.init(alloc, empty_wasm); + try module.decode(); + + var instance = Instance.init(alloc, &store, module); + + // Add a preopen entry + const test_wasi_fd: wasi.fd_t = 3; + const test_name = "/tmp/test"; + const test_host_fd: posix.fd_t = 42; + + try instance.addWasiPreopen(test_wasi_fd, test_name, test_host_fd); + + // Verify the entry was added + const preopen = instance.wasi_preopens.get(test_wasi_fd); + try testing.expect(preopen != null); + try testing.expectEqual(test_wasi_fd, preopen.?.wasi_fd); + try testing.expectEqualStrings(test_name, preopen.?.name); + try testing.expectEqual(test_host_fd, preopen.?.host_fd); + + // Add another preopen and verify both exist + const test_wasi_fd2: wasi.fd_t = 4; + const test_name2 = "/home/user"; + const test_host_fd2: posix.fd_t = 99; + + try instance.addWasiPreopen(test_wasi_fd2, test_name2, test_host_fd2); + + // Verify both entries exist + try testing.expect(instance.wasi_preopens.get(test_wasi_fd) != null); + try testing.expect(instance.wasi_preopens.get(test_wasi_fd2) != null); + try testing.expectEqualStrings(test_name2, instance.wasi_preopens.get(test_wasi_fd2).?.name); +} + +test "addWasiPreopen overwrites existing fd" { + const testing = std.testing; + const ArenaAllocator = std.heap.ArenaAllocator; + var arena = ArenaAllocator.init(testing.allocator); + defer arena.deinit(); + + const alloc = arena.allocator(); + + var store = Store.init(alloc); + + const empty_wasm = &[_]u8{ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00 }; + var module = Module.init(alloc, empty_wasm); + try module.decode(); + + var instance = Instance.init(alloc, &store, module); + + // Add initial preopen + const test_fd: wasi.fd_t = 3; + try instance.addWasiPreopen(test_fd, "/original", 10); + + // Overwrite with same fd but different values + try instance.addWasiPreopen(test_fd, "/updated", 20); + + // Verify the entry was overwritten + const preopen = instance.wasi_preopens.get(test_fd); + try testing.expect(preopen != null); + try testing.expectEqualStrings("/updated", preopen.?.name); + try testing.expectEqual(@as(posix.fd_t, 20), preopen.?.host_fd); + + // Verify only one entry exists for this fd + try testing.expectEqual(@as(usize, 1), instance.wasi_preopens.count()); +} + +test "addWasiPreopen edge cases" { + const testing = std.testing; + const ArenaAllocator = std.heap.ArenaAllocator; + var arena = ArenaAllocator.init(testing.allocator); + defer arena.deinit(); + + const alloc = arena.allocator(); + + var store = Store.init(alloc); + + const empty_wasm = &[_]u8{ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00 }; + var module = Module.init(alloc, empty_wasm); + try module.decode(); + + var instance = Instance.init(alloc, &store, module); + + // Test fd=0 (edge case - typically stdin) + try instance.addWasiPreopen(0, "/fd0", 100); + try testing.expect(instance.wasi_preopens.get(0) != null); + try testing.expectEqualStrings("/fd0", instance.wasi_preopens.get(0).?.name); + + // Test empty name string + try instance.addWasiPreopen(1, "", 101); + try testing.expect(instance.wasi_preopens.get(1) != null); + try testing.expectEqualStrings("", instance.wasi_preopens.get(1).?.name); + + // Test name with special characters + try instance.addWasiPreopen(2, "/path/with spaces/and-dashes", 102); + try testing.expect(instance.wasi_preopens.get(2) != null); + try testing.expectEqualStrings("/path/with spaces/and-dashes", instance.wasi_preopens.get(2).?.name); +} + +test "addWasiPreopen integrates with VirtualMachine lookup" { + const testing = std.testing; + const ArenaAllocator = std.heap.ArenaAllocator; + var arena = ArenaAllocator.init(testing.allocator); + defer arena.deinit(); + + const alloc = arena.allocator(); + + var store = Store.init(alloc); + + const empty_wasm = &[_]u8{ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00 }; + var module = Module.init(alloc, empty_wasm); + try module.decode(); + + var instance = Instance.init(alloc, &store, module); + + // Add preopens + try instance.addWasiPreopen(3, "/tmp", 50); + try instance.addWasiPreopen(4, "/home", 60); + + // Create a VirtualMachine and test lookup functions + var op_stack: [1024]u64 = undefined; + var frame_stack: [1024]VirtualMachine.Frame = undefined; + var label_stack: [1024]VirtualMachine.Label = undefined; + + var vm = VirtualMachine.init(op_stack[0..], frame_stack[0..], label_stack[0..], &instance); + + // Test lookupWasiPreopen + const preopen3 = vm.lookupWasiPreopen(3); + try testing.expect(preopen3 != null); + try testing.expectEqualStrings("/tmp", preopen3.?.name); + try testing.expectEqual(@as(posix.fd_t, 50), preopen3.?.host_fd); + + const preopen4 = vm.lookupWasiPreopen(4); + try testing.expect(preopen4 != null); + try testing.expectEqualStrings("/home", preopen4.?.name); + + // Test lookup of non-existent fd returns null + try testing.expect(vm.lookupWasiPreopen(99) == null); + + // Test getHostFd returns mapped fd + try testing.expectEqual(@as(posix.fd_t, 50), vm.getHostFd(3)); + try testing.expectEqual(@as(posix.fd_t, 60), vm.getHostFd(4)); + + // Test getHostFd returns input fd when not in preopens (passthrough) + try testing.expectEqual(@as(posix.fd_t, 99), vm.getHostFd(99)); +} + const _ = std.testing.refAllDecls(); From 60633a835501ce5dd609d6d34ace64cd2f927e55 Mon Sep 17 00:00:00 2001 From: Noah Baertsch Date: Mon, 29 Dec 2025 20:43:46 -0500 Subject: [PATCH 4/4] skip addWasiPreopen tests on Windows target --- src/instance.zig | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/instance.zig b/src/instance.zig index b8e7390e..b051d816 100644 --- a/src/instance.zig +++ b/src/instance.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); const mem = std.mem; const math = std.math; const posix = std.posix; @@ -489,6 +490,10 @@ pub const WasiPreopen = struct { }; test "addWasiPreopen registers preopens correctly" { + // Skip on Windows: posix.fd_t is *anyopaque (HANDLE), not an integer + // TODO: Windows file descriptor implementation + if (builtin.os.tag == .windows) return error.SkipZigTest; + const testing = std.testing; const ArenaAllocator = std.heap.ArenaAllocator; var arena = ArenaAllocator.init(testing.allocator); @@ -533,6 +538,10 @@ test "addWasiPreopen registers preopens correctly" { } test "addWasiPreopen overwrites existing fd" { + // Skip on Windows: posix.fd_t is *anyopaque (HANDLE), not an integer + // TODO: Windows file descriptor implementation + if (builtin.os.tag == .windows) return error.SkipZigTest; + const testing = std.testing; const ArenaAllocator = std.heap.ArenaAllocator; var arena = ArenaAllocator.init(testing.allocator); @@ -566,6 +575,10 @@ test "addWasiPreopen overwrites existing fd" { } test "addWasiPreopen edge cases" { + // Skip on Windows: posix.fd_t is *anyopaque (HANDLE), not an integer + // TODO: Windows file descriptor implementation + if (builtin.os.tag == .windows) return error.SkipZigTest; + const testing = std.testing; const ArenaAllocator = std.heap.ArenaAllocator; var arena = ArenaAllocator.init(testing.allocator); @@ -598,6 +611,10 @@ test "addWasiPreopen edge cases" { } test "addWasiPreopen integrates with VirtualMachine lookup" { + // Skip on Windows: posix.fd_t is *anyopaque (HANDLE), not an integer + // TODO: Windows file descriptor implementation + if (builtin.os.tag == .windows) return error.SkipZigTest; + const testing = std.testing; const ArenaAllocator = std.heap.ArenaAllocator; var arena = ArenaAllocator.init(testing.allocator);