diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-01-30 10:01:40 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-01-30 10:01:40 -0500 |
| commit | 65b1a4953fd5b87f30260beb363d0e968dc8e291 (patch) | |
| tree | ab01d1b6699d103b4b075807f47c136926404f92 /lib/std/testing/leak_count_allocator.zig | |
| parent | e3a383a661aaf9b43016358e2951ff9d792f240e (diff) | |
| parent | 9c196efa2afe0e337ac0b16bd1138e89393f6106 (diff) | |
| download | zig-65b1a4953fd5b87f30260beb363d0e968dc8e291.tar.gz zig-65b1a4953fd5b87f30260beb363d0e968dc8e291.zip | |
Merge pull request #4324 from fengb/testing-allocator
Remove debug.global_allocator in favor of testing.allocator
Diffstat (limited to 'lib/std/testing/leak_count_allocator.zig')
| -rw-r--r-- | lib/std/testing/leak_count_allocator.zig | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/lib/std/testing/leak_count_allocator.zig b/lib/std/testing/leak_count_allocator.zig new file mode 100644 index 0000000000..65244e529b --- /dev/null +++ b/lib/std/testing/leak_count_allocator.zig @@ -0,0 +1,50 @@ +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); + var data = try self.internal_allocator.reallocFn(self.internal_allocator, old_mem, old_align, new_size, new_align); + if (old_mem.len == 0) { + self.count += 1; + } + return data; + } + + 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) { + if (self.count == 0) { + std.debug.panic("error - too many calls to free, most likely double free", .{}); + } + 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("error - detected leaked allocations without matching free: {}\n", .{self.count}); + return error.Leak; + } + } +}; |
