authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-11 19:41:37-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-12 13:14:51-08:00
log5c59a4623898cdb15b569f59fba49d48a7b9600f
tree226cfe3efb7ea056e2c914cd6a8953076ca5e7a8
parent0a61eca22c5628b0a56d875246fc4ef007a3bad9

std.heap.PageAllocator: fix not respecting alignments

in remap and resize, alignments larger than page size were incorrectly ignored.

2 files changed, 21 insertions(+), 24 deletions(-)

lib/std/heap/PageAllocator.zig+19-22
...@@ -1,19 +1,17 @@...@@ -1,19 +1,17 @@
1const std = @import("../std.zig");
2const builtin = @import("builtin");1const builtin = @import("builtin");
2const native_os = builtin.os.tag;
3
4const std = @import("../std.zig");
3const Allocator = std.mem.Allocator;5const Allocator = std.mem.Allocator;
6const Alignment = std.mem.Alignment;
4const mem = std.mem;7const mem = std.mem;
5const maxInt = std.math.maxInt;8const maxInt = std.math.maxInt;
6const assert = std.debug.assert;9const assert = std.debug.assert;
7const native_os = builtin.os.tag;
8const windows = std.os.windows;10const windows = std.os.windows;
9const ntdll = windows.ntdll;11const ntdll = std.os.windows.ntdll;
10const posix = std.posix;12const posix = std.posix;
11const page_size_min = std.heap.page_size_min;13const page_size_min = std.heap.page_size_min;
1214
13const SUCCESS = @import("../os/windows/ntstatus.zig").NTSTATUS.SUCCESS;
14const MEM_RESERVE_PLACEHOLDER = windows.MEM_RESERVE_PLACEHOLDER;
15const MEM_PRESERVE_PLACEHOLDER = windows.MEM_PRESERVE_PLACEHOLDER;
16
17pub const vtable: Allocator.VTable = .{15pub const vtable: Allocator.VTable = .{
18 .alloc = alloc,16 .alloc = alloc,
19 .resize = resize,17 .resize = resize,
...@@ -21,7 +19,7 @@ pub const vtable: Allocator.VTable = .{...@@ -21,7 +19,7 @@ pub const vtable: Allocator.VTable = .{
21 .free = free,19 .free = free,
22};20};
2321
24pub fn map(n: usize, alignment: mem.Alignment) ?[*]u8 {22pub fn map(n: usize, alignment: Alignment) ?[*]u8 {
25 const page_size = std.heap.pageSize();23 const page_size = std.heap.pageSize();
26 if (n >= maxInt(usize) - page_size) return null;24 if (n >= maxInt(usize) - page_size) return null;
27 const alignment_bytes = alignment.toByteUnits();25 const alignment_bytes = alignment.toByteUnits();
...@@ -33,11 +31,11 @@ pub fn map(n: usize, alignment: mem.Alignment) ?[*]u8 {...@@ -33,11 +31,11 @@ pub fn map(n: usize, alignment: mem.Alignment) ?[*]u8 {
33 const current_process = windows.GetCurrentProcess();31 const current_process = windows.GetCurrentProcess();
34 var status = ntdll.NtAllocateVirtualMemory(current_process, @ptrCast(&base_addr), 0, &size, .{ .COMMIT = true, .RESERVE = true }, .{ .READWRITE = true });32 var status = ntdll.NtAllocateVirtualMemory(current_process, @ptrCast(&base_addr), 0, &size, .{ .COMMIT = true, .RESERVE = true }, .{ .READWRITE = true });
3533
36 if (status == SUCCESS and mem.isAligned(@intFromPtr(base_addr), alignment_bytes)) {34 if (status == .SUCCESS and mem.isAligned(@intFromPtr(base_addr), alignment_bytes)) {
37 return @ptrCast(base_addr);35 return @ptrCast(base_addr);
38 }36 }
3937
40 if (status == SUCCESS) {38 if (status == .SUCCESS) {
41 var region_size: windows.SIZE_T = 0;39 var region_size: windows.SIZE_T = 0;
42 _ = ntdll.NtFreeVirtualMemory(current_process, @ptrCast(&base_addr), &region_size, .{ .RELEASE = true });40 _ = ntdll.NtFreeVirtualMemory(current_process, @ptrCast(&base_addr), &region_size, .{ .RELEASE = true });
43 }41 }
...@@ -50,7 +48,7 @@ pub fn map(n: usize, alignment: mem.Alignment) ?[*]u8 {...@@ -50,7 +48,7 @@ pub fn map(n: usize, alignment: mem.Alignment) ?[*]u8 {
5048
51 status = ntdll.NtAllocateVirtualMemory(current_process, @ptrCast(&base_addr), 0, &size, .{ .RESERVE = true, .RESERVE_PLACEHOLDER = true }, .{ .NOACCESS = true });49 status = ntdll.NtAllocateVirtualMemory(current_process, @ptrCast(&base_addr), 0, &size, .{ .RESERVE = true, .RESERVE_PLACEHOLDER = true }, .{ .NOACCESS = true });
5250
53 if (status != SUCCESS) return null;51 if (status != .SUCCESS) return null;
5452
55 const placeholder_addr = @intFromPtr(base_addr);53 const placeholder_addr = @intFromPtr(base_addr);
56 const aligned_addr = mem.alignForward(usize, placeholder_addr, alignment_bytes);54 const aligned_addr = mem.alignForward(usize, placeholder_addr, alignment_bytes);
...@@ -75,7 +73,7 @@ pub fn map(n: usize, alignment: mem.Alignment) ?[*]u8 {...@@ -75,7 +73,7 @@ pub fn map(n: usize, alignment: mem.Alignment) ?[*]u8 {
7573
76 status = ntdll.NtAllocateVirtualMemory(current_process, @ptrCast(&base_addr), 0, &size, .{ .COMMIT = true }, .{ .READWRITE = true });74 status = ntdll.NtAllocateVirtualMemory(current_process, @ptrCast(&base_addr), 0, &size, .{ .COMMIT = true }, .{ .READWRITE = true });
7775
78 if (status == SUCCESS) {76 if (status == .SUCCESS) {
79 return @ptrCast(base_addr);77 return @ptrCast(base_addr);
80 }78 }
8179
...@@ -116,31 +114,29 @@ pub fn map(n: usize, alignment: mem.Alignment) ?[*]u8 {...@@ -116,31 +114,29 @@ pub fn map(n: usize, alignment: mem.Alignment) ?[*]u8 {
116 return result_ptr;114 return result_ptr;
117}115}
118116
119fn alloc(context: *anyopaque, n: usize, alignment: mem.Alignment, ra: usize) ?[*]u8 {117fn alloc(context: *anyopaque, n: usize, alignment: Alignment, ra: usize) ?[*]u8 {
120 _ = context;118 _ = context;
121 _ = ra;119 _ = ra;
122 assert(n > 0);120 assert(n > 0);
123 return map(n, alignment);121 return map(n, alignment);
124}122}
125123
126fn resize(context: *anyopaque, memory: []u8, alignment: mem.Alignment, new_len: usize, return_address: usize) bool {124fn resize(context: *anyopaque, memory: []u8, alignment: Alignment, new_len: usize, return_address: usize) bool {
127 _ = context;125 _ = context;
128 _ = alignment;
129 _ = return_address;126 _ = return_address;
130 return realloc(memory, new_len, false) != null;127 return realloc(memory, alignment, new_len, false) != null;
131}128}
132129
133fn remap(context: *anyopaque, memory: []u8, alignment: mem.Alignment, new_len: usize, return_address: usize) ?[*]u8 {130fn remap(context: *anyopaque, memory: []u8, alignment: Alignment, new_len: usize, return_address: usize) ?[*]u8 {
134 _ = context;131 _ = context;
135 _ = alignment;
136 _ = return_address;132 _ = return_address;
137 return realloc(memory, new_len, true);133 return realloc(memory, alignment, new_len, true);
138}134}
139135
140fn free(context: *anyopaque, memory: []u8, alignment: mem.Alignment, return_address: usize) void {136fn free(context: *anyopaque, memory: []u8, alignment: Alignment, return_address: usize) void {
141 _ = context;137 _ = context;
142 _ = alignment;
143 _ = return_address;138 _ = return_address;
139 _ = alignment;
144 return unmap(@alignCast(memory));140 return unmap(@alignCast(memory));
145}141}
146142
...@@ -155,9 +151,10 @@ pub fn unmap(memory: []align(page_size_min) u8) void {...@@ -155,9 +151,10 @@ pub fn unmap(memory: []align(page_size_min) u8) void {
155 }151 }
156}152}
157153
158pub fn realloc(uncasted_memory: []u8, new_len: usize, may_move: bool) ?[*]u8 {154pub fn realloc(uncasted_memory: []u8, alignment: Alignment, new_len: usize, may_move: bool) ?[*]u8 {
159 const memory: []align(page_size_min) u8 = @alignCast(uncasted_memory);155 const memory: []align(page_size_min) u8 = @alignCast(uncasted_memory);
160 const page_size = std.heap.pageSize();156 const page_size = std.heap.pageSize();
157 if (alignment.toByteUnits() > page_size) return null;
161 const new_size_aligned = mem.alignForward(usize, new_len, page_size);158 const new_size_aligned = mem.alignForward(usize, new_len, page_size);
162159
163 if (native_os == .windows) {160 if (native_os == .windows) {
lib/std/heap/SmpAllocator.zig+2-2
...@@ -179,7 +179,7 @@ fn resize(context: *anyopaque, memory: []u8, alignment: mem.Alignment, new_len:...@@ -179,7 +179,7 @@ fn resize(context: *anyopaque, memory: []u8, alignment: mem.Alignment, new_len:
179 const new_class = sizeClassIndex(new_len, alignment);179 const new_class = sizeClassIndex(new_len, alignment);
180 if (class >= size_class_count) {180 if (class >= size_class_count) {
181 if (new_class < size_class_count) return false;181 if (new_class < size_class_count) return false;
182 return PageAllocator.realloc(memory, new_len, false) != null;182 return PageAllocator.realloc(memory, alignment, new_len, false) != null;
183 }183 }
184 return new_class == class;184 return new_class == class;
185}185}
...@@ -191,7 +191,7 @@ fn remap(context: *anyopaque, memory: []u8, alignment: mem.Alignment, new_len: u...@@ -191,7 +191,7 @@ fn remap(context: *anyopaque, memory: []u8, alignment: mem.Alignment, new_len: u
191 const new_class = sizeClassIndex(new_len, alignment);191 const new_class = sizeClassIndex(new_len, alignment);
192 if (class >= size_class_count) {192 if (class >= size_class_count) {
193 if (new_class < size_class_count) return null;193 if (new_class < size_class_count) return null;
194 return PageAllocator.realloc(memory, new_len, true);194 return PageAllocator.realloc(memory, alignment, new_len, true);
195 }195 }
196 return if (new_class == class) memory.ptr else null;196 return if (new_class == class) memory.ptr else null;
197}197}