std.heap.PageAllocator: fix not respecting alignments

in remap and resize, alignments larger than page size were incorrectly ignored.
This commit is contained in:
Andrew Kelley 2026-02-11 19:41:37 -08:00
parent 0a61eca22c
commit 5c59a46238
2 changed files with 21 additions and 24 deletions

View file

@ -1,19 +1,17 @@
const std = @import("../std.zig");
const builtin = @import("builtin");
const native_os = builtin.os.tag;
const std = @import("../std.zig");
const Allocator = std.mem.Allocator;
const Alignment = std.mem.Alignment;
const mem = std.mem;
const maxInt = std.math.maxInt;
const assert = std.debug.assert;
const native_os = builtin.os.tag;
const windows = std.os.windows;
const ntdll = windows.ntdll;
const ntdll = std.os.windows.ntdll;
const posix = std.posix;
const page_size_min = std.heap.page_size_min;
const SUCCESS = @import("../os/windows/ntstatus.zig").NTSTATUS.SUCCESS;
const MEM_RESERVE_PLACEHOLDER = windows.MEM_RESERVE_PLACEHOLDER;
const MEM_PRESERVE_PLACEHOLDER = windows.MEM_PRESERVE_PLACEHOLDER;
pub const vtable: Allocator.VTable = .{
.alloc = alloc,
.resize = resize,
@ -21,7 +19,7 @@ pub const vtable: Allocator.VTable = .{
.free = free,
};
pub fn map(n: usize, alignment: mem.Alignment) ?[*]u8 {
pub fn map(n: usize, alignment: Alignment) ?[*]u8 {
const page_size = std.heap.pageSize();
if (n >= maxInt(usize) - page_size) return null;
const alignment_bytes = alignment.toByteUnits();
@ -33,11 +31,11 @@ pub fn map(n: usize, alignment: mem.Alignment) ?[*]u8 {
const current_process = windows.GetCurrentProcess();
var status = ntdll.NtAllocateVirtualMemory(current_process, @ptrCast(&base_addr), 0, &size, .{ .COMMIT = true, .RESERVE = true }, .{ .READWRITE = true });
if (status == SUCCESS and mem.isAligned(@intFromPtr(base_addr), alignment_bytes)) {
if (status == .SUCCESS and mem.isAligned(@intFromPtr(base_addr), alignment_bytes)) {
return @ptrCast(base_addr);
}
if (status == SUCCESS) {
if (status == .SUCCESS) {
var region_size: windows.SIZE_T = 0;
_ = ntdll.NtFreeVirtualMemory(current_process, @ptrCast(&base_addr), &region_size, .{ .RELEASE = true });
}
@ -50,7 +48,7 @@ pub fn map(n: usize, alignment: mem.Alignment) ?[*]u8 {
status = ntdll.NtAllocateVirtualMemory(current_process, @ptrCast(&base_addr), 0, &size, .{ .RESERVE = true, .RESERVE_PLACEHOLDER = true }, .{ .NOACCESS = true });
if (status != SUCCESS) return null;
if (status != .SUCCESS) return null;
const placeholder_addr = @intFromPtr(base_addr);
const aligned_addr = mem.alignForward(usize, placeholder_addr, alignment_bytes);
@ -75,7 +73,7 @@ pub fn map(n: usize, alignment: mem.Alignment) ?[*]u8 {
status = ntdll.NtAllocateVirtualMemory(current_process, @ptrCast(&base_addr), 0, &size, .{ .COMMIT = true }, .{ .READWRITE = true });
if (status == SUCCESS) {
if (status == .SUCCESS) {
return @ptrCast(base_addr);
}
@ -116,31 +114,29 @@ pub fn map(n: usize, alignment: mem.Alignment) ?[*]u8 {
return result_ptr;
}
fn alloc(context: *anyopaque, n: usize, alignment: mem.Alignment, ra: usize) ?[*]u8 {
fn alloc(context: *anyopaque, n: usize, alignment: Alignment, ra: usize) ?[*]u8 {
_ = context;
_ = ra;
assert(n > 0);
return map(n, alignment);
}
fn resize(context: *anyopaque, memory: []u8, alignment: mem.Alignment, new_len: usize, return_address: usize) bool {
fn resize(context: *anyopaque, memory: []u8, alignment: Alignment, new_len: usize, return_address: usize) bool {
_ = context;
_ = alignment;
_ = return_address;
return realloc(memory, new_len, false) != null;
return realloc(memory, alignment, new_len, false) != null;
}
fn remap(context: *anyopaque, memory: []u8, alignment: mem.Alignment, new_len: usize, return_address: usize) ?[*]u8 {
fn remap(context: *anyopaque, memory: []u8, alignment: Alignment, new_len: usize, return_address: usize) ?[*]u8 {
_ = context;
_ = alignment;
_ = return_address;
return realloc(memory, new_len, true);
return realloc(memory, alignment, new_len, true);
}
fn free(context: *anyopaque, memory: []u8, alignment: mem.Alignment, return_address: usize) void {
fn free(context: *anyopaque, memory: []u8, alignment: Alignment, return_address: usize) void {
_ = context;
_ = alignment;
_ = return_address;
_ = alignment;
return unmap(@alignCast(memory));
}
@ -155,9 +151,10 @@ pub fn unmap(memory: []align(page_size_min) u8) void {
}
}
pub fn realloc(uncasted_memory: []u8, new_len: usize, may_move: bool) ?[*]u8 {
pub fn realloc(uncasted_memory: []u8, alignment: Alignment, new_len: usize, may_move: bool) ?[*]u8 {
const memory: []align(page_size_min) u8 = @alignCast(uncasted_memory);
const page_size = std.heap.pageSize();
if (alignment.toByteUnits() > page_size) return null;
const new_size_aligned = mem.alignForward(usize, new_len, page_size);
if (native_os == .windows) {

View file

@ -179,7 +179,7 @@ fn resize(context: *anyopaque, memory: []u8, alignment: mem.Alignment, new_len:
const new_class = sizeClassIndex(new_len, alignment);
if (class >= size_class_count) {
if (new_class < size_class_count) return false;
return PageAllocator.realloc(memory, new_len, false) != null;
return PageAllocator.realloc(memory, alignment, new_len, false) != null;
}
return new_class == class;
}
@ -191,7 +191,7 @@ fn remap(context: *anyopaque, memory: []u8, alignment: mem.Alignment, new_len: u
const new_class = sizeClassIndex(new_len, alignment);
if (class >= size_class_count) {
if (new_class < size_class_count) return null;
return PageAllocator.realloc(memory, new_len, true);
return PageAllocator.realloc(memory, alignment, new_len, true);
}
return if (new_class == class) memory.ptr else null;
}