Commit 1c93cf52d8

Andrew Kelley <andrew@ziglang.org>
2021-10-29 02:23:02
C backend: fix crash when number of Decls passes a threshold
The ensureUnusedCapacity did not reserve a big enough number. I changed it to no longer guess the capacity because I saw that the number of possible items was not determinable ahead of time and this can therefore avoid allocating more memory than necessary.
1 parent c59ee31
Changed files (4)
src
link
test
src/link/C.zig
@@ -251,8 +251,8 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
     var f: Flush = .{};
     defer f.deinit(gpa);
 
-    // This is at least enough until we get to the function bodies without error handling.
-    try f.all_buffers.ensureTotalCapacity(gpa, self.decl_table.count() + 2);
+    // Covers zig.h and err_typedef_item.
+    try f.all_buffers.ensureUnusedCapacity(gpa, 2);
 
     f.all_buffers.appendAssumeCapacity(.{
         .iov_base = zig_h,
@@ -261,7 +261,8 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
     f.file_size += zig_h.len;
 
     const err_typedef_writer = f.err_typedef_buf.writer(gpa);
-    const err_typedef_item = f.all_buffers.addOneAssumeCapacity();
+    const err_typedef_index = f.all_buffers.items.len;
+    f.all_buffers.items.len += 1;
 
     render_errors: {
         if (module.global_error_set.size == 0) break :render_errors;
@@ -291,7 +292,7 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
         try flushDecl(self, &f, decl);
     }
 
-    err_typedef_item.* = .{
+    f.all_buffers.items[err_typedef_index] = .{
         .iov_base = f.err_typedef_buf.items.ptr,
         .iov_len = f.err_typedef_buf.items.len,
     };
@@ -371,7 +372,7 @@ fn flushDecl(self: *C, f: *Flush, decl: *const Module.Decl) FlushDeclError!void
             }
         }
         const buf = decl_block.fwd_decl.items;
-        f.all_buffers.appendAssumeCapacity(.{
+        try f.all_buffers.append(gpa, .{
             .iov_base = buf.ptr,
             .iov_len = buf.len,
         });
@@ -381,7 +382,7 @@ fn flushDecl(self: *C, f: *Flush, decl: *const Module.Decl) FlushDeclError!void
         f.fn_count += 1;
     } else if (decl_block.code.items.len != 0) {
         const buf = decl_block.code.items;
-        f.all_buffers.appendAssumeCapacity(.{
+        try f.all_buffers.append(gpa, .{
             .iov_base = buf.ptr,
             .iov_len = buf.len,
         });
test/behavior/if.zig
@@ -73,3 +73,18 @@ test "const result loc, runtime if cond, else unreachable" {
     const x = if (t) Num.Two else unreachable;
     try expect(x == .Two);
 }
+
+test "if copies its payload" {
+    const S = struct {
+        fn doTheTest() !void {
+            var tmp: ?i32 = 10;
+            if (tmp) |value| {
+                // Modify the original variable
+                tmp = null;
+                try expect(value == 10);
+            } else unreachable;
+        }
+    };
+    try S.doTheTest();
+    comptime try S.doTheTest();
+}
test/behavior/if_llvm.zig
@@ -1,18 +0,0 @@
-const std = @import("std");
-const expect = std.testing.expect;
-const expectEqual = std.testing.expectEqual;
-
-test "if copies its payload" {
-    const S = struct {
-        fn doTheTest() !void {
-            var tmp: ?i32 = 10;
-            if (tmp) |value| {
-                // Modify the original variable
-                tmp = null;
-                try expect(value == 10);
-            } else unreachable;
-        }
-    };
-    try S.doTheTest();
-    comptime try S.doTheTest();
-}
test/behavior.zig
@@ -43,7 +43,6 @@ test {
         _ = @import("behavior/generics.zig");
         _ = @import("behavior/hasdecl.zig");
         _ = @import("behavior/hasfield.zig");
-        _ = @import("behavior/if_llvm.zig");
         _ = @import("behavior/math.zig");
         _ = @import("behavior/maximum_minimum.zig");
         _ = @import("behavior/member_func.zig");