| author | |
| committer | |
| log | 10b1eef2d3901d17cf8810689a9e1eaf6d7901d9 |
| tree | c5312175f5f2716813322196dc10cdabf6b73f51 |
| parent | b215f8667a0cc59888926fcfcbb4be4370bd2216 |
17 files changed, 186 insertions(+), 101 deletions(-)
lib/compiler/test_runner.zig+2-2| ... | ... | @@ -148,7 +148,7 @@ fn mainServer() !void { |
| 148 | 148 | error.SkipZigTest => .skip, |
| 149 | 149 | else => s: { |
| 150 | 150 | if (@errorReturnTrace()) |trace| { |
| 151 | std.debug.dumpStackTrace(trace); | |
| 151 | std.debug.dumpStackTrace(trace.*); | |
| 152 | 152 | } |
| 153 | 153 | break :s .fail; |
| 154 | 154 | }, |
| ... | ... | @@ -269,7 +269,7 @@ fn mainTerminal() void { |
| 269 | 269 | std.debug.print("FAIL ({t})\n", .{err}); |
| 270 | 270 | } |
| 271 | 271 | if (@errorReturnTrace()) |trace| { |
| 272 | std.debug.dumpStackTrace(trace); | |
| 272 | std.debug.dumpStackTrace(trace.*); | |
| 273 | 273 | } |
| 274 | 274 | test_node.end(); |
| 275 | 275 | }, |
lib/std/Build/Step.zig+1-1| ... | ... | @@ -332,7 +332,7 @@ pub fn cast(step: *Step, comptime T: type) ?*T { |
| 332 | 332 | pub fn dump(step: *Step, w: *Io.Writer, tty_config: Io.tty.Config) void { |
| 333 | 333 | if (step.debug_stack_trace.instruction_addresses.len > 0) { |
| 334 | 334 | w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {}; |
| 335 | std.debug.writeStackTrace(&step.debug_stack_trace, w, tty_config) catch {}; | |
| 335 | std.debug.writeStackTrace(step.debug_stack_trace, w, tty_config) catch {}; | |
| 336 | 336 | } else { |
| 337 | 337 | const field = "debug_stack_frames_count"; |
| 338 | 338 | comptime assert(@hasField(Build, field)); |
lib/std/Io/Threaded.zig+1-3| ... | ... | @@ -31,7 +31,7 @@ const max_iovecs_len = 8; |
| 31 | 31 | const splat_buffer_size = 64; |
| 32 | 32 | |
| 33 | 33 | comptime { |
| 34 | assert(max_iovecs_len <= posix.IOV_MAX); | |
| 34 | if (@TypeOf(posix.IOV_MAX) != void) assert(max_iovecs_len <= posix.IOV_MAX); | |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | 37 | const Closure = struct { |
| ... | ... | @@ -91,9 +91,7 @@ pub fn init( |
| 91 | 91 | |
| 92 | 92 | /// Statically initialize such that any call to the following functions will |
| 93 | 93 | /// fail with `error.OutOfMemory`: |
| 94 | /// * `Io.VTable.async` | |
| 95 | 94 | /// * `Io.VTable.concurrent` |
| 96 | /// * `Io.VTable.groupAsync` | |
| 97 | 95 | /// When initialized this way, `deinit` is safe, but unnecessary to call. |
| 98 | 96 | pub const init_single_threaded: Threaded = .{ |
| 99 | 97 | .allocator = .failing, |
lib/std/Io/net/HostName.zig+1-1| ... | ... | @@ -221,7 +221,7 @@ pub fn connect( |
| 221 | 221 | defer { |
| 222 | 222 | connect_many.cancel(io); |
| 223 | 223 | if (!saw_end) while (true) switch (connect_many_queue.getOneUncancelable(io)) { |
| 224 | .connection => |loser| if (loser) |s| s.closeConst(io) else |_| continue, | |
| 224 | .connection => |loser| if (loser) |s| s.close(io) else |_| continue, | |
| 225 | 225 | .end => break, |
| 226 | 226 | }; |
| 227 | 227 | } |
lib/std/Thread.zig+1-1| ... | ... | @@ -577,7 +577,7 @@ fn callFn(comptime f: anytype, args: anytype) switch (Impl) { |
| 577 | 577 | @call(.auto, f, args) catch |err| { |
| 578 | 578 | std.debug.print("error: {s}\n", .{@errorName(err)}); |
| 579 | 579 | if (@errorReturnTrace()) |trace| { |
| 580 | std.debug.dumpStackTrace(trace); | |
| 580 | std.debug.dumpStackTrace(trace.*); | |
| 581 | 581 | } |
| 582 | 582 | }; |
| 583 | 583 |
lib/std/builtin.zig-13| ... | ... | @@ -37,19 +37,6 @@ pub const subsystem: ?std.Target.SubSystem = blk: { |
| 37 | 37 | pub const StackTrace = struct { |
| 38 | 38 | index: usize, |
| 39 | 39 | instruction_addresses: []usize, |
| 40 | ||
| 41 | pub fn format(st: *const StackTrace, writer: *std.Io.Writer) std.Io.Writer.Error!void { | |
| 42 | // TODO: re-evaluate whether to use format() methods at all. | |
| 43 | // Until then, avoid an error when using GeneralPurposeAllocator with WebAssembly | |
| 44 | // where it tries to call detectTTYConfig here. | |
| 45 | if (builtin.os.tag == .freestanding) return; | |
| 46 | ||
| 47 | // TODO: why on earth are we using stderr's ttyconfig? | |
| 48 | // If we want colored output, we should just make a formatter out of `writeStackTrace`. | |
| 49 | const tty_config = std.Io.tty.detectConfig(.stderr()); | |
| 50 | try writer.writeAll("\n"); | |
| 51 | try std.debug.writeStackTrace(st, writer, tty_config); | |
| 52 | } | |
| 53 | 40 | }; |
| 54 | 41 | |
| 55 | 42 | /// This data structure is used by the Zig language code generation and |
lib/std/debug.zig+38-15| ... | ... | @@ -1,4 +1,7 @@ |
| 1 | 1 | const std = @import("std.zig"); |
| 2 | const Io = std.Io; | |
| 3 | const Writer = std.Io.Writer; | |
| 4 | const tty = std.Io.tty; | |
| 2 | 5 | const math = std.math; |
| 3 | 6 | const mem = std.mem; |
| 4 | 7 | const posix = std.posix; |
| ... | ... | @@ -7,12 +10,11 @@ const testing = std.testing; |
| 7 | 10 | const Allocator = mem.Allocator; |
| 8 | 11 | const File = std.fs.File; |
| 9 | 12 | const windows = std.os.windows; |
| 10 | const Writer = std.Io.Writer; | |
| 11 | const tty = std.Io.tty; | |
| 12 | 13 | |
| 13 | 14 | const builtin = @import("builtin"); |
| 14 | 15 | const native_arch = builtin.cpu.arch; |
| 15 | 16 | const native_os = builtin.os.tag; |
| 17 | const StackTrace = std.builtin.StackTrace; | |
| 16 | 18 | |
| 17 | 19 | const root = @import("root"); |
| 18 | 20 | |
| ... | ... | @@ -545,13 +547,13 @@ pub fn defaultPanic( |
| 545 | 547 | stderr.print("panic: ", .{}) catch break :trace; |
| 546 | 548 | } else { |
| 547 | 549 | const current_thread_id = std.Thread.getCurrentId(); |
| 548 | stderr.print("thread {} panic: ", .{current_thread_id}) catch break :trace; | |
| 550 | stderr.print("thread {d} panic: ", .{current_thread_id}) catch break :trace; | |
| 549 | 551 | } |
| 550 | 552 | stderr.print("{s}\n", .{msg}) catch break :trace; |
| 551 | 553 | |
| 552 | 554 | if (@errorReturnTrace()) |t| if (t.index > 0) { |
| 553 | 555 | stderr.writeAll("error return context:\n") catch break :trace; |
| 554 | writeStackTrace(t, stderr, tty_config) catch break :trace; | |
| 556 | writeStackTrace(t.*, stderr, tty_config) catch break :trace; | |
| 555 | 557 | stderr.writeAll("\nstack trace:\n") catch break :trace; |
| 556 | 558 | }; |
| 557 | 559 | writeCurrentStackTrace(.{ |
| ... | ... | @@ -607,8 +609,8 @@ pub const StackUnwindOptions = struct { |
| 607 | 609 | /// the given buffer, so `addr_buf` must have a lifetime at least equal to the `StackTrace`. |
| 608 | 610 | /// |
| 609 | 611 | /// See `writeCurrentStackTrace` to immediately print the trace instead of capturing it. |
| 610 | pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) std.builtin.StackTrace { | |
| 611 | const empty_trace: std.builtin.StackTrace = .{ .index = 0, .instruction_addresses = &.{} }; | |
| 612 | pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) StackTrace { | |
| 613 | const empty_trace: StackTrace = .{ .index = 0, .instruction_addresses = &.{} }; | |
| 612 | 614 | if (!std.options.allow_stack_tracing) return empty_trace; |
| 613 | 615 | var it = StackIterator.init(options.context) catch return empty_trace; |
| 614 | 616 | defer it.deinit(); |
| ... | ... | @@ -646,6 +648,9 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: |
| 646 | 648 | /// |
| 647 | 649 | /// See `captureCurrentStackTrace` to capture the trace addresses into a buffer instead of printing. |
| 648 | 650 | pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_config: tty.Config) Writer.Error!void { |
| 651 | var threaded: Io.Threaded = .init_single_threaded; | |
| 652 | const io = threaded.io(); | |
| 653 | ||
| 649 | 654 | if (!std.options.allow_stack_tracing) { |
| 650 | 655 | tty_config.setColor(writer, .dim) catch {}; |
| 651 | 656 | try writer.print("Cannot print stack trace: stack tracing is disabled\n", .{}); |
| ... | ... | @@ -730,7 +735,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Wri |
| 730 | 735 | } |
| 731 | 736 | // `ret_addr` is the return address, which is *after* the function call. |
| 732 | 737 | // Subtract 1 to get an address *in* the function call for a better source location. |
| 733 | try printSourceAtAddress(di_gpa, di, writer, ret_addr -| StackIterator.ra_call_offset, tty_config); | |
| 738 | try printSourceAtAddress(di_gpa, io, di, writer, ret_addr -| StackIterator.ra_call_offset, tty_config); | |
| 734 | 739 | printed_any_frame = true; |
| 735 | 740 | }, |
| 736 | 741 | }; |
| ... | ... | @@ -754,14 +759,29 @@ pub fn dumpCurrentStackTrace(options: StackUnwindOptions) void { |
| 754 | 759 | }; |
| 755 | 760 | } |
| 756 | 761 | |
| 762 | pub const FormatStackTrace = struct { | |
| 763 | stack_trace: StackTrace, | |
| 764 | tty_config: tty.Config, | |
| 765 | ||
| 766 | pub fn format(context: @This(), writer: *Io.Writer) Io.Writer.Error!void { | |
| 767 | try writer.writeAll("\n"); | |
| 768 | try writeStackTrace(context.stack_trace, writer, context.tty_config); | |
| 769 | } | |
| 770 | }; | |
| 771 | ||
| 757 | 772 | /// Write a previously captured stack trace to `writer`, annotated with source locations. |
| 758 | pub fn writeStackTrace(st: *const std.builtin.StackTrace, writer: *Writer, tty_config: tty.Config) Writer.Error!void { | |
| 773 | pub fn writeStackTrace(st: StackTrace, writer: *Writer, tty_config: tty.Config) Writer.Error!void { | |
| 759 | 774 | if (!std.options.allow_stack_tracing) { |
| 760 | 775 | tty_config.setColor(writer, .dim) catch {}; |
| 761 | 776 | try writer.print("Cannot print stack trace: stack tracing is disabled\n", .{}); |
| 762 | 777 | tty_config.setColor(writer, .reset) catch {}; |
| 763 | 778 | return; |
| 764 | 779 | } |
| 780 | // We use an independent Io implementation here in case there was a problem | |
| 781 | // with the application's Io implementation itself. | |
| 782 | var threaded: Io.Threaded = .init_single_threaded; | |
| 783 | const io = threaded.io(); | |
| 784 | ||
| 765 | 785 | // Fetch `st.index` straight away. Aside from avoiding redundant loads, this prevents issues if |
| 766 | 786 | // `st` is `@errorReturnTrace()` and errors are encountered while writing the stack trace. |
| 767 | 787 | const n_frames = st.index; |
| ... | ... | @@ -779,7 +799,7 @@ pub fn writeStackTrace(st: *const std.builtin.StackTrace, writer: *Writer, tty_c |
| 779 | 799 | for (st.instruction_addresses[0..captured_frames]) |ret_addr| { |
| 780 | 800 | // `ret_addr` is the return address, which is *after* the function call. |
| 781 | 801 | // Subtract 1 to get an address *in* the function call for a better source location. |
| 782 | try printSourceAtAddress(di_gpa, di, writer, ret_addr -| StackIterator.ra_call_offset, tty_config); | |
| 802 | try printSourceAtAddress(di_gpa, io, di, writer, ret_addr -| StackIterator.ra_call_offset, tty_config); | |
| 783 | 803 | } |
| 784 | 804 | if (n_frames > captured_frames) { |
| 785 | 805 | tty_config.setColor(writer, .bold) catch {}; |
| ... | ... | @@ -788,7 +808,7 @@ pub fn writeStackTrace(st: *const std.builtin.StackTrace, writer: *Writer, tty_c |
| 788 | 808 | } |
| 789 | 809 | } |
| 790 | 810 | /// A thin wrapper around `writeStackTrace` which writes to stderr and ignores write errors. |
| 791 | pub fn dumpStackTrace(st: *const std.builtin.StackTrace) void { | |
| 811 | pub fn dumpStackTrace(st: StackTrace) void { | |
| 792 | 812 | const tty_config = tty.detectConfig(.stderr()); |
| 793 | 813 | const stderr = lockStderrWriter(&.{}); |
| 794 | 814 | defer unlockStderrWriter(); |
| ... | ... | @@ -1075,8 +1095,8 @@ pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize { |
| 1075 | 1095 | return ptr; |
| 1076 | 1096 | } |
| 1077 | 1097 | |
| 1078 | fn printSourceAtAddress(gpa: Allocator, debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: tty.Config) Writer.Error!void { | |
| 1079 | const symbol: Symbol = debug_info.getSymbol(gpa, address) catch |err| switch (err) { | |
| 1098 | fn printSourceAtAddress(gpa: Allocator, io: Io, debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: tty.Config) Writer.Error!void { | |
| 1099 | const symbol: Symbol = debug_info.getSymbol(gpa, io, address) catch |err| switch (err) { | |
| 1080 | 1100 | error.MissingDebugInfo, |
| 1081 | 1101 | error.UnsupportedDebugInfo, |
| 1082 | 1102 | error.InvalidDebugInfo, |
| ... | ... | @@ -1581,11 +1601,14 @@ test "manage resources correctly" { |
| 1581 | 1601 | } |
| 1582 | 1602 | }; |
| 1583 | 1603 | const gpa = std.testing.allocator; |
| 1584 | var discarding: std.Io.Writer.Discarding = .init(&.{}); | |
| 1604 | var threaded: Io.Threaded = .init_single_threaded; | |
| 1605 | const io = threaded.io(); | |
| 1606 | var discarding: Io.Writer.Discarding = .init(&.{}); | |
| 1585 | 1607 | var di: SelfInfo = .init; |
| 1586 | 1608 | defer di.deinit(gpa); |
| 1587 | 1609 | try printSourceAtAddress( |
| 1588 | 1610 | gpa, |
| 1611 | io, | |
| 1589 | 1612 | &di, |
| 1590 | 1613 | &discarding.writer, |
| 1591 | 1614 | S.showMyTrace(), |
| ... | ... | @@ -1659,11 +1682,11 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize |
| 1659 | 1682 | stderr.print("{s}:\n", .{t.notes[i]}) catch return; |
| 1660 | 1683 | var frames_array_mutable = frames_array; |
| 1661 | 1684 | const frames = mem.sliceTo(frames_array_mutable[0..], 0); |
| 1662 | const stack_trace: std.builtin.StackTrace = .{ | |
| 1685 | const stack_trace: StackTrace = .{ | |
| 1663 | 1686 | .index = frames.len, |
| 1664 | 1687 | .instruction_addresses = frames, |
| 1665 | 1688 | }; |
| 1666 | writeStackTrace(&stack_trace, stderr, tty_config) catch return; | |
| 1689 | writeStackTrace(stack_trace, stderr, tty_config) catch return; | |
| 1667 | 1690 | } |
| 1668 | 1691 | if (t.index > end) { |
| 1669 | 1692 | stderr.print("{d} more traces not shown; consider increasing trace size\n", .{ |
lib/std/debug/SelfInfo/MachO.zig+3-1| ... | ... | @@ -30,7 +30,8 @@ pub fn deinit(si: *SelfInfo, gpa: Allocator) void { |
| 30 | 30 | si.ofiles.deinit(gpa); |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | pub fn getSymbol(si: *SelfInfo, gpa: Allocator, address: usize) Error!std.debug.Symbol { | |
| 33 | pub fn getSymbol(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!std.debug.Symbol { | |
| 34 | _ = io; | |
| 34 | 35 | const module = try si.findModule(gpa, address); |
| 35 | 36 | defer si.mutex.unlock(); |
| 36 | 37 | |
| ... | ... | @@ -970,6 +971,7 @@ fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile { |
| 970 | 971 | } |
| 971 | 972 | |
| 972 | 973 | const std = @import("std"); |
| 974 | const Io = std.Io; | |
| 973 | 975 | const Allocator = std.mem.Allocator; |
| 974 | 976 | const Dwarf = std.debug.Dwarf; |
| 975 | 977 | const Error = std.debug.SelfInfoError; |
lib/std/debug/SelfInfo/Windows.zig+2-1| ... | ... | @@ -474,7 +474,7 @@ const Module = struct { |
| 474 | 474 | break :pdb pdb; |
| 475 | 475 | }; |
| 476 | 476 | errdefer if (opt_pdb) |*pdb| { |
| 477 | pdb.file_reader.file.close(); | |
| 477 | pdb.file_reader.file.close(io); | |
| 478 | 478 | pdb.deinit(); |
| 479 | 479 | }; |
| 480 | 480 | |
| ... | ... | @@ -484,6 +484,7 @@ const Module = struct { |
| 484 | 484 | |
| 485 | 485 | return .{ |
| 486 | 486 | .arena = arena_instance.state, |
| 487 | .io = io, | |
| 487 | 488 | .coff_image_base = coff_image_base, |
| 488 | 489 | .mapped_file = mapped_file, |
| 489 | 490 | .dwarf = opt_dwarf, |
lib/std/fs/Dir.zig+2-3| ... | ... | @@ -1062,7 +1062,7 @@ pub fn makeOpenPath(self: Dir, sub_path: []const u8, open_dir_options: OpenOptio |
| 1062 | 1062 | w.SYNCHRONIZE | w.FILE_TRAVERSE | |
| 1063 | 1063 | (if (open_dir_options.iterate) w.FILE_LIST_DIRECTORY else @as(u32, 0)); |
| 1064 | 1064 | |
| 1065 | return self.makeOpenPathAccessMaskW(sub_path, base_flags, open_dir_options.no_follow); | |
| 1065 | return self.makeOpenPathAccessMaskW(sub_path, base_flags, !open_dir_options.follow_symlinks); | |
| 1066 | 1066 | }, |
| 1067 | 1067 | else => { |
| 1068 | 1068 | return self.openDir(sub_path, open_dir_options) catch |err| switch (err) { |
| ... | ... | @@ -1575,8 +1575,7 @@ pub fn symLink( |
| 1575 | 1575 | // when converting to an NT namespaced path. CreateSymbolicLink in |
| 1576 | 1576 | // symLinkW will handle the necessary conversion. |
| 1577 | 1577 | var target_path_w: windows.PathSpace = undefined; |
| 1578 | try windows.checkWtf8ToWtf16LeOverflow(target_path, &target_path_w.data); | |
| 1579 | target_path_w.len = try std.unicode.wtf8ToWtf16Le(&target_path_w.data, target_path); | |
| 1578 | target_path_w.len = try windows.wtf8ToWtf16Le(&target_path_w.data, target_path); | |
| 1580 | 1579 | target_path_w.data[target_path_w.len] = 0; |
| 1581 | 1580 | // However, we need to canonicalize any path separators to `\`, since if |
| 1582 | 1581 | // the target path is relative, then it must use `\` as the path separator. |
lib/std/fs/File.zig+2-2| ... | ... | @@ -564,8 +564,8 @@ pub fn updateTimes( |
| 564 | 564 | mtime: Io.Timestamp, |
| 565 | 565 | ) UpdateTimesError!void { |
| 566 | 566 | if (builtin.os.tag == .windows) { |
| 567 | const atime_ft = windows.nanoSecondsToFileTime(atime.nanoseconds); | |
| 568 | const mtime_ft = windows.nanoSecondsToFileTime(mtime.nanoseconds); | |
| 567 | const atime_ft = windows.nanoSecondsToFileTime(atime); | |
| 568 | const mtime_ft = windows.nanoSecondsToFileTime(mtime); | |
| 569 | 569 | return windows.SetFileTime(self.handle, null, &atime_ft, &mtime_ft); |
| 570 | 570 | } |
| 571 | 571 | const times = [2]posix.timespec{ |
lib/std/heap/debug_allocator.zig+90-19| ... | ... | @@ -80,15 +80,15 @@ |
| 80 | 80 | //! |
| 81 | 81 | //! Resizing and remapping are forwarded directly to the backing allocator, |
| 82 | 82 | //! except where such operations would change the category from large to small. |
| 83 | const builtin = @import("builtin"); | |
| 84 | const StackTrace = std.builtin.StackTrace; | |
| 83 | 85 | |
| 84 | 86 | const std = @import("std"); |
| 85 | const builtin = @import("builtin"); | |
| 86 | 87 | const log = std.log.scoped(.gpa); |
| 87 | 88 | const math = std.math; |
| 88 | 89 | const assert = std.debug.assert; |
| 89 | 90 | const mem = std.mem; |
| 90 | 91 | const Allocator = std.mem.Allocator; |
| 91 | const StackTrace = std.builtin.StackTrace; | |
| 92 | 92 | |
| 93 | 93 | const default_page_size: usize = switch (builtin.os.tag) { |
| 94 | 94 | // Makes `std.heap.PageAllocator` take the happy path. |
| ... | ... | @@ -421,7 +421,12 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 421 | 421 | return usedBitsCount(slot_count) * @sizeOf(usize); |
| 422 | 422 | } |
| 423 | 423 | |
| 424 | fn detectLeaksInBucket(bucket: *BucketHeader, size_class_index: usize, used_bits_count: usize) usize { | |
| 424 | fn detectLeaksInBucket( | |
| 425 | bucket: *BucketHeader, | |
| 426 | size_class_index: usize, | |
| 427 | used_bits_count: usize, | |
| 428 | tty_config: std.Io.tty.Config, | |
| 429 | ) usize { | |
| 425 | 430 | const size_class = @as(usize, 1) << @as(Log2USize, @intCast(size_class_index)); |
| 426 | 431 | const slot_count = slot_counts[size_class_index]; |
| 427 | 432 | var leaks: usize = 0; |
| ... | ... | @@ -436,7 +441,13 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 436 | 441 | const stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc); |
| 437 | 442 | const page_addr = @intFromPtr(bucket) & ~(page_size - 1); |
| 438 | 443 | const addr = page_addr + slot_index * size_class; |
| 439 | log.err("memory address 0x{x} leaked: {f}", .{ addr, stack_trace }); | |
| 444 | log.err("memory address 0x{x} leaked: {f}", .{ | |
| 445 | addr, | |
| 446 | std.debug.FormatStackTrace{ | |
| 447 | .stack_trace = stack_trace, | |
| 448 | .tty_config = tty_config, | |
| 449 | }, | |
| 450 | }); | |
| 440 | 451 | leaks += 1; |
| 441 | 452 | } |
| 442 | 453 | } |
| ... | ... | @@ -449,12 +460,14 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 449 | 460 | pub fn detectLeaks(self: *Self) usize { |
| 450 | 461 | var leaks: usize = 0; |
| 451 | 462 | |
| 463 | const tty_config = std.Io.tty.detectConfig(.stderr()); | |
| 464 | ||
| 452 | 465 | for (self.buckets, 0..) |init_optional_bucket, size_class_index| { |
| 453 | 466 | var optional_bucket = init_optional_bucket; |
| 454 | 467 | const slot_count = slot_counts[size_class_index]; |
| 455 | 468 | const used_bits_count = usedBitsCount(slot_count); |
| 456 | 469 | while (optional_bucket) |bucket| { |
| 457 | leaks += detectLeaksInBucket(bucket, size_class_index, used_bits_count); | |
| 470 | leaks += detectLeaksInBucket(bucket, size_class_index, used_bits_count, tty_config); | |
| 458 | 471 | optional_bucket = bucket.prev; |
| 459 | 472 | } |
| 460 | 473 | } |
| ... | ... | @@ -464,7 +477,11 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 464 | 477 | if (config.retain_metadata and large_alloc.freed) continue; |
| 465 | 478 | const stack_trace = large_alloc.getStackTrace(.alloc); |
| 466 | 479 | log.err("memory address 0x{x} leaked: {f}", .{ |
| 467 | @intFromPtr(large_alloc.bytes.ptr), stack_trace, | |
| 480 | @intFromPtr(large_alloc.bytes.ptr), | |
| 481 | std.debug.FormatStackTrace{ | |
| 482 | .stack_trace = stack_trace, | |
| 483 | .tty_config = tty_config, | |
| 484 | }, | |
| 468 | 485 | }); |
| 469 | 486 | leaks += 1; |
| 470 | 487 | } |
| ... | ... | @@ -519,8 +536,20 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 519 | 536 | fn reportDoubleFree(ret_addr: usize, alloc_stack_trace: StackTrace, free_stack_trace: StackTrace) void { |
| 520 | 537 | var addr_buf: [stack_n]usize = undefined; |
| 521 | 538 | const second_free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = ret_addr }, &addr_buf); |
| 539 | const tty_config = std.Io.tty.detectConfig(.stderr()); | |
| 522 | 540 | log.err("Double free detected. Allocation: {f} First free: {f} Second free: {f}", .{ |
| 523 | alloc_stack_trace, free_stack_trace, second_free_stack_trace, | |
| 541 | std.debug.FormatStackTrace{ | |
| 542 | .stack_trace = alloc_stack_trace, | |
| 543 | .tty_config = tty_config, | |
| 544 | }, | |
| 545 | std.debug.FormatStackTrace{ | |
| 546 | .stack_trace = free_stack_trace, | |
| 547 | .tty_config = tty_config, | |
| 548 | }, | |
| 549 | std.debug.FormatStackTrace{ | |
| 550 | .stack_trace = second_free_stack_trace, | |
| 551 | .tty_config = tty_config, | |
| 552 | }, | |
| 524 | 553 | }); |
| 525 | 554 | } |
| 526 | 555 | |
| ... | ... | @@ -561,11 +590,18 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 561 | 590 | if (config.safety and old_mem.len != entry.value_ptr.bytes.len) { |
| 562 | 591 | var addr_buf: [stack_n]usize = undefined; |
| 563 | 592 | const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = ret_addr }, &addr_buf); |
| 593 | const tty_config = std.Io.tty.detectConfig(.stderr()); | |
| 564 | 594 | log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ |
| 565 | 595 | entry.value_ptr.bytes.len, |
| 566 | 596 | old_mem.len, |
| 567 | entry.value_ptr.getStackTrace(.alloc), | |
| 568 | free_stack_trace, | |
| 597 | std.debug.FormatStackTrace{ | |
| 598 | .stack_trace = entry.value_ptr.getStackTrace(.alloc), | |
| 599 | .tty_config = tty_config, | |
| 600 | }, | |
| 601 | std.debug.FormatStackTrace{ | |
| 602 | .stack_trace = free_stack_trace, | |
| 603 | .tty_config = tty_config, | |
| 604 | }, | |
| 569 | 605 | }); |
| 570 | 606 | } |
| 571 | 607 | |
| ... | ... | @@ -667,11 +703,18 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 667 | 703 | if (config.safety and old_mem.len != entry.value_ptr.bytes.len) { |
| 668 | 704 | var addr_buf: [stack_n]usize = undefined; |
| 669 | 705 | const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = ret_addr }, &addr_buf); |
| 706 | const tty_config = std.Io.tty.detectConfig(.stderr()); | |
| 670 | 707 | log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ |
| 671 | 708 | entry.value_ptr.bytes.len, |
| 672 | 709 | old_mem.len, |
| 673 | entry.value_ptr.getStackTrace(.alloc), | |
| 674 | free_stack_trace, | |
| 710 | std.debug.FormatStackTrace{ | |
| 711 | .stack_trace = entry.value_ptr.getStackTrace(.alloc), | |
| 712 | .tty_config = tty_config, | |
| 713 | }, | |
| 714 | std.debug.FormatStackTrace{ | |
| 715 | .stack_trace = free_stack_trace, | |
| 716 | .tty_config = tty_config, | |
| 717 | }, | |
| 675 | 718 | }); |
| 676 | 719 | } |
| 677 | 720 | |
| ... | ... | @@ -892,19 +935,33 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 892 | 935 | var addr_buf: [stack_n]usize = undefined; |
| 893 | 936 | const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = return_address }, &addr_buf); |
| 894 | 937 | if (old_memory.len != requested_size) { |
| 938 | const tty_config = std.Io.tty.detectConfig(.stderr()); | |
| 895 | 939 | log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ |
| 896 | 940 | requested_size, |
| 897 | 941 | old_memory.len, |
| 898 | bucketStackTrace(bucket, slot_count, slot_index, .alloc), | |
| 899 | free_stack_trace, | |
| 942 | std.debug.FormatStackTrace{ | |
| 943 | .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc), | |
| 944 | .tty_config = tty_config, | |
| 945 | }, | |
| 946 | std.debug.FormatStackTrace{ | |
| 947 | .stack_trace = free_stack_trace, | |
| 948 | .tty_config = tty_config, | |
| 949 | }, | |
| 900 | 950 | }); |
| 901 | 951 | } |
| 902 | 952 | if (alignment != slot_alignment) { |
| 953 | const tty_config = std.Io.tty.detectConfig(.stderr()); | |
| 903 | 954 | log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {f} Free: {f}", .{ |
| 904 | 955 | slot_alignment.toByteUnits(), |
| 905 | 956 | alignment.toByteUnits(), |
| 906 | bucketStackTrace(bucket, slot_count, slot_index, .alloc), | |
| 907 | free_stack_trace, | |
| 957 | std.debug.FormatStackTrace{ | |
| 958 | .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc), | |
| 959 | .tty_config = tty_config, | |
| 960 | }, | |
| 961 | std.debug.FormatStackTrace{ | |
| 962 | .stack_trace = free_stack_trace, | |
| 963 | .tty_config = tty_config, | |
| 964 | }, | |
| 908 | 965 | }); |
| 909 | 966 | } |
| 910 | 967 | } |
| ... | ... | @@ -987,19 +1044,33 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 987 | 1044 | var addr_buf: [stack_n]usize = undefined; |
| 988 | 1045 | const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = return_address }, &addr_buf); |
| 989 | 1046 | if (memory.len != requested_size) { |
| 1047 | const tty_config = std.Io.tty.detectConfig(.stderr()); | |
| 990 | 1048 | log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ |
| 991 | 1049 | requested_size, |
| 992 | 1050 | memory.len, |
| 993 | bucketStackTrace(bucket, slot_count, slot_index, .alloc), | |
| 994 | free_stack_trace, | |
| 1051 | std.debug.FormatStackTrace{ | |
| 1052 | .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc), | |
| 1053 | .tty_config = tty_config, | |
| 1054 | }, | |
| 1055 | std.debug.FormatStackTrace{ | |
| 1056 | .stack_trace = free_stack_trace, | |
| 1057 | .tty_config = tty_config, | |
| 1058 | }, | |
| 995 | 1059 | }); |
| 996 | 1060 | } |
| 997 | 1061 | if (alignment != slot_alignment) { |
| 1062 | const tty_config = std.Io.tty.detectConfig(.stderr()); | |
| 998 | 1063 | log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {f} Free: {f}", .{ |
| 999 | 1064 | slot_alignment.toByteUnits(), |
| 1000 | 1065 | alignment.toByteUnits(), |
| 1001 | bucketStackTrace(bucket, slot_count, slot_index, .alloc), | |
| 1002 | free_stack_trace, | |
| 1066 | std.debug.FormatStackTrace{ | |
| 1067 | .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc), | |
| 1068 | .tty_config = tty_config, | |
| 1069 | }, | |
| 1070 | std.debug.FormatStackTrace{ | |
| 1071 | .stack_trace = free_stack_trace, | |
| 1072 | .tty_config = tty_config, | |
| 1073 | }, | |
| 1003 | 1074 | }); |
| 1004 | 1075 | } |
| 1005 | 1076 | } |
lib/std/os/windows.zig+20-14| ... | ... | @@ -5,12 +5,14 @@ |
| 5 | 5 | //! slices as well as APIs which accept null-terminated WTF16LE byte buffers. |
| 6 | 6 | |
| 7 | 7 | const builtin = @import("builtin"); |
| 8 | const native_arch = builtin.cpu.arch; | |
| 9 | ||
| 8 | 10 | const std = @import("../std.zig"); |
| 11 | const Io = std.Io; | |
| 9 | 12 | const mem = std.mem; |
| 10 | 13 | const assert = std.debug.assert; |
| 11 | 14 | const math = std.math; |
| 12 | 15 | const maxInt = std.math.maxInt; |
| 13 | const native_arch = builtin.cpu.arch; | |
| 14 | 16 | const UnexpectedError = std.posix.UnexpectedError; |
| 15 | 17 | |
| 16 | 18 | test { |
| ... | ... | @@ -2219,25 +2221,25 @@ pub fn peb() *PEB { |
| 2219 | 2221 | /// Universal Time (UTC). |
| 2220 | 2222 | /// This function returns the number of nanoseconds since the canonical epoch, |
| 2221 | 2223 | /// which is the POSIX one (Jan 01, 1970 AD). |
| 2222 | pub fn fromSysTime(hns: i64) i128 { | |
| 2224 | pub fn fromSysTime(hns: i64) Io.Timestamp { | |
| 2223 | 2225 | const adjusted_epoch: i128 = hns + std.time.epoch.windows * (std.time.ns_per_s / 100); |
| 2224 | return adjusted_epoch * 100; | |
| 2226 | return .fromNanoseconds(@intCast(adjusted_epoch * 100)); | |
| 2225 | 2227 | } |
| 2226 | 2228 | |
| 2227 | pub fn toSysTime(ns: i128) i64 { | |
| 2228 | const hns = @divFloor(ns, 100); | |
| 2229 | pub fn toSysTime(ns: Io.Timestamp) i64 { | |
| 2230 | const hns = @divFloor(ns.nanoseconds, 100); | |
| 2229 | 2231 | return @as(i64, @intCast(hns)) - std.time.epoch.windows * (std.time.ns_per_s / 100); |
| 2230 | 2232 | } |
| 2231 | 2233 | |
| 2232 | pub fn fileTimeToNanoSeconds(ft: FILETIME) i128 { | |
| 2234 | pub fn fileTimeToNanoSeconds(ft: FILETIME) Io.Timestamp { | |
| 2233 | 2235 | const hns = (@as(i64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime; |
| 2234 | 2236 | return fromSysTime(hns); |
| 2235 | 2237 | } |
| 2236 | 2238 | |
| 2237 | 2239 | /// Converts a number of nanoseconds since the POSIX epoch to a Windows FILETIME. |
| 2238 | pub fn nanoSecondsToFileTime(ns: i128) FILETIME { | |
| 2240 | pub fn nanoSecondsToFileTime(ns: Io.Timestamp) FILETIME { | |
| 2239 | 2241 | const adjusted: u64 = @bitCast(toSysTime(ns)); |
| 2240 | return FILETIME{ | |
| 2242 | return .{ | |
| 2241 | 2243 | .dwHighDateTime = @as(u32, @truncate(adjusted >> 32)), |
| 2242 | 2244 | .dwLowDateTime = @as(u32, @truncate(adjusted)), |
| 2243 | 2245 | }; |
| ... | ... | @@ -5740,11 +5742,15 @@ pub fn ProcessBaseAddress(handle: HANDLE) ProcessBaseAddressError!HMODULE { |
| 5740 | 5742 | return ppeb.ImageBaseAddress; |
| 5741 | 5743 | } |
| 5742 | 5744 | |
| 5743 | pub fn checkWtf8ToWtf16LeOverflow(wtf8: []const u8, wtf16le: []const u16) error{ BadPathName, NameTooLong }!void { | |
| 5745 | pub fn wtf8ToWtf16Le(wtf16le: []u16, wtf8: []const u8) error{ BadPathName, NameTooLong }!usize { | |
| 5744 | 5746 | // Each u8 in UTF-8/WTF-8 correlates to at most one u16 in UTF-16LE/WTF-16LE. |
| 5745 | if (wtf16le.len >= wtf8.len) return; | |
| 5746 | const utf16_len = std.unicode.calcUtf16LeLenImpl(wtf8, .can_encode_surrogate_half) catch | |
| 5747 | return error.BadPathName; | |
| 5748 | if (utf16_len > wtf16le.len) | |
| 5749 | return error.NameTooLong; | |
| 5747 | if (wtf16le.len < wtf8.len) { | |
| 5748 | const utf16_len = std.unicode.calcUtf16LeLenImpl(wtf8, .can_encode_surrogate_half) catch | |
| 5749 | return error.BadPathName; | |
| 5750 | if (utf16_len > wtf16le.len) | |
| 5751 | return error.NameTooLong; | |
| 5752 | } | |
| 5753 | return std.unicode.wtf8ToWtf16Le(wtf16le, wtf8) catch |err| switch (err) { | |
| 5754 | error.InvalidWtf8 => return error.BadPathName, | |
| 5755 | }; | |
| 5750 | 5756 | } |
lib/std/posix.zig+5-4| ... | ... | @@ -821,6 +821,9 @@ pub const ReadError = std.Io.File.ReadStreamingError; |
| 821 | 821 | /// The corresponding POSIX limit is `maxInt(isize)`. |
| 822 | 822 | pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 823 | 823 | if (buf.len == 0) return 0; |
| 824 | if (native_os == .windows) { | |
| 825 | return windows.ReadFile(fd, buf, null); | |
| 826 | } | |
| 824 | 827 | if (native_os == .wasi and !builtin.link_libc) { |
| 825 | 828 | const iovs = [1]iovec{iovec{ |
| 826 | 829 | .base = buf.ptr, |
| ... | ... | @@ -2918,8 +2921,7 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { |
| 2918 | 2921 | @compileError("WASI does not support os.chdir"); |
| 2919 | 2922 | } else if (native_os == .windows) { |
| 2920 | 2923 | var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined; |
| 2921 | try windows.checkWtf8ToWtf16LeOverflow(dir_path, &wtf16_dir_path); | |
| 2922 | const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path); | |
| 2924 | const len = try windows.wtf8ToWtf16Le(&wtf16_dir_path, dir_path); | |
| 2923 | 2925 | return chdirW(wtf16_dir_path[0..len]); |
| 2924 | 2926 | } else { |
| 2925 | 2927 | const dir_path_c = try toPosixPath(dir_path); |
| ... | ... | @@ -2935,8 +2937,7 @@ pub fn chdirZ(dir_path: [*:0]const u8) ChangeCurDirError!void { |
| 2935 | 2937 | if (native_os == .windows) { |
| 2936 | 2938 | const dir_path_span = mem.span(dir_path); |
| 2937 | 2939 | var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined; |
| 2938 | try windows.checkWtf8ToWtf16LeOverflow(dir_path_span, &wtf16_dir_path); | |
| 2939 | const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path_span); | |
| 2940 | const len = try windows.wtf8ToWtf16Le(&wtf16_dir_path, dir_path_span); | |
| 2940 | 2941 | return chdirW(wtf16_dir_path[0..len]); |
| 2941 | 2942 | } else if (native_os == .wasi and !builtin.link_libc) { |
| 2942 | 2943 | return chdir(mem.span(dir_path)); |
lib/std/posix/test.zig-14| ... | ... | @@ -862,20 +862,6 @@ test "isatty" { |
| 862 | 862 | try expectEqual(posix.isatty(file.handle), false); |
| 863 | 863 | } |
| 864 | 864 | |
| 865 | test "read with empty buffer" { | |
| 866 | var tmp = tmpDir(.{}); | |
| 867 | defer tmp.cleanup(); | |
| 868 | ||
| 869 | var file = try tmp.dir.createFile("read_empty", .{ .read = true }); | |
| 870 | defer file.close(); | |
| 871 | ||
| 872 | const bytes = try a.alloc(u8, 0); | |
| 873 | defer a.free(bytes); | |
| 874 | ||
| 875 | const rc = try posix.read(file.handle, bytes); | |
| 876 | try expectEqual(rc, 0); | |
| 877 | } | |
| 878 | ||
| 879 | 865 | test "pread with empty buffer" { |
| 880 | 866 | var tmp = tmpDir(.{}); |
| 881 | 867 | defer tmp.cleanup(); |
lib/std/testing.zig+5-1| ... | ... | @@ -1148,6 +1148,7 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime |
| 1148 | 1148 | } else |err| switch (err) { |
| 1149 | 1149 | error.OutOfMemory => { |
| 1150 | 1150 | if (failing_allocator_inst.allocated_bytes != failing_allocator_inst.freed_bytes) { |
| 1151 | const tty_config = std.Io.tty.detectConfig(.stderr()); | |
| 1151 | 1152 | print( |
| 1152 | 1153 | "\nfail_index: {d}/{d}\nallocated bytes: {d}\nfreed bytes: {d}\nallocations: {d}\ndeallocations: {d}\nallocation that was made to fail: {f}", |
| 1153 | 1154 | .{ |
| ... | ... | @@ -1157,7 +1158,10 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime |
| 1157 | 1158 | failing_allocator_inst.freed_bytes, |
| 1158 | 1159 | failing_allocator_inst.allocations, |
| 1159 | 1160 | failing_allocator_inst.deallocations, |
| 1160 | failing_allocator_inst.getStackTrace(), | |
| 1161 | std.debug.FormatStackTrace{ | |
| 1162 | .stack_trace = failing_allocator_inst.getStackTrace(), | |
| 1163 | .tty_config = tty_config, | |
| 1164 | }, | |
| 1161 | 1165 | }, |
| 1162 | 1166 | ); |
| 1163 | 1167 | return error.MemoryLeakDetected; |
tools/incr-check.zig+13-6| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const Io = std.Io; | |
| 2 | 3 | const Allocator = std.mem.Allocator; |
| 3 | 4 | const Cache = std.Build.Cache; |
| 4 | 5 | |
| ... | ... | @@ -11,6 +12,12 @@ pub fn main() !void { |
| 11 | 12 | defer arena_instance.deinit(); |
| 12 | 13 | const arena = arena_instance.allocator(); |
| 13 | 14 | |
| 15 | const gpa = arena; | |
| 16 | ||
| 17 | var threaded: Io.Threaded = .init(gpa); | |
| 18 | defer threaded.deinit(); | |
| 19 | const io = threaded.io(); | |
| 20 | ||
| 14 | 21 | var opt_zig_exe: ?[]const u8 = null; |
| 15 | 22 | var opt_input_file_name: ?[]const u8 = null; |
| 16 | 23 | var opt_lib_dir: ?[]const u8 = null; |
| ... | ... | @@ -53,7 +60,7 @@ pub fn main() !void { |
| 53 | 60 | const input_file_name = opt_input_file_name orelse fatal("missing input file\n{s}", .{usage}); |
| 54 | 61 | |
| 55 | 62 | const input_file_bytes = try std.fs.cwd().readFileAlloc(input_file_name, arena, .limited(std.math.maxInt(u32))); |
| 56 | const case = try Case.parse(arena, input_file_bytes); | |
| 63 | const case = try Case.parse(arena, io, input_file_bytes); | |
| 57 | 64 | |
| 58 | 65 | // Check now: if there are any targets using the `cbe` backend, we need the lib dir. |
| 59 | 66 | if (opt_lib_dir == null) { |
| ... | ... | @@ -86,7 +93,7 @@ pub fn main() !void { |
| 86 | 93 | else |
| 87 | 94 | null; |
| 88 | 95 | |
| 89 | const host = try std.zig.system.resolveTargetQuery(.{}); | |
| 96 | const host = try std.zig.system.resolveTargetQuery(io, .{}); | |
| 90 | 97 | |
| 91 | 98 | const debug_log_verbose = debug_zcu or debug_dwarf or debug_link; |
| 92 | 99 | |
| ... | ... | @@ -186,7 +193,7 @@ pub fn main() !void { |
| 186 | 193 | |
| 187 | 194 | try child.spawn(); |
| 188 | 195 | |
| 189 | var poller = std.Io.poll(arena, Eval.StreamEnum, .{ | |
| 196 | var poller = Io.poll(arena, Eval.StreamEnum, .{ | |
| 190 | 197 | .stdout = child.stdout.?, |
| 191 | 198 | .stderr = child.stderr.?, |
| 192 | 199 | }); |
| ... | ... | @@ -226,7 +233,7 @@ const Eval = struct { |
| 226 | 233 | cc_child_args: *std.ArrayListUnmanaged([]const u8), |
| 227 | 234 | |
| 228 | 235 | const StreamEnum = enum { stdout, stderr }; |
| 229 | const Poller = std.Io.Poller(StreamEnum); | |
| 236 | const Poller = Io.Poller(StreamEnum); | |
| 230 | 237 | |
| 231 | 238 | /// Currently this function assumes the previous updates have already been written. |
| 232 | 239 | fn write(eval: *Eval, update: Case.Update) void { |
| ... | ... | @@ -647,7 +654,7 @@ const Case = struct { |
| 647 | 654 | msg: []const u8, |
| 648 | 655 | }; |
| 649 | 656 | |
| 650 | fn parse(arena: Allocator, bytes: []const u8) !Case { | |
| 657 | fn parse(arena: Allocator, io: Io, bytes: []const u8) !Case { | |
| 651 | 658 | const fatal = std.process.fatal; |
| 652 | 659 | |
| 653 | 660 | var targets: std.ArrayListUnmanaged(Target) = .empty; |
| ... | ... | @@ -683,7 +690,7 @@ const Case = struct { |
| 683 | 690 | }, |
| 684 | 691 | }) catch fatal("line {d}: invalid target query '{s}'", .{ line_n, query }); |
| 685 | 692 | |
| 686 | const resolved = try std.zig.system.resolveTargetQuery(parsed_query); | |
| 693 | const resolved = try std.zig.system.resolveTargetQuery(io, parsed_query); | |
| 687 | 694 | |
| 688 | 695 | try targets.append(arena, .{ |
| 689 | 696 | .query = query, |