mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
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
This commit is contained in:
@@ -435,7 +435,7 @@ pub fn main() !void {
|
||||
if (builtin.single_threaded) fatal("'--webui' is not yet supported on single-threaded hosts", .{});
|
||||
}
|
||||
|
||||
const ttyconf = color.detectTtyConf();
|
||||
const ttyconf = color.detectTtyConf(io);
|
||||
|
||||
const main_progress_node = std.Progress.start(.{
|
||||
.disable_printing = (color == .off),
|
||||
|
||||
+10
-9
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
+4
-4
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
+16
-16
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
+3
-2
@@ -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)),
|
||||
);
|
||||
|
||||
+5
-4
@@ -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 => {
|
||||
|
||||
+3
-1
@@ -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.? };
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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,
|
||||
};
|
||||
|
||||
+3
-3
@@ -51,10 +51,10 @@ pub const UpdateError = error{
|
||||
} ||
|
||||
codegen.GenerateSymbolError ||
|
||||
Io.File.OpenError ||
|
||||
Io.File.SetEndPosError ||
|
||||
Io.File.LengthError ||
|
||||
Io.File.CopyRangeError ||
|
||||
Io.File.PReadError ||
|
||||
Io.File.PWriteError;
|
||||
Io.File.ReadPositionalError ||
|
||||
Io.File.WritePositionalError;
|
||||
|
||||
pub const FlushError = UpdateError;
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ writers: std.SinglyLinkedList,
|
||||
|
||||
pub const growth_factor = 4;
|
||||
|
||||
pub const Error = std.posix.MMapError || std.posix.MRemapError || Io.File.SetEndPosError || error{
|
||||
pub const Error = std.posix.MMapError || std.posix.MRemapError || Io.File.LengthError || error{
|
||||
NotFile,
|
||||
SystemResources,
|
||||
IsDir,
|
||||
|
||||
+14
-9
@@ -162,17 +162,20 @@ var debug_allocator: std.heap.DebugAllocator(.{
|
||||
.stack_trace_frames = build_options.mem_leak_frames,
|
||||
}) = .init;
|
||||
|
||||
const use_debug_allocator = build_options.debug_gpa or
|
||||
(native_os != .wasi and !builtin.link_libc and switch (builtin.mode) {
|
||||
.Debug, .ReleaseSafe => true,
|
||||
.ReleaseFast, .ReleaseSmall => false,
|
||||
});
|
||||
|
||||
pub fn main() anyerror!void {
|
||||
const gpa, const is_debug = gpa: {
|
||||
if (build_options.debug_gpa) break :gpa .{ debug_allocator.allocator(), true };
|
||||
if (native_os == .wasi) break :gpa .{ std.heap.wasm_allocator, false };
|
||||
if (builtin.link_libc) break :gpa .{ std.heap.c_allocator, false };
|
||||
break :gpa switch (builtin.mode) {
|
||||
.Debug, .ReleaseSafe => .{ debug_allocator.allocator(), true },
|
||||
.ReleaseFast, .ReleaseSmall => .{ std.heap.smp_allocator, false },
|
||||
};
|
||||
const gpa = gpa: {
|
||||
if (use_debug_allocator) break :gpa debug_allocator.allocator();
|
||||
if (native_os == .wasi) break :gpa std.heap.wasm_allocator;
|
||||
if (builtin.link_libc) break :gpa std.heap.c_allocator;
|
||||
break :gpa std.heap.smp_allocator;
|
||||
};
|
||||
defer if (is_debug) {
|
||||
defer if (use_debug_allocator) {
|
||||
_ = debug_allocator.deinit();
|
||||
};
|
||||
var arena_instance = std.heap.ArenaAllocator.init(gpa);
|
||||
@@ -244,6 +247,8 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
||||
threaded.stack_size = thread_stack_size;
|
||||
const io = threaded.io();
|
||||
|
||||
debug_allocator.tty_config = .detect(io, .stderr());
|
||||
|
||||
const cmd = args[1];
|
||||
const cmd_args = args[2..];
|
||||
if (mem.eql(u8, cmd, "build-exe")) {
|
||||
|
||||
+2
-1
@@ -868,9 +868,10 @@ fn testLayout(b: *Build, opts: Options) *Step {
|
||||
}
|
||||
|
||||
fn testLinkDirectlyCppTbd(b: *Build, opts: Options) *Step {
|
||||
const io = b.graph.io;
|
||||
const test_step = addTestStep(b, "link-directly-cpp-tbd", opts);
|
||||
|
||||
const sdk = std.zig.system.darwin.getSdk(b.allocator, &opts.target.result) orelse
|
||||
const sdk = std.zig.system.darwin.getSdk(b.allocator, io, &opts.target.result) orelse
|
||||
@panic("macOS SDK is required to run the test");
|
||||
|
||||
const exe = addExecutable(b, opts, .{
|
||||
|
||||
+3
-2
@@ -339,7 +339,7 @@ fn addFromDirInner(
|
||||
var it = try iterable_dir.walk(ctx.arena);
|
||||
var filenames: ArrayList([]const u8) = .empty;
|
||||
|
||||
while (try it.next()) |entry| {
|
||||
while (try it.next(io)) |entry| {
|
||||
if (entry.kind != .file) continue;
|
||||
|
||||
// Ignore stuff such as .swp files
|
||||
@@ -431,9 +431,10 @@ fn addFromDirInner(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(gpa: Allocator, arena: Allocator) Cases {
|
||||
pub fn init(gpa: Allocator, arena: Allocator, io: Io) Cases {
|
||||
return .{
|
||||
.gpa = gpa,
|
||||
.io = io,
|
||||
.cases = .init(gpa),
|
||||
.arena = arena,
|
||||
};
|
||||
|
||||
@@ -23,7 +23,9 @@ pub fn build(b: *std.Build) void {
|
||||
}),
|
||||
});
|
||||
|
||||
if (std.zig.system.darwin.getSdk(b.allocator, &target.result)) |sdk| {
|
||||
const io = b.graph.io;
|
||||
|
||||
if (std.zig.system.darwin.getSdk(b.allocator, io, &target.result)) |sdk| {
|
||||
b.sysroot = sdk;
|
||||
exe.root_module.addSystemIncludePath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/usr/include" }) });
|
||||
exe.root_module.addSystemFrameworkPath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/System/Library/Frameworks" }) });
|
||||
|
||||
@@ -9,10 +9,6 @@ pub fn build(b: *std.Build) void {
|
||||
const optimize: std.builtin.OptimizeMode = .Debug;
|
||||
const target = b.graph.host;
|
||||
|
||||
// The test requires getFdPath in order to to get the path of the
|
||||
// File returned by openSelfExe
|
||||
if (!std.os.isGetFdPathSupportedOnTarget(target.result.os)) return;
|
||||
|
||||
const main = b.addExecutable(.{
|
||||
.name = "main",
|
||||
.root_module = b.createModule(.{
|
||||
|
||||
+1
-1
@@ -2632,7 +2632,7 @@ pub fn addCases(
|
||||
const gpa = b.allocator;
|
||||
const io = b.graph.io;
|
||||
|
||||
var cases = @import("src/Cases.zig").init(gpa, arena);
|
||||
var cases = @import("src/Cases.zig").init(gpa, arena, io);
|
||||
|
||||
var dir = try b.build_root.handle.openDir(io, "test/cases", .{ .iterate = true });
|
||||
defer dir.close(io);
|
||||
|
||||
Reference in New Issue
Block a user