authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-24 13:31:29-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-26 19:58:56-08:00
logb243e8f8cc7ee27dfa7318d1c3698d01582e84ae
treef4e80f83869b42e0a2f1624019f53c238f3a8df3
parenta72c411fdbafc206115c4f9eb19216d504c36a31

std: integrate DebugAllocator with terminal mode

by adding a new std.Option for log.terminalMode this is an alternative to the approach that was deleted in aa57793b680b3da05f1d888b4df15807905e57c8

3 files changed, 68 insertions(+), 14 deletions(-)

lib/std/heap/debug_allocator.zig+58-14
...@@ -84,7 +84,7 @@ const builtin = @import("builtin");...@@ -84,7 +84,7 @@ const builtin = @import("builtin");
84const StackTrace = std.builtin.StackTrace;84const StackTrace = std.builtin.StackTrace;
8585
86const std = @import("std");86const std = @import("std");
87const log = std.log.scoped(.gpa);87const log = std.log.scoped(.DebugAllocator);
88const math = std.math;88const math = std.math;
89const assert = std.debug.assert;89const assert = std.debug.assert;
90const mem = std.mem;90const mem = std.mem;
...@@ -441,7 +441,11 @@ pub fn DebugAllocator(comptime config: Config) type {...@@ -441,7 +441,11 @@ pub fn DebugAllocator(comptime config: Config) type {
441 const page_addr = @intFromPtr(bucket) & ~(page_size - 1);441 const page_addr = @intFromPtr(bucket) & ~(page_size - 1);
442 const addr = page_addr + slot_index * size_class;442 const addr = page_addr + slot_index * size_class;
443 log.err("memory address 0x{x} leaked: {f}", .{443 log.err("memory address 0x{x} leaked: {f}", .{
444 addr, std.debug.FormatStackTrace{ .stack_trace = stack_trace },444 addr,
445 std.debug.FormatStackTrace{
446 .stack_trace = stack_trace,
447 .terminal_mode = std.log.terminalMode(),
448 },
445 });449 });
446 leaks += 1;450 leaks += 1;
447 }451 }
...@@ -471,7 +475,10 @@ pub fn DebugAllocator(comptime config: Config) type {...@@ -471,7 +475,10 @@ pub fn DebugAllocator(comptime config: Config) type {
471 const stack_trace = large_alloc.getStackTrace(.alloc);475 const stack_trace = large_alloc.getStackTrace(.alloc);
472 log.err("memory address 0x{x} leaked: {f}", .{476 log.err("memory address 0x{x} leaked: {f}", .{
473 @intFromPtr(large_alloc.bytes.ptr),477 @intFromPtr(large_alloc.bytes.ptr),
474 std.debug.FormatStackTrace{ .stack_trace = stack_trace },478 std.debug.FormatStackTrace{
479 .stack_trace = stack_trace,
480 .terminal_mode = std.log.terminalMode(),
481 },
475 });482 });
476 leaks += 1;483 leaks += 1;
477 }484 }
...@@ -528,9 +535,18 @@ pub fn DebugAllocator(comptime config: Config) type {...@@ -528,9 +535,18 @@ pub fn DebugAllocator(comptime config: Config) type {
528 var addr_buf: [stack_n]usize = undefined;535 var addr_buf: [stack_n]usize = undefined;
529 const second_free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = ret_addr }, &addr_buf);536 const second_free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = ret_addr }, &addr_buf);
530 log.err("Double free detected. Allocation: {f} First free: {f} Second free: {f}", .{537 log.err("Double free detected. Allocation: {f} First free: {f} Second free: {f}", .{
531 std.debug.FormatStackTrace{ .stack_trace = alloc_stack_trace },538 std.debug.FormatStackTrace{
532 std.debug.FormatStackTrace{ .stack_trace = free_stack_trace },539 .stack_trace = alloc_stack_trace,
533 std.debug.FormatStackTrace{ .stack_trace = second_free_stack_trace },540 .terminal_mode = std.log.terminalMode(),
541 },
542 std.debug.FormatStackTrace{
543 .stack_trace = free_stack_trace,
544 .terminal_mode = std.log.terminalMode(),
545 },
546 std.debug.FormatStackTrace{
547 .stack_trace = second_free_stack_trace,
548 .terminal_mode = std.log.terminalMode(),
549 },
534 });550 });
535 }551 }
536552
...@@ -575,8 +591,14 @@ pub fn DebugAllocator(comptime config: Config) type {...@@ -575,8 +591,14 @@ pub fn DebugAllocator(comptime config: Config) type {
575 log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{591 log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{
576 entry.value_ptr.bytes.len,592 entry.value_ptr.bytes.len,
577 old_mem.len,593 old_mem.len,
578 std.debug.FormatStackTrace{ .stack_trace = entry.value_ptr.getStackTrace(.alloc) },594 std.debug.FormatStackTrace{
579 std.debug.FormatStackTrace{ .stack_trace = free_stack_trace },595 .stack_trace = entry.value_ptr.getStackTrace(.alloc),
596 .terminal_mode = std.log.terminalMode(),
597 },
598 std.debug.FormatStackTrace{
599 .stack_trace = free_stack_trace,
600 .terminal_mode = std.log.terminalMode(),
601 },
580 });602 });
581 }603 }
582604
...@@ -682,8 +704,14 @@ pub fn DebugAllocator(comptime config: Config) type {...@@ -682,8 +704,14 @@ pub fn DebugAllocator(comptime config: Config) type {
682 log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{704 log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{
683 entry.value_ptr.bytes.len,705 entry.value_ptr.bytes.len,
684 old_mem.len,706 old_mem.len,
685 std.debug.FormatStackTrace{ .stack_trace = entry.value_ptr.getStackTrace(.alloc) },707 std.debug.FormatStackTrace{
686 std.debug.FormatStackTrace{ .stack_trace = free_stack_trace },708 .stack_trace = entry.value_ptr.getStackTrace(.alloc),
709 .terminal_mode = std.log.terminalMode(),
710 },
711 std.debug.FormatStackTrace{
712 .stack_trace = free_stack_trace,
713 .terminal_mode = std.log.terminalMode(),
714 },
687 });715 });
688 }716 }
689717
...@@ -910,8 +938,12 @@ pub fn DebugAllocator(comptime config: Config) type {...@@ -910,8 +938,12 @@ pub fn DebugAllocator(comptime config: Config) type {
910 old_memory.len,938 old_memory.len,
911 std.debug.FormatStackTrace{939 std.debug.FormatStackTrace{
912 .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc),940 .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc),
941 .terminal_mode = std.log.terminalMode(),
942 },
943 std.debug.FormatStackTrace{
944 .stack_trace = free_stack_trace,
945 .terminal_mode = std.log.terminalMode(),
913 },946 },
914 std.debug.FormatStackTrace{ .stack_trace = free_stack_trace },
915 });947 });
916 }948 }
917 if (alignment != slot_alignment) {949 if (alignment != slot_alignment) {
...@@ -921,8 +953,12 @@ pub fn DebugAllocator(comptime config: Config) type {...@@ -921,8 +953,12 @@ pub fn DebugAllocator(comptime config: Config) type {
921 alignment.toByteUnits(),953 alignment.toByteUnits(),
922 std.debug.FormatStackTrace{954 std.debug.FormatStackTrace{
923 .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc),955 .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc),
956 .terminal_mode = std.log.terminalMode(),
957 },
958 std.debug.FormatStackTrace{
959 .stack_trace = free_stack_trace,
960 .terminal_mode = std.log.terminalMode(),
924 },961 },
925 std.debug.FormatStackTrace{ .stack_trace = free_stack_trace },
926 });962 });
927 }963 }
928 }964 }
...@@ -1011,8 +1047,12 @@ pub fn DebugAllocator(comptime config: Config) type {...@@ -1011,8 +1047,12 @@ pub fn DebugAllocator(comptime config: Config) type {
1011 memory.len,1047 memory.len,
1012 std.debug.FormatStackTrace{1048 std.debug.FormatStackTrace{
1013 .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc),1049 .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc),
1050 .terminal_mode = std.log.terminalMode(),
1051 },
1052 std.debug.FormatStackTrace{
1053 .stack_trace = free_stack_trace,
1054 .terminal_mode = std.log.terminalMode(),
1014 },1055 },
1015 std.debug.FormatStackTrace{ .stack_trace = free_stack_trace },
1016 });1056 });
1017 }1057 }
1018 if (alignment != slot_alignment) {1058 if (alignment != slot_alignment) {
...@@ -1022,8 +1062,12 @@ pub fn DebugAllocator(comptime config: Config) type {...@@ -1022,8 +1062,12 @@ pub fn DebugAllocator(comptime config: Config) type {
1022 alignment.toByteUnits(),1062 alignment.toByteUnits(),
1023 std.debug.FormatStackTrace{1063 std.debug.FormatStackTrace{
1024 .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc),1064 .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc),
1065 .terminal_mode = std.log.terminalMode(),
1066 },
1067 std.debug.FormatStackTrace{
1068 .stack_trace = free_stack_trace,
1069 .terminal_mode = std.log.terminalMode(),
1025 },1070 },
1026 std.debug.FormatStackTrace{ .stack_trace = free_stack_trace },
1027 });1071 });
1028 }1072 }
1029 }1073 }
lib/std/log.zig+8
...@@ -80,6 +80,14 @@ pub fn logEnabled(comptime level: Level, comptime scope: @EnumLiteral()) bool {...@@ -80,6 +80,14 @@ pub fn logEnabled(comptime level: Level, comptime scope: @EnumLiteral()) bool {
80 return @intFromEnum(level) <= @intFromEnum(std.options.log_level);80 return @intFromEnum(level) <= @intFromEnum(std.options.log_level);
81}81}
8282
83pub const terminalMode = std.options.logTerminalMode;
84
85pub fn defaultTerminalMode() std.Io.Terminal.Mode {
86 const stderr = std.debug.lockStderr(&.{}).terminal();
87 std.debug.unlockStderr();
88 return stderr.mode;
89}
90
83/// The default implementation for the log function. Custom log functions may91/// The default implementation for the log function. Custom log functions may
84/// forward log messages to this function.92/// forward log messages to this function.
85///93///
lib/std/std.zig+2
...@@ -129,6 +129,8 @@ pub const Options = struct {...@@ -129,6 +129,8 @@ pub const Options = struct {
129 args: anytype,129 args: anytype,
130 ) void = log.defaultLog,130 ) void = log.defaultLog,
131131
132 logTerminalMode: fn () Io.Terminal.Mode = log.defaultTerminalMode,
133
132 /// Overrides `std.heap.page_size_min`.134 /// Overrides `std.heap.page_size_min`.
133 page_size_min: ?usize = null,135 page_size_min: ?usize = null,
134 /// Overrides `std.heap.page_size_max`.136 /// Overrides `std.heap.page_size_max`.