Commit 0c137934cb
Changed files (6)
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.