aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-10-28 17:23:02 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-10-28 17:23:02 -0700
commit1c93cf52d8b8acab469efe5d4457ed43d76bc6e5 (patch)
tree7f85f232fe39aeb3ab43d13dd29ecd70f9921d55
parentc59ee3157f5a7fb5c6110422ea8215601285ea28 (diff)
downloadzig-1c93cf52d8b8acab469efe5d4457ed43d76bc6e5.tar.gz
zig-1c93cf52d8b8acab469efe5d4457ed43d76bc6e5.zip
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.
-rw-r--r--src/link/C.zig13
-rw-r--r--test/behavior.zig1
-rw-r--r--test/behavior/if.zig15
-rw-r--r--test/behavior/if_llvm.zig18
4 files changed, 22 insertions, 25 deletions
diff --git a/src/link/C.zig b/src/link/C.zig
index 86019b1cb7..5237d23a48 100644
--- a/src/link/C.zig
+++ b/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,
});
diff --git a/test/behavior.zig b/test/behavior.zig
index 30b76b00bf..4e18eb5d3f 100644
--- a/test/behavior.zig
+++ b/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");
diff --git a/test/behavior/if.zig b/test/behavior/if.zig
index a1f722d827..e907f288de 100644
--- a/test/behavior/if.zig
+++ b/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();
+}
diff --git a/test/behavior/if_llvm.zig b/test/behavior/if_llvm.zig
deleted file mode 100644
index e6773d90c0..0000000000
--- a/test/behavior/if_llvm.zig
+++ /dev/null
@@ -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();
-}