Hi there! I’ve been loving Zig but I think I’ve confused myself with memory management while trying to track down a leak. The GPA’s leak detection isn’t super helpful with the stacktrace here, but I’ve isolated it down to a section of code. I’m not 100% sure where the leak is happening, but I also feel like this probably isnt the right approach for this code, given what it’s trying to do. I was hoping you all wouldn’t mind taking a look and giving feedback on this implementation and also the memory leak.
Here’s the leak stacktrace:
.../zig/0.13.0/lib/std/array_list.zig:457:67: 0x10438d843 in ensureTotalCapacityPrecise (book)
const new_memory = try self.allocator.alignedAlloc(T, alignment, new_capacity);
^
/Users/bradcypert/.asdf/installs/zig/0.13.0/lib/std/array_list.zig:434:51: 0x10437c83b in ensureTotalCapacity (book)
return self.ensureTotalCapacityPrecise(better_capacity);
^
.../zig/0.13.0/lib/std/array_list.zig:468:44: 0x1043635b7 in ensureUnusedCapacity (book)
return self.ensureTotalCapacity(try addOrOom(self.items.len, additional_count));
^
.../zig/0.13.0/lib/std/array_list.zig:305:42: 0x104335d33 in appendSlice (book)
try self.ensureUnusedCapacity(items.len);
^
.../zig/0.13.0/lib/std/array_list.zig:358:33: 0x10438d34b in appendWrite (book)
try self.appendSlice(m);
^
.../zig/0.13.0/lib/std/io.zig:360:27: 0x10437c067 in typeErasedWriteFn (book)
return writeFn(ptr.*, bytes);
and here’s the code where I’ve isolated the leak towards!
pub const Bookmark = struct {
value: []const u8,
path: []const u8,
tags: []const []const u8,
pub fn fromLine(allocator: std.mem.Allocator, line: []u8) !Bookmark {
var splitter = std.mem.split(u8, line, ",");
var parts = std.ArrayList([]const u8).init(allocator);
defer parts.deinit();
while (splitter.next()) |part| {
try parts.append(try allocator.dupe(u8, part));
}
defer {
for (parts.items) |part| {
allocator.free(part);
}
}
const value = try allocator.dupe(u8, parts.items[0]);
const path = try allocator.dupe(u8, parts.items[1]);
var tags = try allocator.alloc([]const u8, parts.items.len - 2);
for (parts.items[2..], 0..) |tag, index| {
tags[index] = try allocator.dupe(u8, tag);
}
return Bookmark{
.value = value,
.path = path,
.tags = tags,
};
}
pub fn free(self: Bookmark, allocator: std.mem.Allocator) void {
for (self.tags) |tag| {
allocator.free(tag);
}
allocator.free(self.tags);
allocator.free(self.path);
allocator.free(self.value);
}
};
Specifically the leak is coming from the fromLine
function. I appreciate the help!