#Cant print items of ArrayListUnmanaged

1 messages · Page 1 of 1 (latest)

bronze fiber
#

I have a peculiar case. I want to load a json file into a zig struct that contains a list of points with two string fields:

pub const TpPoint = struct { name: []const u8, absFolderPath: []const u8 };
pub const Data = struct { points: []TpPoint };

for example the json data would be:

{
        "points": [
                {
                        "name": "point1",
                        "absFolderPath": "/"
                }
        ]
}

now I use the following code to load the data into an ArrayListUnmanaged

pub const List = struct {
    arena: heap.ArenaAllocator,
    points: std.ArrayListUnmanaged(TpPoint),

    pub fn deinit(list: *List) void {
        list.points.deinit(list.arena.child_allocator);
        list.arena.deinit();
        list.* = undefined;
    }

    pub fn print(list: *List) void {
        debug.print("{any}", .{list.points.items});
    }

    pub fn fromJson(allocator: mem.Allocator, payload: []const u8) !List {
        var arena = heap.ArenaAllocator.init(allocator);
        errdefer arena.deinit();

        var res = std.ArrayListUnmanaged(TpPoint){};
        errdefer res.deinit(allocator);
        
        var stream = std.json.TokenStream.init(payload);
        const parsedData = try std.json.parse(Data, &stream, .{
            .allocator = allocator
        });
        defer std.json.parseFree(Data, parsedData, .{ .allocator = allocator });

        for (parsedData.points) |p| {
            try res.append(allocator, p);
        }
        debug.print("{any}", .{res.items});
        return List{ .arena = arena, .points = res };
    }
};

Continued...

#

The fromJson accepts the data as bytes. Here is the function that i use to call this:

/// Loads the list of points from the filesystem
fn loadList(allocator: mem.Allocator) !List {
    const path_or_null = try folders.getPath(allocator, .home);
    if (path_or_null) |path| {
        defer allocator.free(path);
        const filePath = try fs.path.join(allocator, &[_][]const u8{ path, ".tpdata" });
        defer allocator.free(filePath); 

        const data = try readFile(allocator, filePath);
        defer allocator.free(data);
  
        return try List.fromJson(allocator, data);
    }
    return error.NoSuchList;
}

However when I try to print the contents of the Slice the program I get error: UnexpectedExit

The code for this example is here;
https://github.com/theodesp/zigtp/blob/main/src/main.zig#L151-L152

It looks like the data after. the return of the fromJson call are destroyed.

Is there anything that I'm doing wrong?

#
❯ zig build run -- list
{ teleport.TpPoint{ .name = { 112, 111, 105, 110, 116, 49 }, .absFolderPath = { 47 } } }{ teleport.TpPoint{ .name = { Segmentation fault at address 0x109086000
#

The first print is the debug print inside fromJson . The second one tries to print after it has been returned from json and crashes

vast oriole
#

i'm not 100% sure but this looks like it might be the offending line:

// loadList()
defer allocator.free(data);
#

the reason this is a problem is that List.name are pointers to sub-slices of data

#

does that make sense?

#

seems like you'll need to either return data too so that it can outlive the returned List or rearrange so that data is passed into this function and freed later on.

bronze fiber
#

yeah. I will try a simpler approach thank you

bronze fiber
#
var data = try getData(allocator);
defer std.json.parseFree(Data, data, .{ .allocator = allocator });
#

it is not always obvious which data need to be deallocated so if you are doing it excessively you can fall into traps.