diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2025-12-08 21:00:04 -0800 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-12-23 22:15:08 -0800 |
| commit | bee8005fe6817ade9191de0493888b14cdbcac31 (patch) | |
| tree | 6001bd45ab1118e92a77fe6ebfbf6b332d371a2b /lib/std | |
| parent | 4a53e5b0b4131c6b8e18bb551e8215e425f8ac71 (diff) | |
| download | zig-bee8005fe6817ade9191de0493888b14cdbcac31.tar.gz zig-bee8005fe6817ade9191de0493888b14cdbcac31.zip | |
std.heap.DebugAllocator: never detect TTY config
instead, allow the user to set it as a field.
this fixes a bug where leak printing and error printing would run tty
config detection for stderr, and then emit a log, which is not necessary
going to print to stderr.
however, the nice defaults are gone; the user must explicitly assign the
tty_config field during initialization or else the logging will not have
color.
related: https://github.com/ziglang/zig/issues/24510
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/Build/Fuzz.zig | 19 | ||||
| -rw-r--r-- | lib/std/Build/Step/InstallArtifact.zig | 2 | ||||
| -rw-r--r-- | lib/std/Build/Step/WriteFile.zig | 2 | ||||
| -rw-r--r-- | lib/std/Io/Dir.zig | 8 | ||||
| -rw-r--r-- | lib/std/Io/File.zig | 2 | ||||
| -rw-r--r-- | lib/std/Io/File/Atomic.zig | 2 | ||||
| -rw-r--r-- | lib/std/Io/File/Writer.zig | 9 | ||||
| -rw-r--r-- | lib/std/Io/Threaded.zig | 32 | ||||
| -rw-r--r-- | lib/std/Io/net/HostName.zig | 2 | ||||
| -rw-r--r-- | lib/std/Io/test.zig | 5 | ||||
| -rw-r--r-- | lib/std/Io/tty.zig | 9 | ||||
| -rw-r--r-- | lib/std/debug.zig | 4 | ||||
| -rw-r--r-- | lib/std/debug/Info.zig | 7 | ||||
| -rw-r--r-- | lib/std/heap/debug_allocator.zig | 39 | ||||
| -rw-r--r-- | lib/std/process/Child.zig | 2 | ||||
| -rw-r--r-- | lib/std/zig.zig | 4 |
16 files changed, 85 insertions, 63 deletions
diff --git a/lib/std/Build/Fuzz.zig b/lib/std/Build/Fuzz.zig index 8fedb7e067..8837d7d527 100644 --- a/lib/std/Build/Fuzz.zig +++ b/lib/std/Build/Fuzz.zig @@ -360,12 +360,13 @@ fn coverageRunCancelable(fuzz: *Fuzz) Io.Cancelable!void { fn prepareTables(fuzz: *Fuzz, run_step: *Step.Run, coverage_id: u64) error{ OutOfMemory, AlreadyReported, Canceled }!void { assert(fuzz.mode == .forever); const ws = fuzz.mode.forever.ws; + const gpa = fuzz.gpa; const io = fuzz.io; try fuzz.coverage_mutex.lock(io); defer fuzz.coverage_mutex.unlock(io); - const gop = try fuzz.coverage_files.getOrPut(fuzz.gpa, coverage_id); + const gop = try fuzz.coverage_files.getOrPut(gpa, coverage_id); if (gop.found_existing) { // We are fuzzing the same executable with multiple threads. // Perhaps the same unit test; perhaps a different one. In any @@ -383,12 +384,12 @@ fn prepareTables(fuzz: *Fuzz, run_step: *Step.Run, coverage_id: u64) error{ OutO .entry_points = .{}, .start_timestamp = ws.now(), }; - errdefer gop.value_ptr.coverage.deinit(fuzz.gpa); + errdefer gop.value_ptr.coverage.deinit(gpa); const rebuilt_exe_path = run_step.rebuilt_executable.?; const target = run_step.producer.?.rootModuleTarget(); var debug_info = std.debug.Info.load( - fuzz.gpa, + gpa, io, rebuilt_exe_path, &gop.value_ptr.coverage, @@ -400,7 +401,7 @@ fn prepareTables(fuzz: *Fuzz, run_step: *Step.Run, coverage_id: u64) error{ OutO }); return error.AlreadyReported; }; - defer debug_info.deinit(fuzz.gpa); + defer debug_info.deinit(gpa); const coverage_file_path: Build.Cache.Path = .{ .root_dir = run_step.step.owner.cache_root, @@ -434,14 +435,14 @@ fn prepareTables(fuzz: *Fuzz, run_step: *Step.Run, coverage_id: u64) error{ OutO const header: *const abi.SeenPcsHeader = @ptrCast(mapped_memory[0..@sizeOf(abi.SeenPcsHeader)]); const pcs = header.pcAddrs(); - const source_locations = try fuzz.gpa.alloc(Coverage.SourceLocation, pcs.len); - errdefer fuzz.gpa.free(source_locations); + const source_locations = try gpa.alloc(Coverage.SourceLocation, pcs.len); + errdefer gpa.free(source_locations); // Unfortunately the PCs array that LLVM gives us from the 8-bit PC // counters feature is not sorted. var sorted_pcs: std.MultiArrayList(struct { pc: u64, index: u32, sl: Coverage.SourceLocation }) = .{}; - defer sorted_pcs.deinit(fuzz.gpa); - try sorted_pcs.resize(fuzz.gpa, pcs.len); + defer sorted_pcs.deinit(gpa); + try sorted_pcs.resize(gpa, pcs.len); @memcpy(sorted_pcs.items(.pc), pcs); for (sorted_pcs.items(.index), 0..) |*v, i| v.* = @intCast(i); sorted_pcs.sortUnstable(struct { @@ -452,7 +453,7 @@ fn prepareTables(fuzz: *Fuzz, run_step: *Step.Run, coverage_id: u64) error{ OutO } }{ .addrs = sorted_pcs.items(.pc) }); - debug_info.resolveAddresses(fuzz.gpa, sorted_pcs.items(.pc), sorted_pcs.items(.sl)) catch |err| { + debug_info.resolveAddresses(gpa, io, sorted_pcs.items(.pc), sorted_pcs.items(.sl)) catch |err| { log.err("failed to resolve addresses to source locations: {t}", .{err}); return error.AlreadyReported; }; diff --git a/lib/std/Build/Step/InstallArtifact.zig b/lib/std/Build/Step/InstallArtifact.zig index 4c1506aa33..019d465f01 100644 --- a/lib/std/Build/Step/InstallArtifact.zig +++ b/lib/std/Build/Step/InstallArtifact.zig @@ -172,7 +172,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { defer src_dir.close(io); var it = try src_dir.walk(b.allocator); - next_entry: while (try it.next()) |entry| { + next_entry: while (try it.next(io)) |entry| { for (dir.options.exclude_extensions) |ext| { if (std.mem.endsWith(u8, entry.path, ext)) continue :next_entry; } diff --git a/lib/std/Build/Step/WriteFile.zig b/lib/std/Build/Step/WriteFile.zig index 3d712fa1d4..53222289e6 100644 --- a/lib/std/Build/Step/WriteFile.zig +++ b/lib/std/Build/Step/WriteFile.zig @@ -309,7 +309,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { var it = try already_open_dir.walk(gpa); defer it.deinit(); - while (try it.next()) |entry| { + while (try it.next(io)) |entry| { if (!dir.options.pathIncluded(entry.path)) continue; const src_entry_path = try src_dir_path.join(arena, entry.path); diff --git a/lib/std/Io/Dir.zig b/lib/std/Io/Dir.zig index d6d6aa1be2..6c40e0217e 100644 --- a/lib/std/Io/Dir.zig +++ b/lib/std/Io/Dir.zig @@ -574,7 +574,7 @@ pub fn updateFile( error.WriteFailed => return atomic_file.file_writer.err.?, }; try atomic_file.flush(); - try atomic_file.file_writer.file.updateTimes(src_stat.atime, src_stat.mtime); + try atomic_file.file_writer.file.setTimestamps(io, src_stat.atime, src_stat.mtime); try atomic_file.renameIntoPlace(); return .stale; } @@ -1238,7 +1238,7 @@ pub fn deleteTree(dir: Dir, io: Io, sub_path: []const u8) DeleteTreeError!void { process_stack: while (stack.items.len != 0) { var top = &stack.items[stack.items.len - 1]; - while (try top.iter.next()) |entry| { + while (try top.iter.next(io)) |entry| { var treat_as_dir = entry.kind == .directory; handle_entry: while (true) { if (treat_as_dir) { @@ -1695,9 +1695,9 @@ pub fn atomicFile(parent: Dir, io: Io, dest_path: []const u8, options: AtomicFil else try parent.openDir(io, dirname, .{}); - return .init(path.basename(dest_path), options.permissions, dir, true, options.write_buffer); + return .init(io, path.basename(dest_path), options.permissions, dir, true, options.write_buffer); } else { - return .init(dest_path, options.permissions, parent, false, options.write_buffer); + return .init(io, dest_path, options.permissions, parent, false, options.write_buffer); } } diff --git a/lib/std/Io/File.zig b/lib/std/Io/File.zig index 6d4dd4f323..ead129e3c5 100644 --- a/lib/std/Io/File.zig +++ b/lib/std/Io/File.zig @@ -460,7 +460,7 @@ pub fn setTimestamps( last_accessed: Io.Timestamp, last_modified: Io.Timestamp, ) SetTimestampsError!void { - return io.vtable.fileUpdateTimes(io.userdata, file, last_accessed, last_modified); + return io.vtable.fileSetTimestamps(io.userdata, file, last_accessed, last_modified); } /// Sets the accessed and modification timestamps of `file` to the current wall diff --git a/lib/std/Io/File/Atomic.zig b/lib/std/Io/File/Atomic.zig index 7d412703ed..340303ca39 100644 --- a/lib/std/Io/File/Atomic.zig +++ b/lib/std/Io/File/Atomic.zig @@ -66,7 +66,7 @@ pub fn deinit(af: *Atomic) void { af.* = undefined; } -pub const FlushError = File.WriteError; +pub const FlushError = File.Writer.Error; pub fn flush(af: *Atomic) FlushError!void { af.file_writer.interface.flush() catch |err| switch (err) { diff --git a/lib/std/Io/File/Writer.zig b/lib/std/Io/File/Writer.zig index d8c30ddbef..cc971edbf4 100644 --- a/lib/std/Io/File/Writer.zig +++ b/lib/std/Io/File/Writer.zig @@ -158,7 +158,7 @@ pub fn sendFile(io_w: *Io.Writer, file_reader: *Io.File.Reader, limit: Io.Limit) fn sendFilePositional(w: *Writer, file_reader: *Io.File.Reader, limit: Io.Limit) Io.Writer.FileError!usize { const io = w.io; const header = w.interface.buffered(); - const n = io.vtable.fileSendFilePositional(io.userdata, w.file, header, file_reader, limit, w.pos) catch |err| switch (err) { + const n = io.vtable.fileWriteFilePositional(io.userdata, w.file, header, file_reader, limit, w.pos) catch |err| switch (err) { error.Unseekable => { w.mode = w.mode.toStreaming(); const pos = w.pos; @@ -187,7 +187,7 @@ fn sendFilePositional(w: *Writer, file_reader: *Io.File.Reader, limit: Io.Limit) fn sendFileStreaming(w: *Writer, file_reader: *Io.File.Reader, limit: Io.Limit) Io.Writer.FileError!usize { const io = w.io; const header = w.interface.buffered(); - const n = io.vtable.fileSendFileStreaming(io.userdata, w.file, header, file_reader, limit) catch |err| switch (err) { + const n = io.vtable.fileWriteFileStreaming(io.userdata, w.file, header, file_reader, limit) catch |err| switch (err) { error.Canceled => { w.err = error.Canceled; return error.WriteFailed; @@ -226,7 +226,7 @@ pub fn seekToUnbuffered(w: *Writer, offset: u64) SeekError!void { } } -pub const EndError = File.SetEndPosError || Io.Writer.Error; +pub const EndError = File.SetLengthError || Io.Writer.Error; /// Flushes any buffered data and sets the end position of the file. /// @@ -236,11 +236,12 @@ pub const EndError = File.SetEndPosError || Io.Writer.Error; /// Flush failure is handled by setting `err` so that it can be handled /// along with other write failures. pub fn end(w: *Writer) EndError!void { + const io = w.io; try w.interface.flush(); switch (w.mode) { .positional, .positional_reading, - => w.file.setLength(w.pos) catch |err| switch (err) { + => w.file.setLength(io, w.pos) catch |err| switch (err) { error.NonResizable => return, else => |e| return e, }, diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index 16e8930267..945e47d5fd 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -4,8 +4,6 @@ const builtin = @import("builtin"); const native_os = builtin.os.tag; const is_windows = native_os == .windows; const is_darwin = native_os.isDarwin(); -const windows = std.os.windows; -const ws2_32 = std.os.windows.ws2_32; const is_debug = builtin.mode == .Debug; const std = @import("../std.zig"); @@ -19,6 +17,8 @@ const Allocator = std.mem.Allocator; const Alignment = std.mem.Alignment; const assert = std.debug.assert; const posix = std.posix; +const windows = std.os.windows; +const ws2_32 = std.os.windows.ws2_32; /// Thread-safe. allocator: Allocator, @@ -1452,7 +1452,7 @@ const dirMake = switch (native_os) { else => dirMakePosix, }; -fn dirMakePosix(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, mode: Dir.Mode) Dir.MakeError!void { +fn dirMakePosix(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: Dir.Permissions) Dir.MakeError!void { const t: *Threaded = @ptrCast(@alignCast(userdata)); const current_thread = Thread.getCurrent(t); @@ -1461,7 +1461,7 @@ fn dirMakePosix(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, mode: Dir try current_thread.beginSyscall(); while (true) { - switch (posix.errno(posix.system.mkdirat(dir.handle, sub_path_posix, mode))) { + switch (posix.errno(posix.system.mkdirat(dir.handle, sub_path_posix, permissions.toMode()))) { .SUCCESS => { current_thread.endSyscall(); return; @@ -1498,8 +1498,8 @@ fn dirMakePosix(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, mode: Dir } } -fn dirMakeWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, mode: Dir.Mode) Dir.MakeError!void { - if (builtin.link_libc) return dirMakePosix(userdata, dir, sub_path, mode); +fn dirMakeWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: Dir.Permissions) Dir.MakeError!void { + if (builtin.link_libc) return dirMakePosix(userdata, dir, sub_path, permissions); const t: *Threaded = @ptrCast(@alignCast(userdata)); const current_thread = Thread.getCurrent(t); try current_thread.beginSyscall(); @@ -1540,13 +1540,13 @@ fn dirMakeWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, mode: Dir. } } -fn dirMakeWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, mode: Dir.Mode) Dir.MakeError!void { +fn dirMakeWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: Dir.Permissions) Dir.MakeError!void { const t: *Threaded = @ptrCast(@alignCast(userdata)); const current_thread = Thread.getCurrent(t); try current_thread.checkCancel(); const sub_path_w = try windows.sliceToPrefixedFileW(dir.handle, sub_path); - _ = mode; + _ = permissions; // TODO use this value const sub_dir_handle = windows.OpenFile(sub_path_w.span(), .{ .dir = dir.handle, .access_mask = .{ @@ -1570,7 +1570,7 @@ fn dirMakePath( userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, - mode: Dir.Mode, + permissions: Dir.Permissions, ) Dir.MakePathError!Dir.MakePathStatus { const t: *Threaded = @ptrCast(@alignCast(userdata)); @@ -1578,7 +1578,7 @@ fn dirMakePath( var status: Dir.MakePathStatus = .existed; var component = it.last() orelse return error.BadPathName; while (true) { - if (dirMake(t, dir, component.path, mode)) |_| { + if (dirMake(t, dir, component.path, permissions)) |_| { status = .created; } else |err| switch (err) { error.PathAlreadyExists => { @@ -4945,7 +4945,7 @@ fn dirSetTimestamps( sub_path: []const u8, last_accessed: Io.Timestamp, last_modified: Io.Timestamp, - options: File.SetTimestampsOptions, + options: Dir.SetTimestampsOptions, ) File.SetTimestampsError!void { const t: *Threaded = @ptrCast(@alignCast(userdata)); const current_thread = Thread.getCurrent(t); @@ -4997,7 +4997,7 @@ fn dirSetTimestampsNow( userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, - options: File.SetTimestampsOptions, + options: Dir.SetTimestampsOptions, ) File.SetTimestampsError!void { const t: *Threaded = @ptrCast(@alignCast(userdata)); const current_thread = Thread.getCurrent(t); @@ -6271,7 +6271,7 @@ fn fileWriteStreaming( header: []const u8, data: []const []const u8, splat: usize, -) File.WriteStreamingError!usize { +) File.Writer.Error!usize { const t: *Threaded = @ptrCast(@alignCast(userdata)); const current_thread = Thread.getCurrent(t); @@ -9690,7 +9690,7 @@ fn statFromLinux(stx: *const std.os.linux.Statx) File.Stat { return .{ .inode = stx.ino, .size = stx.size, - .mode = stx.mode, + .permissions = .fromMode(stx.mode), .kind = switch (stx.mode & std.os.linux.S.IFMT) { std.os.linux.S.IFDIR => .directory, std.os.linux.S.IFCHR => .character_device, @@ -9714,7 +9714,7 @@ fn statFromPosix(st: *const posix.Stat) File.Stat { return .{ .inode = st.ino, .size = @bitCast(st.size), - .mode = st.mode, + .permissions = .fromMode(st.mode), .kind = k: { const m = st.mode & posix.S.IFMT; switch (m) { @@ -10019,7 +10019,7 @@ fn lookupHosts( options: HostName.LookupOptions, ) !void { const t_io = io(t); - const file = File.openAbsolute(t_io, "/etc/hosts", .{}) catch |err| switch (err) { + const file = Dir.openFileAbsolute(t_io, "/etc/hosts", .{}) catch |err| switch (err) { error.FileNotFound, error.NotDir, error.AccessDenied, diff --git a/lib/std/Io/net/HostName.zig b/lib/std/Io/net/HostName.zig index 628a97d1f8..84484b9dc1 100644 --- a/lib/std/Io/net/HostName.zig +++ b/lib/std/Io/net/HostName.zig @@ -343,7 +343,7 @@ pub const ResolvConf = struct { .attempts = 2, }; - const file = Io.File.openAbsolute(io, "/etc/resolv.conf", .{}) catch |err| switch (err) { + const file = Io.Dir.openFileAbsolute(io, "/etc/resolv.conf", .{}) catch |err| switch (err) { error.FileNotFound, error.NotDir, error.AccessDenied, diff --git a/lib/std/Io/test.zig b/lib/std/Io/test.zig index 02bdb591d0..891c751ef2 100644 --- a/lib/std/Io/test.zig +++ b/lib/std/Io/test.zig @@ -114,7 +114,7 @@ test "setEndPos" { try expect((try file.getPos()) == 100); } -test "updateTimes" { +test "setTimestamps" { const io = testing.io; var tmp = tmpDir(.{}); @@ -126,7 +126,8 @@ test "updateTimes" { const stat_old = try file.stat(io); // Set atime and mtime to 5s before - try file.updateTimes( + try file.setTimestamps( + io, stat_old.atime.subDuration(.fromSeconds(5)), stat_old.mtime.subDuration(.fromSeconds(5)), ); diff --git a/lib/std/Io/tty.zig b/lib/std/Io/tty.zig index d1f8b576c2..65f1b7dad5 100644 --- a/lib/std/Io/tty.zig +++ b/lib/std/Io/tty.zig @@ -2,6 +2,7 @@ const builtin = @import("builtin"); const native_os = builtin.os.tag; const std = @import("std"); +const Io = std.Io; const File = std.Io.File; const process = std.process; const windows = std.os.windows; @@ -39,7 +40,7 @@ pub const Config = union(enum) { /// This includes feature checks for ANSI escape codes and the Windows console API, as well as /// respecting the `NO_COLOR` and `CLICOLOR_FORCE` environment variables to override the default. /// Will attempt to enable ANSI escape code support if necessary/possible. - pub fn detect(file: File) Config { + pub fn detect(io: Io, file: File) Config { const force_color: ?bool = if (builtin.os.tag == .wasi) null // wasi does not support environment variables else if (process.hasNonEmptyEnvVarConstant("NO_COLOR")) @@ -51,7 +52,7 @@ pub const Config = union(enum) { if (force_color == false) return .no_color; - if (file.enableAnsiEscapeCodes()) |_| { + if (file.enableAnsiEscapeCodes(io)) |_| { return .escape_codes; } else |_| {} @@ -74,9 +75,9 @@ pub const Config = union(enum) { reset_attributes: u16, }; - pub const SetColorError = std.os.windows.SetConsoleTextAttributeError || std.Io.Writer.Error; + pub const SetColorError = std.os.windows.SetConsoleTextAttributeError || Io.Writer.Error; - pub fn setColor(conf: Config, w: *std.Io.Writer, color: Color) SetColorError!void { + pub fn setColor(conf: Config, w: *Io.Writer, color: Color) SetColorError!void { nosuspend switch (conf) { .no_color => return, .escape_codes => { diff --git a/lib/std/debug.zig b/lib/std/debug.zig index cb79bb7855..8f1cd50e8e 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -286,11 +286,13 @@ pub fn unlockStdErr() void { pub fn lockStderrWriter(buffer: []u8) struct { *Writer, tty.Config } { const global = struct { var conf: ?tty.Config = null; + var single_threaded_io: Io.Threaded = .init_single_threaded; }; + const io = global.single_threaded_io.io(); const w = std.Progress.lockStderrWriter(buffer); // The stderr lock also locks access to `global.conf`. if (global.conf == null) { - global.conf = .detect(.stderr()); + global.conf = .detect(io, .stderr()); } return .{ w, global.conf.? }; } diff --git a/lib/std/debug/Info.zig b/lib/std/debug/Info.zig index 6b31f03f72..34e79227d1 100644 --- a/lib/std/debug/Info.zig +++ b/lib/std/debug/Info.zig @@ -42,7 +42,7 @@ pub fn load( var file = try path.root_dir.handle.openFile(io, path.sub_path, .{}); defer file.close(io); - var elf_file: ElfFile = try .load(gpa, file, null, &.none); + var elf_file: ElfFile = try .load(gpa, io, file, null, &.none); errdefer elf_file.deinit(gpa); if (elf_file.dwarf == null) return error.MissingDebugInfo; @@ -58,7 +58,7 @@ pub fn load( const path_str = try path.toString(gpa); defer gpa.free(path_str); - var macho_file: MachOFile = try .load(gpa, path_str, arch); + var macho_file: MachOFile = try .load(gpa, io, path_str, arch); errdefer macho_file.deinit(gpa); return .{ @@ -85,6 +85,7 @@ pub const ResolveAddressesError = Coverage.ResolveAddressesDwarfError || error{U pub fn resolveAddresses( info: *Info, gpa: Allocator, + io: Io, /// Asserts the addresses are in ascending order. sorted_pc_addrs: []const u64, /// Asserts its length equals length of `sorted_pc_addrs`. @@ -97,7 +98,7 @@ pub fn resolveAddresses( // Resolving all of the addresses at once unfortunately isn't so easy in Mach-O binaries // due to split debug information. For now, we'll just resolve the addreses one by one. for (sorted_pc_addrs, output) |pc_addr, *src_loc| { - const dwarf, const dwarf_pc_addr = mf.getDwarfForAddress(gpa, pc_addr) catch |err| switch (err) { + const dwarf, const dwarf_pc_addr = mf.getDwarfForAddress(gpa, io, pc_addr) catch |err| switch (err) { error.InvalidMachO, error.InvalidDwarf => return error.InvalidDebugInfo, else => |e| return e, }; diff --git a/lib/std/heap/debug_allocator.zig b/lib/std/heap/debug_allocator.zig index 3183becd82..27b1b9179f 100644 --- a/lib/std/heap/debug_allocator.zig +++ b/lib/std/heap/debug_allocator.zig @@ -179,6 +179,8 @@ pub fn DebugAllocator(comptime config: Config) type { total_requested_bytes: @TypeOf(total_requested_bytes_init) = total_requested_bytes_init, requested_memory_limit: @TypeOf(requested_memory_limit_init) = requested_memory_limit_init, mutex: @TypeOf(mutex_init) = mutex_init, + /// Set this value differently to affect how errors and leaks are logged. + tty_config: std.Io.tty.Config = .no_color, const Self = @This(); @@ -458,9 +460,9 @@ pub fn DebugAllocator(comptime config: Config) type { /// Emits log messages for leaks and then returns the number of detected leaks (0 if no leaks were detected). pub fn detectLeaks(self: *Self) usize { - var leaks: usize = 0; + const tty_config = self.tty_config; - const tty_config: std.Io.tty.Config = .detect(.stderr()); + var leaks: usize = 0; for (self.buckets, 0..) |init_optional_bucket, size_class_index| { var optional_bucket = init_optional_bucket; @@ -533,10 +535,15 @@ pub fn DebugAllocator(comptime config: Config) type { @memset(addr_buf[@min(st.index, addr_buf.len)..], 0); } - fn reportDoubleFree(ret_addr: usize, alloc_stack_trace: StackTrace, free_stack_trace: StackTrace) void { + fn reportDoubleFree( + tty_config: std.Io.tty.Config, + ret_addr: usize, + alloc_stack_trace: StackTrace, + free_stack_trace: StackTrace, + ) void { + @branchHint(.cold); 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.Config = .detect(.stderr()); log.err("Double free detected. Allocation: {f} First free: {f} Second free: {f}", .{ std.debug.FormatStackTrace{ .stack_trace = alloc_stack_trace, @@ -580,7 +587,7 @@ pub fn DebugAllocator(comptime config: Config) type { if (config.retain_metadata and entry.value_ptr.freed) { if (config.safety) { - reportDoubleFree(ret_addr, entry.value_ptr.getStackTrace(.alloc), entry.value_ptr.getStackTrace(.free)); + reportDoubleFree(self.tty_config, ret_addr, entry.value_ptr.getStackTrace(.alloc), entry.value_ptr.getStackTrace(.free)); @panic("Unrecoverable double free"); } else { unreachable; @@ -588,9 +595,10 @@ pub fn DebugAllocator(comptime config: Config) type { } if (config.safety and old_mem.len != entry.value_ptr.bytes.len) { + @branchHint(.cold); 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.Config = .detect(.stderr()); + const tty_config = self.tty_config; log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ entry.value_ptr.bytes.len, old_mem.len, @@ -693,7 +701,7 @@ pub fn DebugAllocator(comptime config: Config) type { if (config.retain_metadata and entry.value_ptr.freed) { if (config.safety) { - reportDoubleFree(ret_addr, entry.value_ptr.getStackTrace(.alloc), entry.value_ptr.getStackTrace(.free)); + reportDoubleFree(self.tty_config, ret_addr, entry.value_ptr.getStackTrace(.alloc), entry.value_ptr.getStackTrace(.free)); return; } else { unreachable; @@ -701,9 +709,10 @@ pub fn DebugAllocator(comptime config: Config) type { } if (config.safety and old_mem.len != entry.value_ptr.bytes.len) { + @branchHint(.cold); 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.Config = .detect(.stderr()); + const tty_config = self.tty_config; log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ entry.value_ptr.bytes.len, old_mem.len, @@ -915,6 +924,7 @@ pub fn DebugAllocator(comptime config: Config) type { if (!is_used) { if (config.safety) { reportDoubleFree( + self.tty_config, return_address, bucketStackTrace(bucket, slot_count, slot_index, .alloc), bucketStackTrace(bucket, slot_count, slot_index, .free), @@ -935,7 +945,8 @@ 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.Config = .detect(.stderr()); + @branchHint(.cold); + const tty_config = self.tty_config; log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ requested_size, old_memory.len, @@ -950,7 +961,8 @@ pub fn DebugAllocator(comptime config: Config) type { }); } if (alignment != slot_alignment) { - const tty_config: std.Io.tty.Config = .detect(.stderr()); + @branchHint(.cold); + const tty_config = self.tty_config; log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {f} Free: {f}", .{ slot_alignment.toByteUnits(), alignment.toByteUnits(), @@ -1028,6 +1040,7 @@ pub fn DebugAllocator(comptime config: Config) type { const is_used = @as(u1, @truncate(used_byte.* >> used_bit_index)) != 0; if (!is_used) { reportDoubleFree( + self.tty_config, return_address, bucketStackTrace(bucket, slot_count, slot_index, .alloc), bucketStackTrace(bucket, slot_count, slot_index, .free), @@ -1044,7 +1057,8 @@ 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.Config = .detect(.stderr()); + @branchHint(.cold); + const tty_config = self.tty_config; log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ requested_size, memory.len, @@ -1059,7 +1073,8 @@ pub fn DebugAllocator(comptime config: Config) type { }); } if (alignment != slot_alignment) { - const tty_config: std.Io.tty.Config = .detect(.stderr()); + @branchHint(.cold); + const tty_config = self.tty_config; log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {f} Free: {f}", .{ slot_alignment.toByteUnits(), alignment.toByteUnits(), diff --git a/lib/std/process/Child.zig b/lib/std/process/Child.zig index 17139e66b8..05cc4b3944 100644 --- a/lib/std/process/Child.zig +++ b/lib/std/process/Child.zig @@ -470,7 +470,7 @@ pub fn run(allocator: Allocator, io: Io, args: struct { return .{ .stdout = try stdout.toOwnedSlice(allocator), .stderr = try stderr.toOwnedSlice(allocator), - .term = try child.wait(), + .term = try child.wait(io), }; } diff --git a/lib/std/zig.zig b/lib/std/zig.zig index c8a0dcde3b..ac6a0787de 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -60,9 +60,9 @@ pub const Color = enum { .off => .no_color, }; } - pub fn detectTtyConf(color: Color) Io.tty.Config { + pub fn detectTtyConf(color: Color, io: Io) Io.tty.Config { return switch (color) { - .auto => .detect(.stderr()), + .auto => .detect(io, .stderr()), .on => .escape_codes, .off => .no_color, }; |
