authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-03 20:25:04-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-03 20:34:51-07:00
log404dc9692e33099cc59925d5cf03805224fcb36e
tree0701332eab1d990a655ae9a6dcb3975d0b2c1737
parent5c92e24a29ca403cc66515044a25d341a724f093

stage2: fix Cache debug deadlock code memory leak


3 files changed, 30 insertions(+), 19 deletions(-)

src/Cache.zig+24-18
...@@ -16,8 +16,8 @@ const Allocator = std.mem.Allocator;...@@ -16,8 +16,8 @@ const Allocator = std.mem.Allocator;
16/// This protection is conditionally compiled depending on `want_debug_deadlock`.16/// This protection is conditionally compiled depending on `want_debug_deadlock`.
17var all_cache_digest_set: std.AutoHashMapUnmanaged(BinDigest, void) = .{};17var all_cache_digest_set: std.AutoHashMapUnmanaged(BinDigest, void) = .{};
18var all_cache_digest_lock: std.Mutex = .{};18var all_cache_digest_lock: std.Mutex = .{};
19// TODO: Figure out how to make sure that `all_cache_digest_set` does not leak memory!19var all_cache_digest_allocator: ?*Allocator = null;
20pub const want_debug_deadlock = false;20const want_debug_deadlock = std.debug.runtime_safety;
21const DebugBinDigest = if (want_debug_deadlock) BinDigest else void;21const DebugBinDigest = if (want_debug_deadlock) BinDigest else void;
22const null_debug_bin_digest = if (want_debug_deadlock) ([1]u8{0} ** bin_digest_len) else {};22const null_debug_bin_digest = if (want_debug_deadlock) ([1]u8{0} ** bin_digest_len) else {};
2323
...@@ -273,6 +273,14 @@ pub const Manifest = struct {...@@ -273,6 +273,14 @@ pub const Manifest = struct {
273 const held = all_cache_digest_lock.acquire();273 const held = all_cache_digest_lock.acquire();
274 defer held.release();274 defer held.release();
275275
276 if (all_cache_digest_allocator) |prev_gpa| {
277 if (prev_gpa != self.cache.gpa) {
278 @panic("The deadlock debug code in Cache depends on using the same allocator for everything");
279 }
280 } else {
281 all_cache_digest_allocator = self.cache.gpa;
282 }
283
276 const gop = try all_cache_digest_set.getOrPut(self.cache.gpa, bin_digest);284 const gop = try all_cache_digest_set.getOrPut(self.cache.gpa, bin_digest);
277 if (gop.found_existing) {285 if (gop.found_existing) {
278 std.debug.print("Cache deadlock detected in Cache.hit. Manifest has {d} files:\n", .{self.files.items.len});286 std.debug.print("Cache deadlock detected in Cache.hit. Manifest has {d} files:\n", .{self.files.items.len});
...@@ -717,15 +725,22 @@ fn isProblematicTimestamp(fs_clock: i128) bool {...@@ -717,15 +725,22 @@ fn isProblematicTimestamp(fs_clock: i128) bool {
717 return wall_nsec == fs_nsec and wall_sec == fs_sec;725 return wall_nsec == fs_nsec and wall_sec == fs_sec;
718}726}
719727
728pub fn deinitDebugMap() void {
729 if (!want_debug_deadlock) return;
730
731 if (all_cache_digest_set.count() != 0) {
732 @panic("there's a Cache not deinitialized somewhere");
733 }
734 const gpa = all_cache_digest_allocator orelse return;
735 all_cache_digest_set.clearAndFree(gpa);
736}
737
720test "cache file and then recall it" {738test "cache file and then recall it" {
721 if (std.Target.current.os.tag == .wasi) {739 if (std.Target.current.os.tag == .wasi) {
722 // https://github.com/ziglang/zig/issues/5437740 // https://github.com/ziglang/zig/issues/5437
723 return error.SkipZigTest;741 return error.SkipZigTest;
724 }742 }
725 defer if (want_debug_deadlock) {743 defer deinitDebugMap();
726 testing.expect(all_cache_digest_set.count() == 0);
727 all_cache_digest_set.clearAndFree(testing.allocator);
728 };
729744
730 const cwd = fs.cwd();745 const cwd = fs.cwd();
731746
...@@ -804,10 +819,7 @@ test "check that changing a file makes cache fail" {...@@ -804,10 +819,7 @@ test "check that changing a file makes cache fail" {
804 // https://github.com/ziglang/zig/issues/5437819 // https://github.com/ziglang/zig/issues/5437
805 return error.SkipZigTest;820 return error.SkipZigTest;
806 }821 }
807 defer if (want_debug_deadlock) {822 defer deinitDebugMap();
808 testing.expect(all_cache_digest_set.count() == 0);
809 all_cache_digest_set.clearAndFree(testing.allocator);
810 };
811 const cwd = fs.cwd();823 const cwd = fs.cwd();
812824
813 const temp_file = "cache_hash_change_file_test.txt";825 const temp_file = "cache_hash_change_file_test.txt";
...@@ -884,10 +896,7 @@ test "no file inputs" {...@@ -884,10 +896,7 @@ test "no file inputs" {
884 // https://github.com/ziglang/zig/issues/5437896 // https://github.com/ziglang/zig/issues/5437
885 return error.SkipZigTest;897 return error.SkipZigTest;
886 }898 }
887 defer if (want_debug_deadlock) {899 defer deinitDebugMap();
888 testing.expect(all_cache_digest_set.count() == 0);
889 all_cache_digest_set.clearAndFree(testing.allocator);
890 };
891 const cwd = fs.cwd();900 const cwd = fs.cwd();
892 const temp_manifest_dir = "no_file_inputs_manifest_dir";901 const temp_manifest_dir = "no_file_inputs_manifest_dir";
893 defer cwd.deleteTree(temp_manifest_dir) catch {};902 defer cwd.deleteTree(temp_manifest_dir) catch {};
...@@ -933,10 +942,7 @@ test "Manifest with files added after initial hash work" {...@@ -933,10 +942,7 @@ test "Manifest with files added after initial hash work" {
933 // https://github.com/ziglang/zig/issues/5437942 // https://github.com/ziglang/zig/issues/5437
934 return error.SkipZigTest;943 return error.SkipZigTest;
935 }944 }
936 defer if (want_debug_deadlock) {945 defer deinitDebugMap();
937 testing.expect(all_cache_digest_set.count() == 0);
938 all_cache_digest_set.clearAndFree(testing.allocator);
939 };
940 const cwd = fs.cwd();946 const cwd = fs.cwd();
941947
942 const temp_file1 = "cache_hash_post_file_test1.txt";948 const temp_file1 = "cache_hash_post_file_test1.txt";
src/main.zig+5-1
...@@ -104,7 +104,10 @@ pub fn log(...@@ -104,7 +104,10 @@ pub fn log(
104var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};104var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
105105
106pub fn main() anyerror!void {106pub fn main() anyerror!void {
107 const gpa = if (std.builtin.link_libc) std.heap.raw_c_allocator else &general_purpose_allocator.allocator;107 const gpa = if (std.builtin.link_libc)
108 std.heap.raw_c_allocator
109 else
110 &general_purpose_allocator.allocator;
108 defer if (!std.builtin.link_libc) {111 defer if (!std.builtin.link_libc) {
109 _ = general_purpose_allocator.deinit();112 _ = general_purpose_allocator.deinit();
110 };113 };
...@@ -3289,6 +3292,7 @@ fn detectNativeTargetInfo(gpa: *Allocator, cross_target: std.zig.CrossTarget) !s...@@ -3289,6 +3292,7 @@ fn detectNativeTargetInfo(gpa: *Allocator, cross_target: std.zig.CrossTarget) !s
3289/// calls exit(0), and does not return.3292/// calls exit(0), and does not return.
3290pub fn cleanExit() void {3293pub fn cleanExit() void {
3291 if (std.builtin.mode == .Debug) {3294 if (std.builtin.mode == .Debug) {
3295 Cache.deinitDebugMap();
3292 return;3296 return;
3293 } else {3297 } else {
3294 process.exit(0);3298 process.exit(0);
src/test.zig+1
...@@ -518,6 +518,7 @@ pub const TestContext = struct {...@@ -518,6 +518,7 @@ pub const TestContext = struct {
518 case.updates.deinit();518 case.updates.deinit();
519 }519 }
520 self.cases.deinit();520 self.cases.deinit();
521 @import("Cache.zig").deinitDebugMap();
521 self.* = undefined;522 self.* = undefined;
522 }523 }
523524