aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2025-12-08 21:00:04 -0800
committerAndrew Kelley <andrew@ziglang.org>2025-12-23 22:15:08 -0800
commitbee8005fe6817ade9191de0493888b14cdbcac31 (patch)
tree6001bd45ab1118e92a77fe6ebfbf6b332d371a2b /lib/std
parent4a53e5b0b4131c6b8e18bb551e8215e425f8ac71 (diff)
downloadzig-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.zig19
-rw-r--r--lib/std/Build/Step/InstallArtifact.zig2
-rw-r--r--lib/std/Build/Step/WriteFile.zig2
-rw-r--r--lib/std/Io/Dir.zig8
-rw-r--r--lib/std/Io/File.zig2
-rw-r--r--lib/std/Io/File/Atomic.zig2
-rw-r--r--lib/std/Io/File/Writer.zig9
-rw-r--r--lib/std/Io/Threaded.zig32
-rw-r--r--lib/std/Io/net/HostName.zig2
-rw-r--r--lib/std/Io/test.zig5
-rw-r--r--lib/std/Io/tty.zig9
-rw-r--r--lib/std/debug.zig4
-rw-r--r--lib/std/debug/Info.zig7
-rw-r--r--lib/std/heap/debug_allocator.zig39
-rw-r--r--lib/std/process/Child.zig2
-rw-r--r--lib/std/zig.zig4
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,
};