Commit 0c137934cb

Benjamin Feng <benjamin.feng@glassdoor.com>
2020-01-30 00:26:10
Move FailingAllocator to testing
1 parent ffd30db
lib/std/debug/failing_allocator.zig → lib/std/testing/failing_allocator.zig
File renamed without changes
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;
+        }
+    }
+};
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;
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;
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);
 }
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 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,
-        };
-    }
+pub const FailingAllocator = @import("testing/failing_allocator.zig").FailingAllocator;
+pub const failing_allocator = &FailingAllocator.init(allocator, 0).allocator;
 
-    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 LeakCountAllocator = @import("testing/leak_count_allocator.zig").LeakCountAllocator;
+pub var leak_count_allocator_instance = LeakCountAllocator.init(allocator);
+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.