authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-28 17:23:02-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-28 17:23:02-07:00
log1c93cf52d8b8acab469efe5d4457ed43d76bc6e5
tree7f85f232fe39aeb3ab43d13dd29ecd70f9921d55
parentc59ee3157f5a7fb5c6110422ea8215601285ea28

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.

4 files changed, 22 insertions(+), 25 deletions(-)

src/link/C.zig+7-6
...@@ -251,8 +251,8 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {...@@ -251,8 +251,8 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
251 var f: Flush = .{};251 var f: Flush = .{};
252 defer f.deinit(gpa);252 defer f.deinit(gpa);
253253
254 // This is at least enough until we get to the function bodies without error handling.254 // Covers zig.h and err_typedef_item.
255 try f.all_buffers.ensureTotalCapacity(gpa, self.decl_table.count() + 2);255 try f.all_buffers.ensureUnusedCapacity(gpa, 2);
256256
257 f.all_buffers.appendAssumeCapacity(.{257 f.all_buffers.appendAssumeCapacity(.{
258 .iov_base = zig_h,258 .iov_base = zig_h,
...@@ -261,7 +261,8 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {...@@ -261,7 +261,8 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
261 f.file_size += zig_h.len;261 f.file_size += zig_h.len;
262262
263 const err_typedef_writer = f.err_typedef_buf.writer(gpa);263 const err_typedef_writer = f.err_typedef_buf.writer(gpa);
264 const err_typedef_item = f.all_buffers.addOneAssumeCapacity();264 const err_typedef_index = f.all_buffers.items.len;
265 f.all_buffers.items.len += 1;
265266
266 render_errors: {267 render_errors: {
267 if (module.global_error_set.size == 0) break :render_errors;268 if (module.global_error_set.size == 0) break :render_errors;
...@@ -291,7 +292,7 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {...@@ -291,7 +292,7 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
291 try flushDecl(self, &f, decl);292 try flushDecl(self, &f, decl);
292 }293 }
293294
294 err_typedef_item.* = .{295 f.all_buffers.items[err_typedef_index] = .{
295 .iov_base = f.err_typedef_buf.items.ptr,296 .iov_base = f.err_typedef_buf.items.ptr,
296 .iov_len = f.err_typedef_buf.items.len,297 .iov_len = f.err_typedef_buf.items.len,
297 };298 };
...@@ -371,7 +372,7 @@ fn flushDecl(self: *C, f: *Flush, decl: *const Module.Decl) FlushDeclError!void...@@ -371,7 +372,7 @@ fn flushDecl(self: *C, f: *Flush, decl: *const Module.Decl) FlushDeclError!void
371 }372 }
372 }373 }
373 const buf = decl_block.fwd_decl.items;374 const buf = decl_block.fwd_decl.items;
374 f.all_buffers.appendAssumeCapacity(.{375 try f.all_buffers.append(gpa, .{
375 .iov_base = buf.ptr,376 .iov_base = buf.ptr,
376 .iov_len = buf.len,377 .iov_len = buf.len,
377 });378 });
...@@ -381,7 +382,7 @@ fn flushDecl(self: *C, f: *Flush, decl: *const Module.Decl) FlushDeclError!void...@@ -381,7 +382,7 @@ fn flushDecl(self: *C, f: *Flush, decl: *const Module.Decl) FlushDeclError!void
381 f.fn_count += 1;382 f.fn_count += 1;
382 } else if (decl_block.code.items.len != 0) {383 } else if (decl_block.code.items.len != 0) {
383 const buf = decl_block.code.items;384 const buf = decl_block.code.items;
384 f.all_buffers.appendAssumeCapacity(.{385 try f.all_buffers.append(gpa, .{
385 .iov_base = buf.ptr,386 .iov_base = buf.ptr,
386 .iov_len = buf.len,387 .iov_len = buf.len,
387 });388 });
test/behavior.zig-1
...@@ -43,7 +43,6 @@ test {...@@ -43,7 +43,6 @@ test {
43 _ = @import("behavior/generics.zig");43 _ = @import("behavior/generics.zig");
44 _ = @import("behavior/hasdecl.zig");44 _ = @import("behavior/hasdecl.zig");
45 _ = @import("behavior/hasfield.zig");45 _ = @import("behavior/hasfield.zig");
46 _ = @import("behavior/if_llvm.zig");
47 _ = @import("behavior/math.zig");46 _ = @import("behavior/math.zig");
48 _ = @import("behavior/maximum_minimum.zig");47 _ = @import("behavior/maximum_minimum.zig");
49 _ = @import("behavior/member_func.zig");48 _ = @import("behavior/member_func.zig");
test/behavior/if.zig+15
...@@ -73,3 +73,18 @@ test "const result loc, runtime if cond, else unreachable" {...@@ -73,3 +73,18 @@ test "const result loc, runtime if cond, else unreachable" {
73 const x = if (t) Num.Two else unreachable;73 const x = if (t) Num.Two else unreachable;
74 try expect(x == .Two);74 try expect(x == .Two);
75}75}
76
77test "if copies its payload" {
78 const S = struct {
79 fn doTheTest() !void {
80 var tmp: ?i32 = 10;
81 if (tmp) |value| {
82 // Modify the original variable
83 tmp = null;
84 try expect(value == 10);
85 } else unreachable;
86 }
87 };
88 try S.doTheTest();
89 comptime try S.doTheTest();
90}
test/behavior/if_llvm.zig deleted-18
...@@ -1,18 +0,0 @@
1const std = @import("std");
2const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;
4
5test "if copies its payload" {
6 const S = struct {
7 fn doTheTest() !void {
8 var tmp: ?i32 = 10;
9 if (tmp) |value| {
10 // Modify the original variable
11 tmp = null;
12 try expect(value == 10);
13 } else unreachable;
14 }
15 };
16 try S.doTheTest();
17 comptime try S.doTheTest();
18}