#[gpa] (err): Allocation size 4096 bytes does not match free size 2509.

1 messages · Page 1 of 1 (latest)

dense bison
#

Hey there, I am back once again.

I am frustrated that I am reaching my debugging limits once again, but I have absolutely no clue why this error occurs.

For context, I am working on a library called zig-csv (https://distreat.github.io/zig-csv/#root;Table), which I am currently using to finish another project. The issue I am facing is that when running a certain snippet of code over and over then I am faced with the issue below.

I abstracted the code and managed to replicated the issue, which should mean this it is a problem within the library.

const std = @import("std");
const csv = @import("zig-csv");
const allocator = std.testing.allocator;

test "a" {
    var table = csv.Table.init(allocator, csv.Settings.default());
    defer table.deinit();

    const col_index = try table.insertEmptyColumn("col1");

    var i: usize = 0;
    while (i <= 4) : (i += 1) {  // works fine on less iterations, but at a certain threshold the error will occur
        const row_index = try table.insertEmptyRow();
        try table.replaceValue(row_index, col_index, "a" ** 500);
    }

    const exported = try table.exportCSV(allocator);
    defer allocator.free(exported);
}

I'll post the traceback below, because of the character limit.

I appreciate everyones help and am just thankful for the help provided here.

#
Test [1/1] test.a... [gpa] (err): Allocation size 4096 bytes does not match free size 2509. Allocation:
/usr/lib/zig/std/array_list.zig:361:89: 0x253ef5 in ensureTotalCapacityPrecise (test)
                const new_memory = try self.allocator.reallocAtLeast(self.allocatedSlice(), new_capacity);
                                                                                        ^
/usr/lib/zig/std/array_list.zig:346:55: 0x22eace in ensureTotalCapacity (test)
                return self.ensureTotalCapacityPrecise(better_capacity);
                                                      ^
/usr/lib/zig/std/array_list.zig:372:60: 0x2222ac in ensureUnusedCapacity (test)
            return self.ensureTotalCapacity(self.items.len + additional_count);
                                                           ^
/usr/lib/zig/std/array_list.zig:213:48: 0x21c1b9 in appendSlice (test)
            try self.ensureUnusedCapacity(items.len);
                                               ^
/tmp/test/lib/zig-csv/src/zig-csv.zig:281:36: 0x215810 in exportCSV (test)
                try csv.appendSlice(row);
                                   ^
/tmp/test/src/main.zig:17:41: 0x21456a in test.a (test)
    const exported = try table.exportCSV(allocator);
                                        ^
/usr/lib/zig/test_runner.zig:63:28: 0x21ec03 in main (test)
        } else test_fn.func();
                           ^
/usr/lib/zig/std/start.zig:604:22: 0x2163dc in posixCallMainAndExit (test)
            root.main();
#
 Free:
/tmp/test/src/main.zig:18:25: 0x2145c3 in test.a (test)
    defer allocator.free(exported);
                        ^
/usr/lib/zig/test_runner.zig:63:28: 0x21ec03 in main (test)
        } else test_fn.func();
                           ^
/usr/lib/zig/std/start.zig:604:22: 0x2163dc in posixCallMainAndExit (test)
            root.main();
                     ^
/usr/lib/zig/std/start.zig:376:5: 0x215ee1 in _start (test)
    @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    ^


All 1 tests passed.
1 errors were logged.
young blade
#

exportCSV contains the line return csv.items;

#

items on an ArrayList is sliced up to the length (number of items it actually contains), not capacity (number of items it has room for)

#

so if you pass items into the allocator's free() you have an error since the length of the items slice doesn't match the length it was allocated with (since the size allocated was 4096 i would guess that ArrayList doubles its capacity whenever it becomes full)

#

i think you should use the toOwnedSlice method on the ArrayList instead, that will reallocate to shrink the slice to only the number of items that were actually inserted. and then that slice can be passed to free() successfully

dense bison
#

I assume thus, return csv.items a bad practice? And I should use toOwnedSlice?

dense bison
#

Let me give it a try.

young blade
#

either that or return the ArrayList itself, if you want the caller to be able to grow or shrink the returned string

#

but it doesn't seem like that is necessary here

dense bison
#

Thank you so much and especially all of your engagement.

#

There are just so many small details that I am not used to and keep missing.