Commit 9cd038d73a

Veikka Tuominen <git@vexu.eu>
2021-03-05 19:04:33
std: fix memory leak in MultiArrayList
1 parent 291edaf
Changed files (1)
lib/std/multi_array_list.zig
@@ -8,6 +8,7 @@ const assert = std.debug.assert;
 const meta = std.meta;
 const mem = std.mem;
 const Allocator = mem.Allocator;
+const testing = std.testing;
 
 pub fn MultiArrayList(comptime S: type) type {
     return struct {
@@ -247,6 +248,7 @@ pub fn MultiArrayList(comptime S: type) type {
                 .exact,
             );
             if (self.len == 0) {
+                gpa.free(self.allocatedBytes());
                 self.bytes = new_bytes.ptr;
                 self.capacity = new_capacity;
                 return;
@@ -287,7 +289,6 @@ pub fn MultiArrayList(comptime S: type) type {
 }
 
 test "basic usage" {
-    const testing = std.testing;
     const ally = testing.allocator;
 
     const Foo = struct {
@@ -369,7 +370,7 @@ test "basic usage" {
 // This was observed to fail on aarch64 with LLVM 11, when the capacityInBytes
 // function used the @reduce code path.
 test "regression test for @reduce bug" {
-    const ally = std.testing.allocator;
+    const ally = testing.allocator;
     var list = MultiArrayList(struct {
         tag: std.zig.Token.Tag,
         start: u32,
@@ -412,35 +413,70 @@ test "regression test for @reduce bug" {
     try list.append(ally, .{ .tag = .eof, .start = 123 });
 
     const tags = list.items(.tag);
-    std.testing.expectEqual(tags[1], .identifier);
-    std.testing.expectEqual(tags[2], .equal);
-    std.testing.expectEqual(tags[3], .builtin);
-    std.testing.expectEqual(tags[4], .l_paren);
-    std.testing.expectEqual(tags[5], .string_literal);
-    std.testing.expectEqual(tags[6], .r_paren);
-    std.testing.expectEqual(tags[7], .semicolon);
-    std.testing.expectEqual(tags[8], .keyword_pub);
-    std.testing.expectEqual(tags[9], .keyword_fn);
-    std.testing.expectEqual(tags[10], .identifier);
-    std.testing.expectEqual(tags[11], .l_paren);
-    std.testing.expectEqual(tags[12], .r_paren);
-    std.testing.expectEqual(tags[13], .identifier);
-    std.testing.expectEqual(tags[14], .bang);
-    std.testing.expectEqual(tags[15], .identifier);
-    std.testing.expectEqual(tags[16], .l_brace);
-    std.testing.expectEqual(tags[17], .identifier);
-    std.testing.expectEqual(tags[18], .period);
-    std.testing.expectEqual(tags[19], .identifier);
-    std.testing.expectEqual(tags[20], .period);
-    std.testing.expectEqual(tags[21], .identifier);
-    std.testing.expectEqual(tags[22], .l_paren);
-    std.testing.expectEqual(tags[23], .string_literal);
-    std.testing.expectEqual(tags[24], .comma);
-    std.testing.expectEqual(tags[25], .period);
-    std.testing.expectEqual(tags[26], .l_brace);
-    std.testing.expectEqual(tags[27], .r_brace);
-    std.testing.expectEqual(tags[28], .r_paren);
-    std.testing.expectEqual(tags[29], .semicolon);
-    std.testing.expectEqual(tags[30], .r_brace);
-    std.testing.expectEqual(tags[31], .eof);
+    testing.expectEqual(tags[1], .identifier);
+    testing.expectEqual(tags[2], .equal);
+    testing.expectEqual(tags[3], .builtin);
+    testing.expectEqual(tags[4], .l_paren);
+    testing.expectEqual(tags[5], .string_literal);
+    testing.expectEqual(tags[6], .r_paren);
+    testing.expectEqual(tags[7], .semicolon);
+    testing.expectEqual(tags[8], .keyword_pub);
+    testing.expectEqual(tags[9], .keyword_fn);
+    testing.expectEqual(tags[10], .identifier);
+    testing.expectEqual(tags[11], .l_paren);
+    testing.expectEqual(tags[12], .r_paren);
+    testing.expectEqual(tags[13], .identifier);
+    testing.expectEqual(tags[14], .bang);
+    testing.expectEqual(tags[15], .identifier);
+    testing.expectEqual(tags[16], .l_brace);
+    testing.expectEqual(tags[17], .identifier);
+    testing.expectEqual(tags[18], .period);
+    testing.expectEqual(tags[19], .identifier);
+    testing.expectEqual(tags[20], .period);
+    testing.expectEqual(tags[21], .identifier);
+    testing.expectEqual(tags[22], .l_paren);
+    testing.expectEqual(tags[23], .string_literal);
+    testing.expectEqual(tags[24], .comma);
+    testing.expectEqual(tags[25], .period);
+    testing.expectEqual(tags[26], .l_brace);
+    testing.expectEqual(tags[27], .r_brace);
+    testing.expectEqual(tags[28], .r_paren);
+    testing.expectEqual(tags[29], .semicolon);
+    testing.expectEqual(tags[30], .r_brace);
+    testing.expectEqual(tags[31], .eof);
+}
+
+test "ensure capacity on empty list" {
+    const ally = testing.allocator;
+
+    const Foo = struct {
+        a: u32,
+        b: u8,
+    };
+
+    var list = MultiArrayList(Foo){};
+    defer list.deinit(ally);
+
+    try list.ensureCapacity(ally, 2);
+    list.appendAssumeCapacity(.{ .a = 1, .b = 2 });
+    list.appendAssumeCapacity(.{ .a = 3, .b = 4 });
+
+    testing.expectEqualSlices(u32, &[_]u32{ 1, 3 }, list.items(.a));
+    testing.expectEqualSlices(u8, &[_]u8{ 2, 4 }, list.items(.b));
+
+    list.len = 0;
+    list.appendAssumeCapacity(.{ .a = 5, .b = 6 });
+    list.appendAssumeCapacity(.{ .a = 7, .b = 8 });
+
+    testing.expectEqualSlices(u32, &[_]u32{ 5, 7 }, list.items(.a));
+    testing.expectEqualSlices(u8, &[_]u8{ 6, 8 }, list.items(.b));
+
+    list.len = 0;
+    try list.ensureCapacity(ally, 16);
+
+    list.appendAssumeCapacity(.{ .a = 9, .b = 10 });
+    list.appendAssumeCapacity(.{ .a = 11, .b = 12 });
+
+    testing.expectEqualSlices(u32, &[_]u32{ 9, 11 }, list.items(.a));
+    testing.expectEqualSlices(u8, &[_]u8{ 10, 12 }, list.items(.b));
 }