commit a70e0061579a4365da0092554470ffeadb4594a4 (tree)
parent 5a7dc4b0fae62c8b7ec798043c93e4d90704a638
Author: Andrew Kelley <andrew@ziglang.org>
Date: Wed, 14 Jan 2026 15:11:37 -0800
std: add unit test for memory mapping
Diffstat:
4 files changed, 55 insertions(+), 2 deletions(-)
diff --git a/lib/std/Io/File.zig b/lib/std/Io/File.zig
@@ -784,6 +784,10 @@ pub fn hardLink(
return io.vtable.fileHardLink(io.userdata, file, new_dir, new_sub_path, options);
}
+pub fn createMemoryMap(file: File, io: Io, options: MemoryMap.CreateOptions) MemoryMap.CreateError!MemoryMap {
+ return .create(io, file, options);
+}
+
test {
_ = Reader;
_ = Writer;
diff --git a/lib/std/Io/File/MemoryMap.zig b/lib/std/Io/File/MemoryMap.zig
@@ -36,7 +36,14 @@ pub const CreateError = error{
} || Allocator.Error || File.ReadPositionalError;
pub const CreateOptions = struct {
+ /// When this has read set to false, bytes that are not modified before a
+ /// sync may have the original file contents, or may be set to zero.
protection: std.process.MemoryProtection = .{ .read = true, .write = true },
+ /// If set to `true`, allows bytes observed before calling `read` to be
+ /// undefined, and bytes unwritten before calling `write` to write
+ /// undefined memory to the file.
+ undefined_contents: bool = false,
+ /// Prefault the pages.
populate: bool = true,
/// Byte index of file to start from.
offset: u64 = 0,
@@ -46,6 +53,8 @@ pub const CreateOptions = struct {
len: ?usize = null,
};
+/// To release the resources associated with the returned `MemoryMap`, call
+/// `destroy`.
pub fn create(io: Io, file: File, options: CreateOptions) CreateError!MemoryMap {
return io.vtable.fileMemoryMapCreate(io.userdata, file, options);
}
diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig
@@ -16150,8 +16150,7 @@ fn fileMemoryMapCreate(
};
errdefer gpa.rawFree(memory, alignment, @returnAddress());
- // If the mapping does not have read permissions, no need to populate the contents.
- if (options.protection.read) try mmSyncRead(file, memory, offset);
+ if (!options.undefined_contents) try mmSyncRead(file, memory, offset);
return .{
.file = file,
diff --git a/lib/std/Io/test.zig b/lib/std/Io/test.zig
@@ -592,3 +592,44 @@ test "randomSecure" {
// that two sets of 50 bytes were equal.
try expect(!mem.eql(u8, &buf_a, &buf_b));
}
+
+test "memory mapping" {
+ const io = testing.io;
+
+ var tmp = tmpDir(.{});
+ defer tmp.cleanup();
+
+ try tmp.dir.writeFile(io, .{
+ .sub_path = "blah.txt",
+ .data = "this is my data123",
+ });
+
+ {
+ var file = try tmp.dir.openFile(io, "blah.txt", .{});
+ defer file.close(io);
+
+ var mm = try file.createMemoryMap(io, .{});
+ defer mm.destroy(io);
+
+ try expectEqualStrings("this is my data123", mm.memory);
+ mm.memory[5] = '9';
+ mm.memory[8] = '9';
+
+ try mm.write(io);
+ }
+
+ var buffer: [100]u8 = undefined;
+ const updated_contents = try tmp.dir.readFile(io, "blah.txt", &buffer);
+ try expectEqualStrings("this9is9my data123", updated_contents);
+
+ var file = try tmp.dir.openFile(io, "blah.txt", .{});
+ defer file.close(io);
+
+ var mm = try file.createMemoryMap(io, .{
+ .protection = .{ .read = true },
+ .offset = 2,
+ });
+ defer mm.destroy(io);
+
+ try expectEqualStrings("is9is9my data123", mm.memory);
+}