From b2776d097d4407a8d76bea88e4289297eed65e3e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 15 Jan 2026 10:30:25 -0800 Subject: [PATCH] std.Io.Threaded: implement MemoryMap.setLength for Windows --- lib/std/Io/Threaded.zig | 43 +++++++++++++++++++++++++++-------------- lib/std/Io/test.zig | 5 +++-- lib/std/os/windows.zig | 2 ++ 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index bfa012c8c2f177773cf4bc2cb6bd8d077c924bac..c8b2f26d273405000abbe3cfa708f5a313c82f8e 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -16232,7 +16232,7 @@ fn createFileMap( protection: std.process.MemoryProtection, offset: u64, populate: bool, - aligned_len: usize, + len: usize, ) CreateFileMapError!File.MemoryMap { if (is_windows) { try Thread.checkCancel(); @@ -16251,7 +16251,7 @@ fn createFileMap( .STANDARD = .{ .RIGHTS = .REQUIRED }, }, null, - @constCast(&@as(i64, @intCast(aligned_len))), + @constCast(&@as(i64, @intCast(len))), .{ .READWRITE = true }, .{ .COMMIT = populate }, file.handle, @@ -16261,12 +16261,11 @@ fn createFileMap( .INVALID_FILE_FOR_SECTION => return error.OperationUnsupported, else => |status| return windows.unexpectedStatus(status), } - const current_process: windows.HANDLE = @ptrFromInt(@as(usize, @bitCast(@as(isize, -1)))); - var contents_ptr: ?[*]u8 = null; - var contents_len = aligned_len; + var contents_ptr: ?[*]align(std.heap.page_size_min) u8 = null; + var contents_len = len; switch (windows.ntdll.NtMapViewOfSection( section, - current_process, + windows.current_process, @ptrCast(&contents_ptr), null, 0, @@ -16284,7 +16283,7 @@ fn createFileMap( return .{ .file = file, .offset = offset, - .memory = @alignCast(contents_ptr.?[0..contents_len]), + .memory = contents_ptr.?[0..contents_len], .section = section, }; } else if (have_mmap) { @@ -16308,17 +16307,17 @@ fn createFileMap( const contents = while (true) { const syscall: Syscall = try .start(); const casted_offset = std.math.cast(i64, offset) orelse return error.Unseekable; - const rc = mmap_sym(null, aligned_len, prot, flags, file.handle, casted_offset); + const rc = mmap_sym(null, len, prot, flags, file.handle, casted_offset); syscall.finish(); const err: posix.E = if (builtin.link_libc) e: { if (rc != std.c.MAP_FAILED) { - break @as([*]align(page_align) u8, @ptrCast(@alignCast(rc)))[0..aligned_len]; + break @as([*]align(page_align) u8, @ptrCast(@alignCast(rc)))[0..len]; } break :e @enumFromInt(posix.system._errno().*); } else e: { const err = posix.errno(rc); if (err == .SUCCESS) { - break @as([*]align(page_align) u8, @ptrFromInt(rc))[0..aligned_len]; + break @as([*]align(page_align) u8, @ptrFromInt(rc))[0..len]; } break :e err; }; @@ -16356,8 +16355,7 @@ fn fileMemoryMapDestroy(userdata: ?*anyopaque, mm: *File.MemoryMap) void { const memory = mm.memory; if (mm.section) |section| switch (native_os) { .windows => { - const current_process: windows.HANDLE = @ptrFromInt(@as(usize, @bitCast(@as(isize, -1)))); - _ = windows.ntdll.NtUnmapViewOfSection(current_process, memory.ptr); + _ = windows.ntdll.NtUnmapViewOfSection(windows.current_process, memory.ptr); windows.CloseHandle(section); }, .wasi => unreachable, @@ -16394,8 +16392,25 @@ fn fileMemoryMapSetLength( } switch (native_os) { .windows => { - _ = section; - @panic("TODO"); + var contents_ptr: ?[*]align(page_align) u8 = null; + var contents_len = new_len; + switch (windows.ntdll.NtMapViewOfSection( + section, + windows.current_process, + @ptrCast(&contents_ptr), + null, + 0, + null, + &contents_len, + .Unmap, + .{}, + .{ .READWRITE = true }, + )) { + .SUCCESS => {}, + .SECTION_PROTECTION => return error.PermissionDenied, + else => |status| return windows.unexpectedStatus(status), + } + mm.memory = contents_ptr.?[0..contents_len]; }, .wasi => unreachable, .linux => { diff --git a/lib/std/Io/test.zig b/lib/std/Io/test.zig index 00a2d872418167d53c5d09d3ce2d8072d21026fa..0f4285b9bd92183cb9efa265e22ac2aec4042baa 100644 --- a/lib/std/Io/test.zig +++ b/lib/std/Io/test.zig @@ -640,9 +640,10 @@ test "memory mapping" { try expectEqualStrings("this9is9my", mm.memory); - try mm.setLength(io, .{ .len = "this9is9my data123".len }); + // Cross a page boundary to require an actual remap. + try mm.setLength(io, .{ .len = std.heap.pageSize() * 2 }); try mm.read(io); - try expectEqualStrings("this9is9my data123", mm.memory); + try expectEqualStrings("this9is9my data123\x00\x00", mm.memory[0.."this9is9my data123\x00\x00".len]); } } diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 1e864d14c277f4d09954f388559bf4255a4bd821..91f3cb6513fd6969b98dd0cc67b2e922268bde42 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -28,6 +28,8 @@ pub const ws2_32 = @import("windows/ws2_32.zig"); pub const crypt32 = @import("windows/crypt32.zig"); pub const nls = @import("windows/nls.zig"); +pub const current_process: HANDLE = @ptrFromInt(@as(usize, @bitCast(@as(isize, -1)))); + pub const FILE = struct { // ref: km/ntddk.h -- 2.54.0