tiny.stabilizer.ShuffleAllocator
Defined in tiny.stabilizer.
API (15)
Actions
Public operations.
allocatorcallocdeinitfreePointerfreePointerIfOwnedinitmallocownsPointerreallocrequestedLength
Fields and members
Public fields and members.
Source
Source: lib/stabilizer/src/heap.zig:77
zig
pub const ShuffleAllocator = struct { backing: Allocator, config: HeapConfig, rng: Marsaglia, pools: std.ArrayListUnmanaged(Pool) = .empty, known: std.AutoHashMapUnmanaged(usize, AllocationState) = .empty, pub fn init(backing: Allocator, heap_config: HeapConfig, seed: u64) ShuffleAllocator { return .{ .backing = backing, .config = normalizeHeapConfig(heap_config), .rng = Marsaglia.init(seed), }; } pub fn deinit(self: *ShuffleAllocator) void { for (self.pools.items) |*pool| pool.deinit(self); self.pools.deinit(self.backing); self.known.deinit(self.backing); self.* = undefined; } pub fn allocator(self: *ShuffleAllocator) Allocator { return .{ .ptr = self, .vtable = &vtable }; } pub fn malloc(self: *ShuffleAllocator, len: usize) ![*]u8 { return try self.alloc(len, Alignment.fromByteUnits(1), true, @returnAddress()); } pub fn calloc(self: *ShuffleAllocator, count: usize, len: usize) ![*]u8 { const total = std.math.mul(usize, count, len) catch return error.OutOfMemory; const memory = try self.malloc(total); @memset(memory[0..total], 0); return memory; } pub fn realloc(self: *ShuffleAllocator, ptr: ?[*]u8, new_len: usize) !?[*]u8 { const memory = ptr orelse return try self.malloc(new_len); const state = self.known.get(@intFromPtr(memory)) orelse return error.InvalidAllocation; if (state == .inactive) return error.InvalidAllocation; const header = checkedHeader(memory) orelse return error.InvalidAllocation; if (!header.allocated) return error.InvalidAllocation; const alignment = Alignment.fromByteUnits(header.alignment); const old_len = header.requested_len; const old_memory = memory[0..old_len]; if (new_len == 0) { self.free(old_memory, alignment, @returnAddress()); return null; } if (self.resize(old_memory, alignment, new_len, @returnAddress())) return memory; const new_memory = try self.alloc(new_len, alignment, true, @returnAddress()); @memcpy(new_memory[0..@min(old_len, new_len)], old_memory[0..@min(old_len, new_len)]); self.free(old_memory, alignment, @returnAddress()); return new_memory; } pub fn freePointer(self: *ShuffleAllocator, ptr: ?[*]u8) void { _ = self.freePointerIfOwned(ptr); } pub fn freePointerIfOwned(self: *ShuffleAllocator, ptr: ?[*]u8) bool { const memory = ptr orelse return true; const state = self.known.get(@intFromPtr(memory)) orelse return false; if (state == .inactive) reportDoubleFreeError(); const header = checkedHeader(memory) orelse return false; self.free(memory[0..header.requested_len], Alignment.fromByteUnits(header.alignment), @returnAddress()); return true; } pub fn ownsPointer(self: *const ShuffleAllocator, ptr: ?[*]u8) bool { const memory = ptr orelse return false; return self.known.get(@intFromPtr(memory)) != null; } pub fn requestedLength(ptr: [*]u8) ?usize { const header = checkedHeader(ptr) orelse return null; if (!header.allocated) return null; return header.requested_len; } fn normalizedSlots(self: *const ShuffleAllocator) usize { return if (self.config.shuffle_slots == 0) 1 else self.config.shuffle_slots; } fn alloc( self: *ShuffleAllocator, len: usize, alignment: Alignment, pointer_validation: bool, ret_addr: usize, ) ![*]u8 { if (!self.config.enabled or len > self.config.max_shuffled_size) { const memory = try self.createUserMemory( len, alignment, 0, pointer_validation, .active, ); _ = ret_addr; return memory.ptr; } const class_size = try sizeClass(len, self.config.min_class_size); const pool = try self.getPool(class_size, alignment, pointer_validation); const index = self.rng.bounded(pool.slots.len); const replacement = Slot{ .memory = try self.createUserMemory( class_size, alignment, class_size, pointer_validation, .inactive, ) }; const selected = pool.slots[index]; const header = headerFromUser(selected.memory.ptr); if (header.allocated) reportDoubleFreeError(); if (pointer_validation) self.activatePointer(selected.memory.ptr); pool.slots[index] = replacement; header.requested_len = len; header.allocated = true; return selected.memory.ptr; } fn resize(self: *ShuffleAllocator, memory: []u8, alignment: Alignment, new_len: usize, ret_addr: usize) bool { _ = self; _ = ret_addr; const header = checkedHeader(memory.ptr) orelse return false; if (!header.allocated) return false; if (header.alignment != alignment.toByteUnits()) return false; const current_class = header.class_size; if (current_class == 0) { if (new_len <= header.base_len - headerOffset(memory.ptr, header)) { header.requested_len = new_len; return true; } return false; } if (new_len <= current_class) { header.requested_len = new_len; return true; } return false; } fn remap(self: *ShuffleAllocator, memory: []u8, alignment: Alignment, new_len: usize, ret_addr: usize) ?[*]u8 { _ = self; _ = memory; _ = alignment; _ = new_len; _ = ret_addr; return null; } fn free(self: *ShuffleAllocator, memory: []u8, alignment: Alignment, ret_addr: usize) void { const header = checkedHeader(memory.ptr) orelse return; if (header.alignment != alignment.toByteUnits()) return; if (!header.allocated) reportDoubleFreeError(); header.allocated = false; if (header.tracked) { const state = self.known.getPtr(@intFromPtr(memory.ptr)) orelse unreachable; std.debug.assert(state.* == .active); state.* = .inactive; } if (header.class_size == 0 or !self.config.enabled) { self.destroyUserMemory(memory.ptr, ret_addr); return; } const pool = self.findPool(header.class_size, alignment, header.tracked) orelse { self.destroyUserMemory(memory.ptr, ret_addr); return; }; const index = self.rng.bounded(pool.slots.len); const evicted = pool.slots[index]; pool.slots[index] = .{ .memory = memory.ptr[0..header.class_size] }; self.destroySlot(evicted); } fn getPool( self: *ShuffleAllocator, class_size: usize, alignment: Alignment, pointer_validation: bool, ) !*Pool { if (self.findPool(class_size, alignment, pointer_validation)) |pool| return pool; var pool = try Pool.init(self, class_size, alignment, pointer_validation); errdefer pool.deinit(self); try self.pools.append(self.backing, pool); return &self.pools.items[self.pools.items.len - 1]; } fn findPool( self: *ShuffleAllocator, class_size: usize, alignment: Alignment, pointer_validation: bool, ) ?*Pool { for (self.pools.items) |*pool| { if (pool.class_size == class_size and pool.alignment == alignment and pool.pointer_validation == pointer_validation) { return pool; } } return null; } fn createUserMemory( self: *ShuffleAllocator, len: usize, alignment: Alignment, class_size: usize, pointer_validation: bool, state: AllocationState, ) ![]u8 { const user_alignment = Alignment.max(alignment, .of(Header)); const alignment_bytes = user_alignment.toByteUnits(); const overhead = std.math.add(usize, @sizeOf(Header), alignment_bytes - 1) catch return error.OutOfMemory; const base_len = std.math.add(usize, len, overhead) catch return error.OutOfMemory; const base = try self.backing.alloc(u8, base_len); const user_addr = user_alignment.forward(@intFromPtr(base.ptr) + @sizeOf(Header)); const header: *Header = @ptrFromInt(user_addr - @sizeOf(Header)); header.* = .{ .magic = allocation_magic, .base_addr = @intFromPtr(base.ptr), .base_len = base_len, .class_size = class_size, .requested_len = len, .alignment = alignment.toByteUnits(), .allocated = class_size == 0, .tracked = false, }; errdefer self.backing.free(base); if (pointer_validation) { try self.known.put(self.backing, user_addr, state); header.tracked = true; } return @as([*]u8, @ptrFromInt(user_addr))[0..len]; } fn activatePointer(self: *ShuffleAllocator, ptr: [*]u8) void { const header = headerFromUser(ptr); std.debug.assert(header.tracked); const state = self.known.getPtr(@intFromPtr(ptr)) orelse unreachable; std.debug.assert(state.* == .inactive); state.* = .active; } fn destroySlot(self: *ShuffleAllocator, slot: Slot) void { self.destroyUserMemory(slot.memory.ptr, @returnAddress()); } fn destroyUserMemory(self: *ShuffleAllocator, ptr: [*]u8, ret_addr: usize) void { _ = ret_addr; const header = checkedHeader(ptr) orelse return; const base: [*]u8 = @ptrFromInt(header.base_addr); if (header.tracked) std.debug.assert(self.known.remove(@intFromPtr(ptr))); self.backing.free(base[0..header.base_len]); } const vtable: Allocator.VTable = .{ .alloc = rawAlloc, .resize = rawResize, .remap = rawRemap, .free = rawFree, }; fn rawAlloc(ctx: *anyopaque, len: usize, alignment: Alignment, ret_addr: usize) ?[*]u8 { const self: *ShuffleAllocator = @ptrCast(@alignCast(ctx)); return self.alloc(len, alignment, self.config.pointer_validation, ret_addr) catch null; } fn rawResize(ctx: *anyopaque, memory: []u8, alignment: Alignment, new_len: usize, ret_addr: usize) bool { const self: *ShuffleAllocator = @ptrCast(@alignCast(ctx)); return self.resize(memory, alignment, new_len, ret_addr); } fn rawRemap(ctx: *anyopaque, memory: []u8, alignment: Alignment, new_len: usize, ret_addr: usize) ?[*]u8 { const self: *ShuffleAllocator = @ptrCast(@alignCast(ctx)); return self.remap(memory, alignment, new_len, ret_addr); } fn rawFree(ctx: *anyopaque, memory: []u8, alignment: Alignment, ret_addr: usize) void { const self: *ShuffleAllocator = @ptrCast(@alignCast(ctx)); self.free(memory, alignment, ret_addr); }};Source: lib/stabilizer/src/root.zig:55
zig
pub const ShuffleAllocator = heap_mod.ShuffleAllocator;Complete caller list for ShuffleAllocator.allocator
7 direct callers.
lib.stabilizer.src.heap.exerciseTrackedPoolAllocationFailures[function] — private source atlib/stabilizer/src/heap.zig:412in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_allocator_pointer_validation_defaults_to_tracked_pointers[function] — test source atlib/stabilizer/src/heap.zig:504in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_allocator_pointer_validation_is_explicit_and_C_pointers_remain_tracked[function] — test source atlib/stabilizer/src/heap.zig:475in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_untracked_direct_allocations_resize_remap_and_free_without_the_address_map[function] — test source atlib/stabilizer/src/heap.zig:594in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.properties.heap.AllocatorProperty.property[function] — private source atlib/stabilizer/src/properties/heap.zig:73in nearest public ownerlib.stabilizer.src.properties.heaplib.stabilizer.src.properties.heap.test_shuffle_allocator_reuses_frees_through_the_vector[function] — test source atlib/stabilizer/src/properties/heap.zig:47in nearest public ownerlib.stabilizer.src.properties.heaptiny.stabilizer.Runtime.randomizedAllocator[method] atlib/stabilizer/src/runtime.zig:47
Complete caller list for ShuffleAllocator.deinit
14 direct callers.
lib.stabilizer.src.heap.exerciseTrackedPoolAllocationFailures[function] — private source atlib/stabilizer/src/heap.zig:412in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_allocation_size_overflow_is_reported_as_out_of_memory[function] — test source atlib/stabilizer/src/heap.zig:615in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_allocator_pointer_validation_defaults_to_tracked_pointers[function] — test source atlib/stabilizer/src/heap.zig:504in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_allocator_pointer_validation_is_explicit_and_C_pointers_remain_tracked[function] — test source atlib/stabilizer/src/heap.zig:475in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_pointer_tracking_allocation_failure_releases_direct_memory[function] — test source atlib/stabilizer/src/heap.zig:518in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_pooled_pointer_tracking_failure_preserves_the_selected_slot[function] — test source atlib/stabilizer/src/heap.zig:538in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_realloc_tracking_failure_preserves_the_old_allocation[function] — test source atlib/stabilizer/src/heap.zig:568in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_shuffle_allocator_exposes_upstream_c_heap_operations[function] — test source atlib/stabilizer/src/heap.zig:425in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_shuffle_allocator_marks_freed_shuffled_pointers_inactive[function] — test source atlib/stabilizer/src/heap.zig:455in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_untracked_direct_allocations_resize_remap_and_free_without_the_address_map[function] — test source atlib/stabilizer/src/heap.zig:594in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.properties.heap.AllocatorProperty.property[function] — private source atlib/stabilizer/src/properties/heap.zig:73in nearest public ownerlib.stabilizer.src.properties.heaplib.stabilizer.src.properties.heap.CHeapProperty.property[function] — private source atlib/stabilizer/src/properties/heap.zig:140in nearest public ownerlib.stabilizer.src.properties.heaplib.stabilizer.src.properties.heap.test_shuffle_allocator_reuses_frees_through_the_vector[function] — test source atlib/stabilizer/src/properties/heap.zig:47in nearest public ownerlib.stabilizer.src.properties.heaptiny.stabilizer.Runtime.deinit[method] atlib/stabilizer/src/runtime.zig:38
Complete caller list for ShuffleAllocator.freePointer
7 direct callers.
lib.stabilizer.src.heap.test_allocator_pointer_validation_is_explicit_and_C_pointers_remain_tracked[function] — test source atlib/stabilizer/src/heap.zig:475in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_pooled_pointer_tracking_failure_preserves_the_selected_slot[function] — test source atlib/stabilizer/src/heap.zig:538in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_realloc_tracking_failure_preserves_the_old_allocation[function] — test source atlib/stabilizer/src/heap.zig:568in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_shuffle_allocator_exposes_upstream_c_heap_operations[function] — test source atlib/stabilizer/src/heap.zig:425in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_shuffle_allocator_marks_freed_shuffled_pointers_inactive[function] — test source atlib/stabilizer/src/heap.zig:455in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.properties.heap.CHeapProperty.property[function] — private source atlib/stabilizer/src/properties/heap.zig:140in nearest public ownerlib.stabilizer.src.properties.heaptiny.stabilizer.Runtime.free[method] atlib/stabilizer/src/runtime.zig:63
Complete caller list for ShuffleAllocator.init
14 direct callers.
lib.stabilizer.src.heap.exerciseTrackedPoolAllocationFailures[function] — private source atlib/stabilizer/src/heap.zig:412in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_allocation_size_overflow_is_reported_as_out_of_memory[function] — test source atlib/stabilizer/src/heap.zig:615in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_allocator_pointer_validation_defaults_to_tracked_pointers[function] — test source atlib/stabilizer/src/heap.zig:504in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_allocator_pointer_validation_is_explicit_and_C_pointers_remain_tracked[function] — test source atlib/stabilizer/src/heap.zig:475in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_pointer_tracking_allocation_failure_releases_direct_memory[function] — test source atlib/stabilizer/src/heap.zig:518in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_pooled_pointer_tracking_failure_preserves_the_selected_slot[function] — test source atlib/stabilizer/src/heap.zig:538in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_realloc_tracking_failure_preserves_the_old_allocation[function] — test source atlib/stabilizer/src/heap.zig:568in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_shuffle_allocator_exposes_upstream_c_heap_operations[function] — test source atlib/stabilizer/src/heap.zig:425in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_shuffle_allocator_marks_freed_shuffled_pointers_inactive[function] — test source atlib/stabilizer/src/heap.zig:455in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_untracked_direct_allocations_resize_remap_and_free_without_the_address_map[function] — test source atlib/stabilizer/src/heap.zig:594in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.properties.heap.AllocatorProperty.property[function] — private source atlib/stabilizer/src/properties/heap.zig:73in nearest public ownerlib.stabilizer.src.properties.heaplib.stabilizer.src.properties.heap.CHeapProperty.property[function] — private source atlib/stabilizer/src/properties/heap.zig:140in nearest public ownerlib.stabilizer.src.properties.heaplib.stabilizer.src.properties.heap.test_shuffle_allocator_reuses_frees_through_the_vector[function] — test source atlib/stabilizer/src/properties/heap.zig:47in nearest public ownerlib.stabilizer.src.properties.heaptiny.stabilizer.Runtime.init[function] atlib/stabilizer/src/runtime.zig:24
Complete caller list for ShuffleAllocator.malloc
10 direct callers.
tiny.stabilizer.ShuffleAllocator.calloc[method] atlib/stabilizer/src/heap.zig:107tiny.stabilizer.ShuffleAllocator.realloc[method] atlib/stabilizer/src/heap.zig:114lib.stabilizer.src.heap.test_allocation_size_overflow_is_reported_as_out_of_memory[function] — test source atlib/stabilizer/src/heap.zig:615in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_allocator_pointer_validation_is_explicit_and_C_pointers_remain_tracked[function] — test source atlib/stabilizer/src/heap.zig:475in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_pointer_tracking_allocation_failure_releases_direct_memory[function] — test source atlib/stabilizer/src/heap.zig:518in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_pooled_pointer_tracking_failure_preserves_the_selected_slot[function] — test source atlib/stabilizer/src/heap.zig:538in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_realloc_tracking_failure_preserves_the_old_allocation[function] — test source atlib/stabilizer/src/heap.zig:568in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.heap.test_shuffle_allocator_marks_freed_shuffled_pointers_inactive[function] — test source atlib/stabilizer/src/heap.zig:455in nearest public ownerlib.stabilizer.src.heaplib.stabilizer.src.properties.heap.CHeapProperty.property[function] — private source atlib/stabilizer/src/properties/heap.zig:140in nearest public ownerlib.stabilizer.src.properties.heaptiny.stabilizer.Runtime.malloc[method] atlib/stabilizer/src/runtime.zig:51
Audit
| Definitions | 11 |
|---|---|
| Public names | 11 |
| Members | 5 |
| Version | 26.7.0 |
| Revision | daab053ee433 |