Search code examples
zig

Incorrect alignment when destroy a value in Zig


I tried using the create and destroy functions mentioned in the documentation to create and destroy the value. However, a panic occurs during the destroy.

Fullstack:

run test: error: thread 2017663 panic: incorrect alignment
/home/kumiko/zig/zig-linux-x86_64-0.11.0-dev.3206+b9d2e0e30/lib/std/heap/PageAllocator.zig:107:52: 0x2106a0 in free (test)
        const ptr = @alignCast(mem.page_size, slice.ptr);
                                                   ^
/home/kumiko/zig/zig-linux-x86_64-0.11.0-dev.3206+b9d2e0e30/lib/std/mem/Allocator.zig:98:28: 0x20f2c9 in destroy__anon_1471 (test)
    return self.vtable.free(self.ptr, buf, log2_buf_align, ret_addr);
                           ^
/home/kumiko/zig/struct-env/t/src/main.zig:38:36: 0x20f222 in test.simple test (test)
    std.heap.page_allocator.destroy(&t);

Minimal reproduction code

const T = struct {
    a: u32,
};

fn testFn() !T {
    var t = try std.heap.page_allocator.create(T);
    t.a = 10;
    return t.*;
}

test "simple test" {
    var t = try testFn();
    try std.testing.expect(t.a == 10);
    std.heap.page_allocator.destroy(&t);
}

Some attempts

I tried using a global variable to store it, and in this case, there is no panic.

var g: ?*T = null;

const T = struct {
    a: u32,
};

fn testFn() !T {
    var t = try std.heap.page_allocator.create(T);
    t.a = 10;
    g = t;
    return t.*;
}

test "simple test" {
    var t = try testFn();
    try std.testing.expect(t.a == 10);
    std.heap.page_allocator.destroy(g.?);
}

Why the alignment is incorrect? And how can I get the correct alignment to destroy the value?


Solution

  • create returns *T (a pointer to T). But your testFn returns T by copying it. Later in the test you call destroy and give it an address of a local copy of T instead of the original pointer that create returned.

    Here's corrected code:

    const std = @import("std");
    
    const T = struct {
        a: u32,
    };
    
    fn testFn() !*T {
        var t = try std.heap.page_allocator.create(T);
        t.a = 10;
        return t;
    }
    
    test "simple test" {
        var t = try testFn(); // `t` is now of type `*T`
        try std.testing.expect(t.a == 10);
        std.heap.page_allocator.destroy(t);
    }