std.mem.Allocator missing runtime-known alignment functions

Allocgate missing runtime-known alignment functions · Issue #10348 · ziglang/zig · GitHub was closed by Allocator: `allocBytes` and `reallocBytes` by leecannon · Pull Request #10352 · ziglang/zig · GitHub but it was reverted in https://codeberg.org/ziglang/zig/commit/ceb0a632 so there is no function in std.mem.Allocator to do an allocation with a runtime known alignment except rawAlloc.

Should I use rawAlloc?
Should I open an issue about this?

Isn’t there any of the allocWithOptions ? Otherwise, specify the alignement in the type directly with align(X).

Zig doesn’t store alignement as I’m aware at runtime so you need to tell the compiler directly.

Edit : OP was talking about runtime alignement

SORRY !
I’m dumb, didn’t read it correctly… I’ll leave my older message for shame.

1 Like

haha no problem :ok_hand:

1 Like

Hum it looks they did not end up needing runtime-known alignment. In my case I do actually need runtime known alignment.

The bottom of my answer contains a link to functions that allow runtime alignment, basically you switch on the alignment and the inline prongs of the switch turn the runtime alignment into something that is statically known allowing you to call one of the functions with the right comptime alignment.

3 Likes

interesting, but afaik the interface allows runtime known alignments; rawAlloc takes a runtime alignment parameter, so with it I can implement the allocation functions that I need. It just seemed like a strange hole in the Allocator api.

1 Like

to add to this here’s the implementation ill be using as a workaround for now:

pub fn freeRuntimeAligned(
    allocator: std.mem.Allocator,
    old_mem: []u8,
    alignment: std.mem.Alignment,
) void {
    if (old_mem.len == 0) return;
    @memset(old_mem, undefined);
    allocator.rawFree(old_mem, alignment, @returnAddress());
}

pub fn reallocRuntimeAligned(
    allocator: std.mem.Allocator,
    old_mem: []u8,
    alignment: std.mem.Alignment,
    new_byte_count: usize,
) std.mem.Allocator.Error![]u8 {
    const return_address = @returnAddress();
    if (old_mem.len == 0) {
        const new_mem = allocator.rawAlloc(new_byte_count, alignment, return_address) orelse
            return error.OutOfMemory;
        return new_mem[0..new_byte_count];
    }
    if (new_byte_count == 0) {
        allocator.rawFree(old_mem, alignment, return_address);
        const addr = std.mem.alignBackward(usize, std.math.maxInt(usize), alignment.toByteUnits());
        const ptr: [*]u8 = @ptrFromInt(addr);
        return ptr[0..0];
    }

    if (allocator.rawRemap(old_mem, alignment, new_byte_count, return_address)) |p| {
        return p[0..new_byte_count];
    }

    const new_mem = allocator.rawAlloc(new_byte_count, alignment, return_address) orelse
        return error.OutOfMemory;
    const copy_len = @min(new_byte_count, old_mem.len);
    @memcpy(new_mem[0..copy_len], old_mem[0..copy_len]);
    @memset(old_mem, undefined);
    allocator.rawFree(old_mem, alignment, return_address);

    return new_mem[0..new_byte_count];
}
2 Likes

For future reference, since Allocator is a runtime interface, all information must be lowered to runtime data before the vtable because runtime function pointers can’t take comptime parameters.