The following code snippet leaks memory when using the GeneralPurposeAllocator
and I can’t explain why.
pub fn part2(elfGroupLines: []const u8, allocator: Allocator) !i32 {
var threeMaxStack = ArrayList(i32).init(allocator);
var groupsIter = std.mem.tokenizeSequence(u8, elfGroupLines, "\n\n");
while (groupsIter.next()) |elfLines| {
var linesIter = std.mem.tokenizeSequence(u8, elfLines, "\n");
var totalCalories: i32 = 0;
while (linesIter.next()) |line| {
totalCalories += try std.fmt.parseInt(i32, line, 10);
}
const maybeIndex = findPosition(threeMaxStack.items, totalCalories);
if (maybeIndex) |index| {
try threeMaxStack.insert(index, totalCalories);
} else if (threeMaxStack.items.len < 3) {
try threeMaxStack.append(totalCalories);
}
if (threeMaxStack.items.len == 4) {
_ = threeMaxStack.pop();
}
assert(threeMaxStack.items.len <= 3);
}
const items = try threeMaxStack.toOwnedSlice();
return items[0] + items[1] + items[2];
}
When I run the following test, the code works as expected and no memory is leaked.
test "Day 1, Part 2" {
var buffer: [32]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buffer);
const allocator = fba.allocator();
const actual = try part2(input, allocator);
try expect(actual == 212836);
}
However, when I swap out the FixedBufferAllocator
for the GeneralPurposeAllocator
, I get the following memory leak.
test "Day 1, Part 2" {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
defer {
const deinit_status = gpa.deinit();
if (deinit_status == .leak) expect(false) catch @panic("TEST FAIL");
}
const actual = try part2(input, allocator);
try expect(actual == 212836);
}
Here is the console output of the memory leak.
[gpa] (err): memory address 0x7fb24d300000 leaked:
/home/christian/.zig/lib/std/array_list.zig:457:67: 0x1083dbe in ensureTotalCapacityPrecise (test)
const new_memory = try self.allocator.alignedAlloc(T, alignment, new_capacity);
^
/home/christian/.zig/lib/std/array_list.zig:434:51: 0x104b900 in ensureTotalCapacity (test)
return self.ensureTotalCapacityPrecise(better_capacity);
^
/home/christian/.zig/lib/std/array_list.zig:483:41: 0x1045910 in addOne (test)
try self.ensureTotalCapacity(newlen);
^
/home/christian/.zig/lib/std/array_list.zig:262:49: 0x1040e5c in append (test)
const new_item_ptr = try self.addOne();
^
/home/christian/Coding/Zig/advent_of_code_2022/1_day/src/lib.zig:41:37: 0x1040a53 in part2 (test)
try threeMaxStack.append(totalCalories);
^
/home/christian/Coding/Zig/advent_of_code_2022/1_day/src/lib.zig:78:29: 0x104145a in test.Day 1, Part 2 (test)
const actual = try part2(input, allocator);
^
/home/christian/.zig/lib/compiler/test_runner.zig:95:29: 0x10522ca in mainServer (test)
test_fn.func() catch |err| switch (err) {
^
/home/christian/.zig/lib/compiler/test_runner.zig:35:26: 0x1046d0e in main (test)
return mainServer() catch @panic("internal test runner failure");
^
/home/christian/.zig/lib/std/start.zig:514:22: 0x1041bb9 in posixCallMainAndExit (test)
root.main();
^
/home/christian/.zig/lib/std/start.zig:266:5: 0x1041721 in _start (test)
asm volatile (switch (native_arch) {
Can someone break down for me why there is a memory leak?