diff options
Diffstat (limited to 'lib/std/heap/debug_allocator.zig')
| -rw-r--r-- | lib/std/heap/debug_allocator.zig | 109 |
1 files changed, 90 insertions, 19 deletions
diff --git a/lib/std/heap/debug_allocator.zig b/lib/std/heap/debug_allocator.zig index 8e66f722c3..4480009781 100644 --- a/lib/std/heap/debug_allocator.zig +++ b/lib/std/heap/debug_allocator.zig @@ -80,15 +80,15 @@ //! //! Resizing and remapping are forwarded directly to the backing allocator, //! except where such operations would change the category from large to small. +const builtin = @import("builtin"); +const StackTrace = std.builtin.StackTrace; const std = @import("std"); -const builtin = @import("builtin"); const log = std.log.scoped(.gpa); const math = std.math; const assert = std.debug.assert; const mem = std.mem; const Allocator = std.mem.Allocator; -const StackTrace = std.builtin.StackTrace; const default_page_size: usize = switch (builtin.os.tag) { // Makes `std.heap.PageAllocator` take the happy path. @@ -421,7 +421,12 @@ pub fn DebugAllocator(comptime config: Config) type { return usedBitsCount(slot_count) * @sizeOf(usize); } - fn detectLeaksInBucket(bucket: *BucketHeader, size_class_index: usize, used_bits_count: usize) usize { + fn detectLeaksInBucket( + bucket: *BucketHeader, + size_class_index: usize, + used_bits_count: usize, + tty_config: std.Io.tty.Config, + ) usize { const size_class = @as(usize, 1) << @as(Log2USize, @intCast(size_class_index)); const slot_count = slot_counts[size_class_index]; var leaks: usize = 0; @@ -436,7 +441,13 @@ pub fn DebugAllocator(comptime config: Config) type { const stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc); const page_addr = @intFromPtr(bucket) & ~(page_size - 1); const addr = page_addr + slot_index * size_class; - log.err("memory address 0x{x} leaked: {f}", .{ addr, stack_trace }); + log.err("memory address 0x{x} leaked: {f}", .{ + addr, + std.debug.FormatStackTrace{ + .stack_trace = stack_trace, + .tty_config = tty_config, + }, + }); leaks += 1; } } @@ -449,12 +460,14 @@ pub fn DebugAllocator(comptime config: Config) type { pub fn detectLeaks(self: *Self) usize { var leaks: usize = 0; + const tty_config = std.Io.tty.detectConfig(.stderr()); + for (self.buckets, 0..) |init_optional_bucket, size_class_index| { var optional_bucket = init_optional_bucket; const slot_count = slot_counts[size_class_index]; const used_bits_count = usedBitsCount(slot_count); while (optional_bucket) |bucket| { - leaks += detectLeaksInBucket(bucket, size_class_index, used_bits_count); + leaks += detectLeaksInBucket(bucket, size_class_index, used_bits_count, tty_config); optional_bucket = bucket.prev; } } @@ -464,7 +477,11 @@ pub fn DebugAllocator(comptime config: Config) type { if (config.retain_metadata and large_alloc.freed) continue; const stack_trace = large_alloc.getStackTrace(.alloc); log.err("memory address 0x{x} leaked: {f}", .{ - @intFromPtr(large_alloc.bytes.ptr), stack_trace, + @intFromPtr(large_alloc.bytes.ptr), + std.debug.FormatStackTrace{ + .stack_trace = stack_trace, + .tty_config = tty_config, + }, }); leaks += 1; } @@ -519,8 +536,20 @@ pub fn DebugAllocator(comptime config: Config) type { fn reportDoubleFree(ret_addr: usize, alloc_stack_trace: StackTrace, free_stack_trace: StackTrace) void { var addr_buf: [stack_n]usize = undefined; const second_free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = ret_addr }, &addr_buf); + const tty_config = std.Io.tty.detectConfig(.stderr()); log.err("Double free detected. Allocation: {f} First free: {f} Second free: {f}", .{ - alloc_stack_trace, free_stack_trace, second_free_stack_trace, + std.debug.FormatStackTrace{ + .stack_trace = alloc_stack_trace, + .tty_config = tty_config, + }, + std.debug.FormatStackTrace{ + .stack_trace = free_stack_trace, + .tty_config = tty_config, + }, + std.debug.FormatStackTrace{ + .stack_trace = second_free_stack_trace, + .tty_config = tty_config, + }, }); } @@ -561,11 +590,18 @@ pub fn DebugAllocator(comptime config: Config) type { if (config.safety and old_mem.len != entry.value_ptr.bytes.len) { var addr_buf: [stack_n]usize = undefined; const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = ret_addr }, &addr_buf); + const tty_config = std.Io.tty.detectConfig(.stderr()); log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ entry.value_ptr.bytes.len, old_mem.len, - entry.value_ptr.getStackTrace(.alloc), - free_stack_trace, + std.debug.FormatStackTrace{ + .stack_trace = entry.value_ptr.getStackTrace(.alloc), + .tty_config = tty_config, + }, + std.debug.FormatStackTrace{ + .stack_trace = free_stack_trace, + .tty_config = tty_config, + }, }); } @@ -667,11 +703,18 @@ pub fn DebugAllocator(comptime config: Config) type { if (config.safety and old_mem.len != entry.value_ptr.bytes.len) { var addr_buf: [stack_n]usize = undefined; const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = ret_addr }, &addr_buf); + const tty_config = std.Io.tty.detectConfig(.stderr()); log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ entry.value_ptr.bytes.len, old_mem.len, - entry.value_ptr.getStackTrace(.alloc), - free_stack_trace, + std.debug.FormatStackTrace{ + .stack_trace = entry.value_ptr.getStackTrace(.alloc), + .tty_config = tty_config, + }, + std.debug.FormatStackTrace{ + .stack_trace = free_stack_trace, + .tty_config = tty_config, + }, }); } @@ -892,19 +935,33 @@ pub fn DebugAllocator(comptime config: Config) type { var addr_buf: [stack_n]usize = undefined; const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = return_address }, &addr_buf); if (old_memory.len != requested_size) { + const tty_config = std.Io.tty.detectConfig(.stderr()); log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ requested_size, old_memory.len, - bucketStackTrace(bucket, slot_count, slot_index, .alloc), - free_stack_trace, + std.debug.FormatStackTrace{ + .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc), + .tty_config = tty_config, + }, + std.debug.FormatStackTrace{ + .stack_trace = free_stack_trace, + .tty_config = tty_config, + }, }); } if (alignment != slot_alignment) { + const tty_config = std.Io.tty.detectConfig(.stderr()); log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {f} Free: {f}", .{ slot_alignment.toByteUnits(), alignment.toByteUnits(), - bucketStackTrace(bucket, slot_count, slot_index, .alloc), - free_stack_trace, + std.debug.FormatStackTrace{ + .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc), + .tty_config = tty_config, + }, + std.debug.FormatStackTrace{ + .stack_trace = free_stack_trace, + .tty_config = tty_config, + }, }); } } @@ -987,19 +1044,33 @@ pub fn DebugAllocator(comptime config: Config) type { var addr_buf: [stack_n]usize = undefined; const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = return_address }, &addr_buf); if (memory.len != requested_size) { + const tty_config = std.Io.tty.detectConfig(.stderr()); log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ requested_size, memory.len, - bucketStackTrace(bucket, slot_count, slot_index, .alloc), - free_stack_trace, + std.debug.FormatStackTrace{ + .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc), + .tty_config = tty_config, + }, + std.debug.FormatStackTrace{ + .stack_trace = free_stack_trace, + .tty_config = tty_config, + }, }); } if (alignment != slot_alignment) { + const tty_config = std.Io.tty.detectConfig(.stderr()); log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {f} Free: {f}", .{ slot_alignment.toByteUnits(), alignment.toByteUnits(), - bucketStackTrace(bucket, slot_count, slot_index, .alloc), - free_stack_trace, + std.debug.FormatStackTrace{ + .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc), + .tty_config = tty_config, + }, + std.debug.FormatStackTrace{ + .stack_trace = free_stack_trace, + .tty_config = tty_config, + }, }); } } |
