mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 12:59:04 +00:00
Move FailingAllocator to testing
This commit is contained in:
parent
ffd30dbe28
commit
0c137934cb
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
46
lib/std/testing/leak_count_allocator.zig
Normal file
46
lib/std/testing/leak_count_allocator.zig
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user