0

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?

Hanaasagi
  • 219
  • 3
  • 7

1 Answers1

2

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);
}
sigod
  • 3,514
  • 2
  • 21
  • 44
  • Is a copy happening in `return t.*` ? Is this copy a shallow copy or a deep copy? – Hanaasagi May 26 '23 at 16:38
  • 2
    @Hanaasagi -- `t.*` evaluates to a struct and `return t.*` returns a copy of that struct. This is exactly the same behavior you would see in C: the return value is passed back to the caller _as if by assignment_. So taking the address of the returned value does not give you a pointer to the original allocation. I don't see this explicitly described in the Zig documentation, but I'm not sure that it could be any other way. – ad absurdum May 26 '23 at 16:48