From 0c137934cbd10528c2dced898b6c5485ab528e6d Mon Sep 17 00:00:00 2001 From: Benjamin Feng Date: Wed, 29 Jan 2020 17:26:10 -0600 Subject: [PATCH] Move FailingAllocator to testing --- lib/std/debug.zig | 10 +--- lib/std/io.zig | 2 +- lib/std/testing.zig | 45 ++---------------- .../{debug => testing}/failing_allocator.zig | 0 lib/std/testing/leak_count_allocator.zig | 46 +++++++++++++++++++ lib/std/zig/parser_test.zig | 4 +- 6 files changed, 56 insertions(+), 51 deletions(-) rename lib/std/{debug => testing}/failing_allocator.zig (100%) create mode 100644 lib/std/testing/leak_count_allocator.zig diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 7e1a99a395..32aba0d9b4 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -19,8 +19,8 @@ const windows = std.os.windows; pub const leb = @import("debug/leb128.zig"); -pub const FailingAllocator = @import("debug/failing_allocator.zig").FailingAllocator; -pub const failing_allocator = &FailingAllocator.init(&global_fixed_allocator.allocator, 0).allocator; +pub const global_allocator = @compileError("Please switch to std.testing.leak_count_allocator."); +pub const failing_allocator = @compileError("Please switch to std.testing.failing_allocator."); pub const runtime_safety = switch (builtin.mode) { .Debug, .ReleaseSafe => true, @@ -2192,12 +2192,6 @@ fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) } } -pub const global_allocator = blk: { - @compileError("Please switch to std.testing.leak_count_allocator."); -}; -var global_fixed_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(global_allocator_mem[0..]); -var global_allocator_mem: [100 * 1024]u8 = undefined; - /// TODO multithreaded awareness var debug_info_allocator: ?*mem.Allocator = null; var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined; diff --git a/lib/std/io.zig b/lib/std/io.zig index 93f2ae7680..a0e58c373d 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -891,7 +891,7 @@ pub fn readLineSlice(slice: []u8) ![]u8 { pub fn readLineSliceFrom(stream: var, slice: []u8) ![]u8 { // We cannot use Buffer.fromOwnedSlice, as it wants to append a null byte // after taking ownership, which would always require an allocation. - var buf = std.Buffer{ .list = std.ArrayList(u8).fromOwnedSlice(debug.failing_allocator, slice) }; + var buf = std.Buffer{ .list = std.ArrayList(u8).fromOwnedSlice(testing.failing_allocator, slice) }; try buf.resize(0); return try readLineFrom(stream, &buf); } diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 58298708c3..07479a3852 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -7,47 +7,12 @@ pub const allocator = &allocator_instance.allocator; pub var allocator_instance = std.heap.ThreadSafeFixedBufferAllocator.init(allocator_mem[0..]); var allocator_mem: [100 * 1024]u8 = undefined; -pub const leak_count_allocator = &leak_count_allocator_instance.allocator; +pub const FailingAllocator = @import("testing/failing_allocator.zig").FailingAllocator; +pub const failing_allocator = &FailingAllocator.init(allocator, 0).allocator; + +pub const LeakCountAllocator = @import("testing/leak_count_allocator.zig").LeakCountAllocator; pub var leak_count_allocator_instance = LeakCountAllocator.init(allocator); -const LeakCountAllocator = struct { - count: usize, - allocator: std.mem.Allocator, - internal_allocator: *std.mem.Allocator, - - fn init(allo: *std.mem.Allocator) LeakCountAllocator { - return .{ - .count = 0, - .allocator = .{ - .reallocFn = realloc, - .shrinkFn = shrink, - }, - .internal_allocator = allo, - }; - } - - fn realloc(allo: *std.mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 { - const self = @fieldParentPtr(LeakCountAllocator, "allocator", allo); - if (old_mem.len == 0) { - self.count += 1; - } - return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, old_align, new_size, new_align); - } - - fn shrink(allo: *std.mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { - const self = @fieldParentPtr(LeakCountAllocator, "allocator", allo); - if (new_size == 0) { - self.count -= 1; - } - return self.internal_allocator.shrinkFn(self.internal_allocator, old_mem, old_align, new_size, new_align); - } - - fn validate(self: LeakCountAllocator) !void { - if (self.count > 0) { - std.debug.warn("Detected leaked allocations without matching free: {}\n", .{self.count}); - return error.Leak; - } - } -}; +pub const leak_count_allocator = &leak_count_allocator_instance.allocator; /// This function is intended to be used only in tests. It prints diagnostics to stderr /// and then aborts when actual_error_union is not expected_error. diff --git a/lib/std/debug/failing_allocator.zig b/lib/std/testing/failing_allocator.zig similarity index 100% rename from lib/std/debug/failing_allocator.zig rename to lib/std/testing/failing_allocator.zig diff --git a/lib/std/testing/leak_count_allocator.zig b/lib/std/testing/leak_count_allocator.zig new file mode 100644 index 0000000000..84c3248178 --- /dev/null +++ b/lib/std/testing/leak_count_allocator.zig @@ -0,0 +1,46 @@ +const std = @import("../std.zig"); + +/// This allocator is used in front of another allocator and counts the numbers of allocs and frees. +/// The test runner asserts every alloc has a corresponding free at the end of each test. +/// +/// The detection algorithm is incredibly primitive and only accounts for number of calls. +/// This should be replaced by the general purpose debug allocator. +pub const LeakCountAllocator = struct { + count: usize, + allocator: std.mem.Allocator, + internal_allocator: *std.mem.Allocator, + + pub fn init(allocator: *std.mem.Allocator) LeakCountAllocator { + return .{ + .count = 0, + .allocator = .{ + .reallocFn = realloc, + .shrinkFn = shrink, + }, + .internal_allocator = allocator, + }; + } + + fn realloc(allocator: *std.mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 { + const self = @fieldParentPtr(LeakCountAllocator, "allocator", allocator); + if (old_mem.len == 0) { + self.count += 1; + } + return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, old_align, new_size, new_align); + } + + fn shrink(allocator: *std.mem.Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { + const self = @fieldParentPtr(LeakCountAllocator, "allocator", allocator); + if (new_size == 0) { + self.count -= 1; + } + return self.internal_allocator.shrinkFn(self.internal_allocator, old_mem, old_align, new_size, new_align); + } + + pub fn validate(self: LeakCountAllocator) !void { + if (self.count > 0) { + std.debug.warn("Detected leaked allocations without matching free: {}\n", .{self.count}); + return error.Leak; + } + } +}; diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index c57540ade9..1640d09992 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -2773,7 +2773,7 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void { const needed_alloc_count = x: { // Try it once with unlimited memory, make sure it works var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); - var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, maxInt(usize)); + var failing_allocator = std.testing.FailingAllocator.init(&fixed_allocator.allocator, maxInt(usize)); var anything_changed: bool = undefined; const result_source = try testParse(source, &failing_allocator.allocator, &anything_changed); if (!mem.eql(u8, result_source, expected_source)) { @@ -2797,7 +2797,7 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void { var fail_index: usize = 0; while (fail_index < needed_alloc_count) : (fail_index += 1) { var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); - var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index); + var failing_allocator = std.testing.FailingAllocator.init(&fixed_allocator.allocator, fail_index); var anything_changed: bool = undefined; if (testParse(source, &failing_allocator.allocator, &anything_changed)) |_| { return error.NondeterministicMemoryUsage;