Skip to documentation
SLOP

tiny.stabilizer.ShuffleAllocator

Reference tiny.stabilizer ShuffleAllocator

Defined in tiny.stabilizer.

API (15)

Actions

Public operations.

Fields and members

Public fields and members.

No direct callersNo direct callstiny.stabilizerShuffleAllocator
Static calls · unresolved targets: unknown · external targets: unknown.

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;
Called byCallsNo direct callsprivate sourcelib.stabilizer.src.heapexerciseTrackedPoolAllocationFailurestest sourcelib.stabilizer.src.heaptest: allocator pointer validation de...test sourcelib.stabilizer.src.heaptest: allocator pointer validation is...test sourcelib.stabilizer.src.heaptest: untracked direct allocations re...private sourcelib.stabilizer.src.properties.heap.AllocatorP...property+2 moreShuffleAllocatorallocator
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.stabilizer.src.heaptest: shuffle allocator exposes upstr...private sourcelib.stabilizer.src.properties.heap.CHeapPropertypropertyRuntimecallocShuffleAllocatormallocShuffleAllocatorcalloc
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsprivate sourcelib.stabilizer.src.heapexerciseTrackedPoolAllocationFailurestest sourcelib.stabilizer.src.heaptest: allocation size overflow is rep...test sourcelib.stabilizer.src.heaptest: allocator pointer validation de...test sourcelib.stabilizer.src.heaptest: allocator pointer validation is...test sourcelib.stabilizer.src.heaptest: pointer tracking allocation fai...+9 moreShuffleAllocatordeinit
Static calls · unresolved targets: 0 · external targets: 3.
Called byCallstest sourcelib.stabilizer.src.heaptest: allocator pointer validation is...test sourcelib.stabilizer.src.heaptest: pooled pointer tracking failure...test sourcelib.stabilizer.src.heaptest: realloc tracking failure preser...test sourcelib.stabilizer.src.heaptest: shuffle allocator exposes upstr...test sourcelib.stabilizer.src.heaptest: shuffle allocator marks freed s...+2 moreShuffleAllocatorfreePointerIfOwnedShuffleAllocatorfreePointer
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsShuffleAllocatorfreePointertest sourcelib.stabilizer.src.heaptest: shuffle allocator marks freed s...RuntimefreeIfOwnedprivate sourcelib.stabilizer.src.heap.ShuffleAllocatorfreeprivate sourcelib.stabilizer.src.heapcheckedHeaderprivate sourcelib.stabilizer.src.heapreportDoubleFreeErrorShuffleAllocatorfreePointerIfOwned
Static calls · unresolved targets: 2 · external targets: 0.
Called byCallsprivate sourcelib.stabilizer.src.heapexerciseTrackedPoolAllocationFailurestest sourcelib.stabilizer.src.heaptest: allocation size overflow is rep...test sourcelib.stabilizer.src.heaptest: allocator pointer validation de...test sourcelib.stabilizer.src.heaptest: allocator pointer validation is...test sourcelib.stabilizer.src.heaptest: pointer tracking allocation fai...+9 moreprivate sourcelib.stabilizer.src.heapnormalizeHeapConfigMarsagliainitShuffleAllocatorinit
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsShuffleAllocatorcallocShuffleAllocatorrealloctest sourcelib.stabilizer.src.heaptest: allocation size overflow is rep...test sourcelib.stabilizer.src.heaptest: allocator pointer validation is...test sourcelib.stabilizer.src.heaptest: pointer tracking allocation fai...+5 moreprivate sourcelib.stabilizer.src.heap.ShuffleAllocatorallocShuffleAllocatormalloc
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsNo direct callstest sourcelib.stabilizer.src.heaptest: allocator pointer validation de...test sourcelib.stabilizer.src.heaptest: allocator pointer validation is...test sourcelib.stabilizer.src.heaptest: realloc tracking failure preser...test sourcelib.stabilizer.src.heaptest: shuffle allocator marks freed s...RuntimeownsPointerShuffleAllocatorownsPointer
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallstest sourcelib.stabilizer.src.heaptest: realloc tracking failure preser...test sourcelib.stabilizer.src.heaptest: shuffle allocator exposes upstr...test sourcelib.stabilizer.src.heaptest: shuffle allocator marks freed s...private sourcelib.stabilizer.src.properties.heap.CHeapPropertypropertyRuntimereallocprivate sourcelib.stabilizer.src.heap.ShuffleAllocatorallocprivate sourcelib.stabilizer.src.heap.ShuffleAllocatorfreeShuffleAllocatormallocprivate sourcelib.stabilizer.src.heap.ShuffleAllocatorresizeprivate sourcelib.stabilizer.src.heapcheckedHeaderShuffleAllocatorrealloc
Static calls · unresolved targets: 2 · external targets: 0.
Called byCallstest sourcelib.stabilizer.src.heaptest: realloc tracking failure preser...test sourcelib.stabilizer.src.heaptest: shuffle allocator exposes upstr...test sourcelib.stabilizer.src.heaptest: shuffle allocator marks freed s...private sourcelib.stabilizer.src.properties.heap.CHeapPropertypropertyprivate sourcelib.stabilizer.src.heapcheckedHeaderShuffleAllocatorrequestedLength
Static calls · unresolved targets: 0 · external targets: 0.

Complete caller list for ShuffleAllocator.allocator

7 direct callers.

Complete caller list for ShuffleAllocator.deinit

14 direct callers.

Complete caller list for ShuffleAllocator.freePointer

7 direct callers.

Complete caller list for ShuffleAllocator.init

14 direct callers.

Complete caller list for ShuffleAllocator.malloc

10 direct callers.

Audit

Definitions11
Public names11
Members5
Version26.7.0
Revisiondaab053ee433