#Segmentation fault using ArrayList in struct

1 messages · Page 1 of 1 (latest)

quiet tinsel
#
const std = @import("std");

const Object = @import("object.zig").Object;
const Shader = @import("shader.zig").Shader;

pub const Scene = struct {
    shader: Shader,
    objects: std.ArrayList(Object),

    pub fn init(allocator: std.mem.Allocator) !Scene {
        var objects = try std.ArrayList(Object).initCapacity(allocator, 2);
        defer objects.deinit();

        const shader = try Shader.init(@embedFile("shaders/vert.glsl"), @embedFile("shaders/frag.glsl"));

        return Scene{
            .objects = objects,
            .shader = shader,
        };
    }

    pub fn newObject(self: *Scene) !Object {
        const obj = Object.init(&self.shader);
        try self.objects.append(obj);

        return obj;
    }

    pub fn use(self: *Scene) void {
        for (self.objects.items) |obj| {
            @constCast(&obj).*.use();
        }
    }

    pub fn deinit(self: *Scene) void {
        for (self.objects.items) |obj| {
            @constCast(&obj).*.deinit();
        }
    }
};
zig build run
info(utils): Creating window Jenjin (1024x768)
Segmentation fault at address 0x7d35bfdd1070
/usr/lib/zig/std/array_list.zig:263:13: 0x10b243d in append (Jenjin)
            new_item_ptr.* = item;
            ^
/home/ben/Dev/Jenjin/src/scene.zig:24:32: 0x10b2170 in newObject (Jenjin)
        try self.objects.append(obj);
                               ^
/home/ben/Dev/Jenjin/src/main.zig:68:39: 0x10b26f7 in main (Jenjin)
    const player = try scene.newObject();
                                      ^
/usr/lib/zig/std/start.zig:524:37: 0x10b2f0e in main (Jenjin)
            const result = root.main() catch |err| {
                                    ^```
#

Can I not have an array list of owned types?

#
const std = @import("std");
const log = std.log.scoped(.main);

const zopengl = @import("zopengl");
const zglfw = @import("zglfw");

const Shader = @import("shader.zig").Shader;
const Buffers = @import("buffers.zig").Buffers;
const Object = @import("object.zig").Object;
const Camera = @import("camera.zig").Camera;
const Scene = @import("scene.zig").Scene;

const utils = @import("utils.zig");
const gl = zopengl.bindings;

var camera = Camera.init(1024, 768);

fn resizeCallback(
    window: *zglfw.Window,
    width: i32,
    height: i32,
) callconv(.C) void {
    _ = window;
    gl.viewport(0, 0, width, height);
    camera.resize(width, height);
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    try zglfw.init();
    defer zglfw.terminate();

    const window = try utils.newWindow("Jenjin", 1024, 768);
    defer window.destroy();

    try zopengl.loadCoreProfile(zglfw.getProcAddress, 4, 6);

    var scene = try Scene.init(allocator);
    defer scene.deinit();

    const player = try scene.newObject();
    _ = player;

    _ = window.setFramebufferSizeCallback(resizeCallback);
    while (!window.shouldClose() and window.getKey(.escape) != .press) {
        zglfw.pollEvents();

        gl.clearBufferfv(gl.COLOR, 0, &[_]f32{ 0.1, 0.1, 0.1, 1.0 });
        gl.clear(gl.COLOR);

        scene.use(&buffers);

        window.swapBuffers();
    }
}

If I switch to heap allocation of Object in the Scene struct:

#
pub const Scene = struct {
    shader: Shader,
    objects: std.ArrayList(*Object),

    allocator: std.mem.Allocator,

    pub fn init(allocator: std.mem.Allocator) !Scene {
        var objects = try std.ArrayList(*Object).initCapacity(allocator, 2);
        defer objects.deinit();

        const shader = try Shader.init(@embedFile("shaders/vert.glsl"), @embedFile("shaders/frag.glsl"));

        return Scene{
            .objects = objects,
            .shader = shader,
            .allocator = allocator,
        };
    }

    pub fn newObject(self: *Scene) !*Object {
        const obj = try self.allocator.create(Object);
        obj.* = Object.init(&self.shader);
        self.objects.append(obj) catch unreachable;
        return obj;
    }

    pub fn use(self: *Scene, buffers: *Buffers) void {
        for (self.objects.items) |obj| {
            obj.use();
            buffers.draw();
        }
    }

    pub fn deinit(self: *Scene) void {
        for (self.objects.items) |obj| {
            obj.deinit();
            self.allocator.destroy(obj);
        }
    }
};
#

I get the following:

zig build run
info(utils): Creating window Jenjin (1024x768)
Segmentation fault at address 0x0
/usr/lib/zig/compiler_rt/memcpy.zig:19:21: 0x125299c in memcpy (compiler_rt)
            d[0] = s[0];
                    ^
???:?:?: 0x745eb9ecaf7e in ??? (libgallium-24.2.5-arch1.1.so)
Unwind information for `libgallium-24.2.5-arch1.1.so:0x745eb9ecaf7e` was not available, trace may be incomplete

???:?:?: 0x745eb9ec75dc in ??? (libgallium-24.2.5-arch1.1.so)
???:?:?: 0x745eb9acee9c in ??? (libgallium-24.2.5-arch1.1.so)
???:?:?: 0x745eb9ad030f in ??? (libgallium-24.2.5-arch1.1.so)
/home/ben/Dev/Jenjin/src/buffers.zig:57:24: 0x10b9354 in draw (Jenjin)
        gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, null);
                       ^
/home/ben/Dev/Jenjin/src/scene.zig:36:25: 0x10b35e0 in use (Jenjin)
            buffers.draw();
                        ^
/home/ben/Dev/Jenjin/src/main.zig:87:18: 0x10b2f3b in main (Jenjin)
        scene.use(&buffers);
                 ^
/usr/lib/zig/std/start.zig:524:37: 0x10b398e in main (Jenjin)
            const result = root.main() catch |err| {
                                    ^
???:?:?: 0x745edeb9de07 in ??? (libc.so.6)
???:?:?: 0x745edeb9decb in ??? (libc.so.6)
???:?:?: 0x10849d4 in ??? (???)```
#

Sorry for all the split messages, Discord message size limit was affecting it

#

If the repo helps at all it is at https://github.com/JenjinEngine/Jenjin however the repo does not have the Scene code pushed to it. The main.zig may show how I structured it before trying to move all the components into a scene struct

burnt merlin
#
 pub fn init(allocator: std.mem.Allocator) !Scene {
    var objects = try std.ArrayList(*Object).initCapacity(allocator, 2);
    defer objects.deinit(); // this is bad because this runs just after init() returns 

    const shader = try Shader.init(@embedFile("shaders/vert.glsl"), @embedFile("shaders/frag.glsl"));

    return Scene{
        .objects = objects,
        .shader = shader,
        .allocator = allocator,
    };
}
#

I also might consider avoiding the need for those Objects to be allocated

#

Maybe referring to them by index instead.

#

Or you use a slab allocator, a.k.a. object pool.

#

The point being, to: avoid as many 'actual' allocations / making allocation much faster / avoid 'actually' freeing things.

quiet tinsel
#

Ah, good catch! That was silly on my end... I for some reason still get this crash though at cpp /home/ben/Dev/Jenjin/src/buffers.zig:57:24: 0x10b91b1 in draw (Jenjin) gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, null); ^

All I have done so far is remove that defer objects.deinit line. Also, how would I implement handles? One final question for now, is indexing not slower than a pointer?

charred kiln
quiet tinsel
#

Oh do you mean taking a pointer to the array list and adding on an offset?

#

Nevermind, I see what you mean. Good to know!

naive glacier
#

It becomes one addition plus pointer access
I could be wrong, but I believe x86 has instructions for that, and they're not any slower

#

for:

for (self.objects.items) |obj| {
 @constCast(&obj).*.use();
}

you may want to do this instead:

for (self.objects.items) |*obj| {
    obj.use();
}

(that's regarding the code in the original question. seems like you may have changed that in the code pasted in replies)