| 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,7 +148,7 @@ fn mainServer() !void { |
| 148 | error.SkipZigTest => .skip, | 148 | error.SkipZigTest => .skip, |
| 149 | else => s: { | 149 | else => s: { |
| 150 | if (@errorReturnTrace()) |trace| { | 150 | if (@errorReturnTrace()) |trace| { |
| 151 | std.debug.dumpStackTrace(trace); | 151 | std.debug.dumpStackTrace(trace.*); |
| 152 | } | 152 | } |
| 153 | break :s .fail; | 153 | break :s .fail; |
| 154 | }, | 154 | }, |
| ... | @@ -269,7 +269,7 @@ fn mainTerminal() void { | ... | @@ -269,7 +269,7 @@ fn mainTerminal() void { |
| 269 | std.debug.print("FAIL ({t})\n", .{err}); | 269 | std.debug.print("FAIL ({t})\n", .{err}); |
| 270 | } | 270 | } |
| 271 | if (@errorReturnTrace()) |trace| { | 271 | if (@errorReturnTrace()) |trace| { |
| 272 | std.debug.dumpStackTrace(trace); | 272 | std.debug.dumpStackTrace(trace.*); |
| 273 | } | 273 | } |
| 274 | test_node.end(); | 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,7 +332,7 @@ pub fn cast(step: *Step, comptime T: type) ?*T { |
| 332 | pub fn dump(step: *Step, w: *Io.Writer, tty_config: Io.tty.Config) void { | 332 | pub fn dump(step: *Step, w: *Io.Writer, tty_config: Io.tty.Config) void { |
| 333 | if (step.debug_stack_trace.instruction_addresses.len > 0) { | 333 | if (step.debug_stack_trace.instruction_addresses.len > 0) { |
| 334 | w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {}; | 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 | } else { | 336 | } else { |
| 337 | const field = "debug_stack_frames_count"; | 337 | const field = "debug_stack_frames_count"; |
| 338 | comptime assert(@hasField(Build, field)); | 338 | comptime assert(@hasField(Build, field)); |
lib/std/Io/Threaded.zig+1-3| ... | @@ -31,7 +31,7 @@ const max_iovecs_len = 8; | ... | @@ -31,7 +31,7 @@ const max_iovecs_len = 8; |
| 31 | const splat_buffer_size = 64; | 31 | const splat_buffer_size = 64; |
| 32 | 32 | ||
| 33 | comptime { | 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 | const Closure = struct { | 37 | const Closure = struct { |
| ... | @@ -91,9 +91,7 @@ pub fn init( | ... | @@ -91,9 +91,7 @@ pub fn init( |
| 91 | 91 | ||
| 92 | /// Statically initialize such that any call to the following functions will | 92 | /// Statically initialize such that any call to the following functions will |
| 93 | /// fail with `error.OutOfMemory`: | 93 | /// fail with `error.OutOfMemory`: |
| 94 | /// * `Io.VTable.async` | ||
| 95 | /// * `Io.VTable.concurrent` | 94 | /// * `Io.VTable.concurrent` |
| 96 | /// * `Io.VTable.groupAsync` | ||
| 97 | /// When initialized this way, `deinit` is safe, but unnecessary to call. | 95 | /// When initialized this way, `deinit` is safe, but unnecessary to call. |
| 98 | pub const init_single_threaded: Threaded = .{ | 96 | pub const init_single_threaded: Threaded = .{ |
| 99 | .allocator = .failing, | 97 | .allocator = .failing, |
lib/std/Io/net/HostName.zig+1-1| ... | @@ -221,7 +221,7 @@ pub fn connect( | ... | @@ -221,7 +221,7 @@ pub fn connect( |
| 221 | defer { | 221 | defer { |
| 222 | connect_many.cancel(io); | 222 | connect_many.cancel(io); |
| 223 | if (!saw_end) while (true) switch (connect_many_queue.getOneUncancelable(io)) { | 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 | .end => break, | 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,7 +577,7 @@ fn callFn(comptime f: anytype, args: anytype) switch (Impl) { |
| 577 | @call(.auto, f, args) catch |err| { | 577 | @call(.auto, f, args) catch |err| { |
| 578 | std.debug.print("error: {s}\n", .{@errorName(err)}); | 578 | std.debug.print("error: {s}\n", .{@errorName(err)}); |
| 579 | if (@errorReturnTrace()) |trace| { | 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,19 +37,6 @@ pub const subsystem: ?std.Target.SubSystem = blk: { |
| 37 | pub const StackTrace = struct { | 37 | pub const StackTrace = struct { |
| 38 | index: usize, | 38 | index: usize, |
| 39 | instruction_addresses: []usize, | 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 | /// This data structure is used by the Zig language code generation and | 42 | /// This data structure is used by the Zig language code generation and |
lib/std/debug.zig+38-15| ... | @@ -1,4 +1,7 @@ | ... | @@ -1,4 +1,7 @@ |
| 1 | const std = @import("std.zig"); | 1 | const std = @import("std.zig"); |
| 2 | const Io = std.Io; | ||
| 3 | const Writer = std.Io.Writer; | ||
| 4 | const tty = std.Io.tty; | ||
| 2 | const math = std.math; | 5 | const math = std.math; |
| 3 | const mem = std.mem; | 6 | const mem = std.mem; |
| 4 | const posix = std.posix; | 7 | const posix = std.posix; |
| ... | @@ -7,12 +10,11 @@ const testing = std.testing; | ... | @@ -7,12 +10,11 @@ const testing = std.testing; |
| 7 | const Allocator = mem.Allocator; | 10 | const Allocator = mem.Allocator; |
| 8 | const File = std.fs.File; | 11 | const File = std.fs.File; |
| 9 | const windows = std.os.windows; | 12 | const windows = std.os.windows; |
| 10 | const Writer = std.Io.Writer; | ||
| 11 | const tty = std.Io.tty; | ||
| 12 | 13 | ||
| 13 | const builtin = @import("builtin"); | 14 | const builtin = @import("builtin"); |
| 14 | const native_arch = builtin.cpu.arch; | 15 | const native_arch = builtin.cpu.arch; |
| 15 | const native_os = builtin.os.tag; | 16 | const native_os = builtin.os.tag; |
| 17 | const StackTrace = std.builtin.StackTrace; | ||
| 16 | 18 | ||
| 17 | const root = @import("root"); | 19 | const root = @import("root"); |
| 18 | 20 | ||
| ... | @@ -545,13 +547,13 @@ pub fn defaultPanic( | ... | @@ -545,13 +547,13 @@ pub fn defaultPanic( |
| 545 | stderr.print("panic: ", .{}) catch break :trace; | 547 | stderr.print("panic: ", .{}) catch break :trace; |
| 546 | } else { | 548 | } else { |
| 547 | const current_thread_id = std.Thread.getCurrentId(); | 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 | stderr.print("{s}\n", .{msg}) catch break :trace; | 552 | stderr.print("{s}\n", .{msg}) catch break :trace; |
| 551 | 553 | ||
| 552 | if (@errorReturnTrace()) |t| if (t.index > 0) { | 554 | if (@errorReturnTrace()) |t| if (t.index > 0) { |
| 553 | stderr.writeAll("error return context:\n") catch break :trace; | 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 | stderr.writeAll("\nstack trace:\n") catch break :trace; | 557 | stderr.writeAll("\nstack trace:\n") catch break :trace; |
| 556 | }; | 558 | }; |
| 557 | writeCurrentStackTrace(.{ | 559 | writeCurrentStackTrace(.{ |
| ... | @@ -607,8 +609,8 @@ pub const StackUnwindOptions = struct { | ... | @@ -607,8 +609,8 @@ pub const StackUnwindOptions = struct { |
| 607 | /// the given buffer, so `addr_buf` must have a lifetime at least equal to the `StackTrace`. | 609 | /// the given buffer, so `addr_buf` must have a lifetime at least equal to the `StackTrace`. |
| 608 | /// | 610 | /// |
| 609 | /// See `writeCurrentStackTrace` to immediately print the trace instead of capturing it. | 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 { | 612 | pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) StackTrace { |
| 611 | const empty_trace: std.builtin.StackTrace = .{ .index = 0, .instruction_addresses = &.{} }; | 613 | const empty_trace: StackTrace = .{ .index = 0, .instruction_addresses = &.{} }; |
| 612 | if (!std.options.allow_stack_tracing) return empty_trace; | 614 | if (!std.options.allow_stack_tracing) return empty_trace; |
| 613 | var it = StackIterator.init(options.context) catch return empty_trace; | 615 | var it = StackIterator.init(options.context) catch return empty_trace; |
| 614 | defer it.deinit(); | 616 | defer it.deinit(); |
| ... | @@ -646,6 +648,9 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: | ... | @@ -646,6 +648,9 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: |
| 646 | /// | 648 | /// |
| 647 | /// See `captureCurrentStackTrace` to capture the trace addresses into a buffer instead of printing. | 649 | /// See `captureCurrentStackTrace` to capture the trace addresses into a buffer instead of printing. |
| 648 | pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_config: tty.Config) Writer.Error!void { | 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 | if (!std.options.allow_stack_tracing) { | 654 | if (!std.options.allow_stack_tracing) { |
| 650 | tty_config.setColor(writer, .dim) catch {}; | 655 | tty_config.setColor(writer, .dim) catch {}; |
| 651 | try writer.print("Cannot print stack trace: stack tracing is disabled\n", .{}); | 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,7 +735,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Wri |
| 730 | } | 735 | } |
| 731 | // `ret_addr` is the return address, which is *after* the function call. | 736 | // `ret_addr` is the return address, which is *after* the function call. |
| 732 | // Subtract 1 to get an address *in* the function call for a better source location. | 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 | printed_any_frame = true; | 739 | printed_any_frame = true; |
| 735 | }, | 740 | }, |
| 736 | }; | 741 | }; |
| ... | @@ -754,14 +759,29 @@ pub fn dumpCurrentStackTrace(options: StackUnwindOptions) void { | ... | @@ -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 | /// Write a previously captured stack trace to `writer`, annotated with source locations. | 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 | if (!std.options.allow_stack_tracing) { | 774 | if (!std.options.allow_stack_tracing) { |
| 760 | tty_config.setColor(writer, .dim) catch {}; | 775 | tty_config.setColor(writer, .dim) catch {}; |
| 761 | try writer.print("Cannot print stack trace: stack tracing is disabled\n", .{}); | 776 | try writer.print("Cannot print stack trace: stack tracing is disabled\n", .{}); |
| 762 | tty_config.setColor(writer, .reset) catch {}; | 777 | tty_config.setColor(writer, .reset) catch {}; |
| 763 | return; | 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 | // Fetch `st.index` straight away. Aside from avoiding redundant loads, this prevents issues if | 785 | // Fetch `st.index` straight away. Aside from avoiding redundant loads, this prevents issues if |
| 766 | // `st` is `@errorReturnTrace()` and errors are encountered while writing the stack trace. | 786 | // `st` is `@errorReturnTrace()` and errors are encountered while writing the stack trace. |
| 767 | const n_frames = st.index; | 787 | const n_frames = st.index; |
| ... | @@ -779,7 +799,7 @@ pub fn writeStackTrace(st: *const std.builtin.StackTrace, writer: *Writer, tty_c | ... | @@ -779,7 +799,7 @@ pub fn writeStackTrace(st: *const std.builtin.StackTrace, writer: *Writer, tty_c |
| 779 | for (st.instruction_addresses[0..captured_frames]) |ret_addr| { | 799 | for (st.instruction_addresses[0..captured_frames]) |ret_addr| { |
| 780 | // `ret_addr` is the return address, which is *after* the function call. | 800 | // `ret_addr` is the return address, which is *after* the function call. |
| 781 | // Subtract 1 to get an address *in* the function call for a better source location. | 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 | if (n_frames > captured_frames) { | 804 | if (n_frames > captured_frames) { |
| 785 | tty_config.setColor(writer, .bold) catch {}; | 805 | tty_config.setColor(writer, .bold) catch {}; |
| ... | @@ -788,7 +808,7 @@ pub fn writeStackTrace(st: *const std.builtin.StackTrace, writer: *Writer, tty_c | ... | @@ -788,7 +808,7 @@ pub fn writeStackTrace(st: *const std.builtin.StackTrace, writer: *Writer, tty_c |
| 788 | } | 808 | } |
| 789 | } | 809 | } |
| 790 | /// A thin wrapper around `writeStackTrace` which writes to stderr and ignores write errors. | 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 | const tty_config = tty.detectConfig(.stderr()); | 812 | const tty_config = tty.detectConfig(.stderr()); |
| 793 | const stderr = lockStderrWriter(&.{}); | 813 | const stderr = lockStderrWriter(&.{}); |
| 794 | defer unlockStderrWriter(); | 814 | defer unlockStderrWriter(); |
| ... | @@ -1075,8 +1095,8 @@ pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize { | ... | @@ -1075,8 +1095,8 @@ pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize { |
| 1075 | return ptr; | 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 { | 1098 | fn printSourceAtAddress(gpa: Allocator, io: Io, 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) { | 1099 | const symbol: Symbol = debug_info.getSymbol(gpa, io, address) catch |err| switch (err) { |
| 1080 | error.MissingDebugInfo, | 1100 | error.MissingDebugInfo, |
| 1081 | error.UnsupportedDebugInfo, | 1101 | error.UnsupportedDebugInfo, |
| 1082 | error.InvalidDebugInfo, | 1102 | error.InvalidDebugInfo, |
| ... | @@ -1581,11 +1601,14 @@ test "manage resources correctly" { | ... | @@ -1581,11 +1601,14 @@ test "manage resources correctly" { |
| 1581 | } | 1601 | } |
| 1582 | }; | 1602 | }; |
| 1583 | const gpa = std.testing.allocator; | 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 | var di: SelfInfo = .init; | 1607 | var di: SelfInfo = .init; |
| 1586 | defer di.deinit(gpa); | 1608 | defer di.deinit(gpa); |
| 1587 | try printSourceAtAddress( | 1609 | try printSourceAtAddress( |
| 1588 | gpa, | 1610 | gpa, |
| 1611 | io, | ||
| 1589 | &di, | 1612 | &di, |
| 1590 | &discarding.writer, | 1613 | &discarding.writer, |
| 1591 | S.showMyTrace(), | 1614 | S.showMyTrace(), |
| ... | @@ -1659,11 +1682,11 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize | ... | @@ -1659,11 +1682,11 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize |
| 1659 | stderr.print("{s}:\n", .{t.notes[i]}) catch return; | 1682 | stderr.print("{s}:\n", .{t.notes[i]}) catch return; |
| 1660 | var frames_array_mutable = frames_array; | 1683 | var frames_array_mutable = frames_array; |
| 1661 | const frames = mem.sliceTo(frames_array_mutable[0..], 0); | 1684 | const frames = mem.sliceTo(frames_array_mutable[0..], 0); |
| 1662 | const stack_trace: std.builtin.StackTrace = .{ | 1685 | const stack_trace: StackTrace = .{ |
| 1663 | .index = frames.len, | 1686 | .index = frames.len, |
| 1664 | .instruction_addresses = frames, | 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 | if (t.index > end) { | 1691 | if (t.index > end) { |
| 1669 | stderr.print("{d} more traces not shown; consider increasing trace size\n", .{ | 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,7 +30,8 @@ pub fn deinit(si: *SelfInfo, gpa: Allocator) void { |
| 30 | si.ofiles.deinit(gpa); | 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 | const module = try si.findModule(gpa, address); | 35 | const module = try si.findModule(gpa, address); |
| 35 | defer si.mutex.unlock(); | 36 | defer si.mutex.unlock(); |
| 36 | 37 | ||
| ... | @@ -970,6 +971,7 @@ fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile { | ... | @@ -970,6 +971,7 @@ fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile { |
| 970 | } | 971 | } |
| 971 | 972 | ||
| 972 | const std = @import("std"); | 973 | const std = @import("std"); |
| 974 | const Io = std.Io; | ||
| 973 | const Allocator = std.mem.Allocator; | 975 | const Allocator = std.mem.Allocator; |
| 974 | const Dwarf = std.debug.Dwarf; | 976 | const Dwarf = std.debug.Dwarf; |
| 975 | const Error = std.debug.SelfInfoError; | 977 | const Error = std.debug.SelfInfoError; |
lib/std/debug/SelfInfo/Windows.zig+2-1| ... | @@ -474,7 +474,7 @@ const Module = struct { | ... | @@ -474,7 +474,7 @@ const Module = struct { |
| 474 | break :pdb pdb; | 474 | break :pdb pdb; |
| 475 | }; | 475 | }; |
| 476 | errdefer if (opt_pdb) |*pdb| { | 476 | errdefer if (opt_pdb) |*pdb| { |
| 477 | pdb.file_reader.file.close(); | 477 | pdb.file_reader.file.close(io); |
| 478 | pdb.deinit(); | 478 | pdb.deinit(); |
| 479 | }; | 479 | }; |
| 480 | 480 | ||
| ... | @@ -484,6 +484,7 @@ const Module = struct { | ... | @@ -484,6 +484,7 @@ const Module = struct { |
| 484 | 484 | ||
| 485 | return .{ | 485 | return .{ |
| 486 | .arena = arena_instance.state, | 486 | .arena = arena_instance.state, |
| 487 | .io = io, | ||
| 487 | .coff_image_base = coff_image_base, | 488 | .coff_image_base = coff_image_base, |
| 488 | .mapped_file = mapped_file, | 489 | .mapped_file = mapped_file, |
| 489 | .dwarf = opt_dwarf, | 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,7 +1062,7 @@ pub fn makeOpenPath(self: Dir, sub_path: []const u8, open_dir_options: OpenOptio |
| 1062 | w.SYNCHRONIZE | w.FILE_TRAVERSE | | 1062 | w.SYNCHRONIZE | w.FILE_TRAVERSE | |
| 1063 | (if (open_dir_options.iterate) w.FILE_LIST_DIRECTORY else @as(u32, 0)); | 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 | else => { | 1067 | else => { |
| 1068 | return self.openDir(sub_path, open_dir_options) catch |err| switch (err) { | 1068 | return self.openDir(sub_path, open_dir_options) catch |err| switch (err) { |
| ... | @@ -1575,8 +1575,7 @@ pub fn symLink( | ... | @@ -1575,8 +1575,7 @@ pub fn symLink( |
| 1575 | // when converting to an NT namespaced path. CreateSymbolicLink in | 1575 | // when converting to an NT namespaced path. CreateSymbolicLink in |
| 1576 | // symLinkW will handle the necessary conversion. | 1576 | // symLinkW will handle the necessary conversion. |
| 1577 | var target_path_w: windows.PathSpace = undefined; | 1577 | var target_path_w: windows.PathSpace = undefined; |
| 1578 | try windows.checkWtf8ToWtf16LeOverflow(target_path, &target_path_w.data); | 1578 | target_path_w.len = try windows.wtf8ToWtf16Le(&target_path_w.data, target_path); |
| 1579 | target_path_w.len = try std.unicode.wtf8ToWtf16Le(&target_path_w.data, target_path); | ||
| 1580 | target_path_w.data[target_path_w.len] = 0; | 1579 | target_path_w.data[target_path_w.len] = 0; |
| 1581 | // However, we need to canonicalize any path separators to `\`, since if | 1580 | // However, we need to canonicalize any path separators to `\`, since if |
| 1582 | // the target path is relative, then it must use `\` as the path separator. | 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,8 +564,8 @@ pub fn updateTimes( |
| 564 | mtime: Io.Timestamp, | 564 | mtime: Io.Timestamp, |
| 565 | ) UpdateTimesError!void { | 565 | ) UpdateTimesError!void { |
| 566 | if (builtin.os.tag == .windows) { | 566 | if (builtin.os.tag == .windows) { |
| 567 | const atime_ft = windows.nanoSecondsToFileTime(atime.nanoseconds); | 567 | const atime_ft = windows.nanoSecondsToFileTime(atime); |
| 568 | const mtime_ft = windows.nanoSecondsToFileTime(mtime.nanoseconds); | 568 | const mtime_ft = windows.nanoSecondsToFileTime(mtime); |
| 569 | return windows.SetFileTime(self.handle, null, &atime_ft, &mtime_ft); | 569 | return windows.SetFileTime(self.handle, null, &atime_ft, &mtime_ft); |
| 570 | } | 570 | } |
| 571 | const times = [2]posix.timespec{ | 571 | const times = [2]posix.timespec{ |
lib/std/heap/debug_allocator.zig+90-19| ... | @@ -80,15 +80,15 @@ | ... | @@ -80,15 +80,15 @@ |
| 80 | //! | 80 | //! |
| 81 | //! Resizing and remapping are forwarded directly to the backing allocator, | 81 | //! Resizing and remapping are forwarded directly to the backing allocator, |
| 82 | //! except where such operations would change the category from large to small. | 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 | const std = @import("std"); | 86 | const std = @import("std"); |
| 85 | const builtin = @import("builtin"); | ||
| 86 | const log = std.log.scoped(.gpa); | 87 | const log = std.log.scoped(.gpa); |
| 87 | const math = std.math; | 88 | const math = std.math; |
| 88 | const assert = std.debug.assert; | 89 | const assert = std.debug.assert; |
| 89 | const mem = std.mem; | 90 | const mem = std.mem; |
| 90 | const Allocator = std.mem.Allocator; | 91 | const Allocator = std.mem.Allocator; |
| 91 | const StackTrace = std.builtin.StackTrace; | ||
| 92 | 92 | ||
| 93 | const default_page_size: usize = switch (builtin.os.tag) { | 93 | const default_page_size: usize = switch (builtin.os.tag) { |
| 94 | // Makes `std.heap.PageAllocator` take the happy path. | 94 | // Makes `std.heap.PageAllocator` take the happy path. |
| ... | @@ -421,7 +421,12 @@ pub fn DebugAllocator(comptime config: Config) type { | ... | @@ -421,7 +421,12 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 421 | return usedBitsCount(slot_count) * @sizeOf(usize); | 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 | const size_class = @as(usize, 1) << @as(Log2USize, @intCast(size_class_index)); | 430 | const size_class = @as(usize, 1) << @as(Log2USize, @intCast(size_class_index)); |
| 426 | const slot_count = slot_counts[size_class_index]; | 431 | const slot_count = slot_counts[size_class_index]; |
| 427 | var leaks: usize = 0; | 432 | var leaks: usize = 0; |
| ... | @@ -436,7 +441,13 @@ pub fn DebugAllocator(comptime config: Config) type { | ... | @@ -436,7 +441,13 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 436 | const stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc); | 441 | const stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc); |
| 437 | const page_addr = @intFromPtr(bucket) & ~(page_size - 1); | 442 | const page_addr = @intFromPtr(bucket) & ~(page_size - 1); |
| 438 | const addr = page_addr + slot_index * size_class; | 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 | leaks += 1; | 451 | leaks += 1; |
| 441 | } | 452 | } |
| 442 | } | 453 | } |
| ... | @@ -449,12 +460,14 @@ pub fn DebugAllocator(comptime config: Config) type { | ... | @@ -449,12 +460,14 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 449 | pub fn detectLeaks(self: *Self) usize { | 460 | pub fn detectLeaks(self: *Self) usize { |
| 450 | var leaks: usize = 0; | 461 | var leaks: usize = 0; |
| 451 | 462 | ||
| 463 | const tty_config = std.Io.tty.detectConfig(.stderr()); | ||
| 464 | |||
| 452 | for (self.buckets, 0..) |init_optional_bucket, size_class_index| { | 465 | for (self.buckets, 0..) |init_optional_bucket, size_class_index| { |
| 453 | var optional_bucket = init_optional_bucket; | 466 | var optional_bucket = init_optional_bucket; |
| 454 | const slot_count = slot_counts[size_class_index]; | 467 | const slot_count = slot_counts[size_class_index]; |
| 455 | const used_bits_count = usedBitsCount(slot_count); | 468 | const used_bits_count = usedBitsCount(slot_count); |
| 456 | while (optional_bucket) |bucket| { | 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 | optional_bucket = bucket.prev; | 471 | optional_bucket = bucket.prev; |
| 459 | } | 472 | } |
| 460 | } | 473 | } |
| ... | @@ -464,7 +477,11 @@ pub fn DebugAllocator(comptime config: Config) type { | ... | @@ -464,7 +477,11 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 464 | if (config.retain_metadata and large_alloc.freed) continue; | 477 | if (config.retain_metadata and large_alloc.freed) continue; |
| 465 | const stack_trace = large_alloc.getStackTrace(.alloc); | 478 | const stack_trace = large_alloc.getStackTrace(.alloc); |
| 466 | log.err("memory address 0x{x} leaked: {f}", .{ | 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 | leaks += 1; | 486 | leaks += 1; |
| 470 | } | 487 | } |
| ... | @@ -519,8 +536,20 @@ pub fn DebugAllocator(comptime config: Config) type { | ... | @@ -519,8 +536,20 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 519 | fn reportDoubleFree(ret_addr: usize, alloc_stack_trace: StackTrace, free_stack_trace: StackTrace) void { | 536 | fn reportDoubleFree(ret_addr: usize, alloc_stack_trace: StackTrace, free_stack_trace: StackTrace) void { |
| 520 | var addr_buf: [stack_n]usize = undefined; | 537 | var addr_buf: [stack_n]usize = undefined; |
| 521 | const second_free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = ret_addr }, &addr_buf); | 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 | log.err("Double free detected. Allocation: {f} First free: {f} Second free: {f}", .{ | 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,11 +590,18 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 561 | if (config.safety and old_mem.len != entry.value_ptr.bytes.len) { | 590 | if (config.safety and old_mem.len != entry.value_ptr.bytes.len) { |
| 562 | var addr_buf: [stack_n]usize = undefined; | 591 | var addr_buf: [stack_n]usize = undefined; |
| 563 | const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = ret_addr }, &addr_buf); | 592 | const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = ret_addr }, &addr_buf); |
| 593 | const tty_config = std.Io.tty.detectConfig(.stderr()); | ||
| 564 | log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ | 594 | log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ |
| 565 | entry.value_ptr.bytes.len, | 595 | entry.value_ptr.bytes.len, |
| 566 | old_mem.len, | 596 | old_mem.len, |
| 567 | entry.value_ptr.getStackTrace(.alloc), | 597 | std.debug.FormatStackTrace{ |
| 568 | free_stack_trace, | 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,11 +703,18 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 667 | if (config.safety and old_mem.len != entry.value_ptr.bytes.len) { | 703 | if (config.safety and old_mem.len != entry.value_ptr.bytes.len) { |
| 668 | var addr_buf: [stack_n]usize = undefined; | 704 | var addr_buf: [stack_n]usize = undefined; |
| 669 | const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = ret_addr }, &addr_buf); | 705 | const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = ret_addr }, &addr_buf); |
| 706 | const tty_config = std.Io.tty.detectConfig(.stderr()); | ||
| 670 | log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ | 707 | log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ |
| 671 | entry.value_ptr.bytes.len, | 708 | entry.value_ptr.bytes.len, |
| 672 | old_mem.len, | 709 | old_mem.len, |
| 673 | entry.value_ptr.getStackTrace(.alloc), | 710 | std.debug.FormatStackTrace{ |
| 674 | free_stack_trace, | 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,19 +935,33 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 892 | var addr_buf: [stack_n]usize = undefined; | 935 | var addr_buf: [stack_n]usize = undefined; |
| 893 | const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = return_address }, &addr_buf); | 936 | const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = return_address }, &addr_buf); |
| 894 | if (old_memory.len != requested_size) { | 937 | if (old_memory.len != requested_size) { |
| 938 | const tty_config = std.Io.tty.detectConfig(.stderr()); | ||
| 895 | log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ | 939 | log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ |
| 896 | requested_size, | 940 | requested_size, |
| 897 | old_memory.len, | 941 | old_memory.len, |
| 898 | bucketStackTrace(bucket, slot_count, slot_index, .alloc), | 942 | std.debug.FormatStackTrace{ |
| 899 | free_stack_trace, | 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 | if (alignment != slot_alignment) { | 952 | if (alignment != slot_alignment) { |
| 953 | const tty_config = std.Io.tty.detectConfig(.stderr()); | ||
| 903 | log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {f} Free: {f}", .{ | 954 | log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {f} Free: {f}", .{ |
| 904 | slot_alignment.toByteUnits(), | 955 | slot_alignment.toByteUnits(), |
| 905 | alignment.toByteUnits(), | 956 | alignment.toByteUnits(), |
| 906 | bucketStackTrace(bucket, slot_count, slot_index, .alloc), | 957 | std.debug.FormatStackTrace{ |
| 907 | free_stack_trace, | 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,19 +1044,33 @@ pub fn DebugAllocator(comptime config: Config) type { |
| 987 | var addr_buf: [stack_n]usize = undefined; | 1044 | var addr_buf: [stack_n]usize = undefined; |
| 988 | const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = return_address }, &addr_buf); | 1045 | const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = return_address }, &addr_buf); |
| 989 | if (memory.len != requested_size) { | 1046 | if (memory.len != requested_size) { |
| 1047 | const tty_config = std.Io.tty.detectConfig(.stderr()); | ||
| 990 | log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ | 1048 | log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ |
| 991 | requested_size, | 1049 | requested_size, |
| 992 | memory.len, | 1050 | memory.len, |
| 993 | bucketStackTrace(bucket, slot_count, slot_index, .alloc), | 1051 | std.debug.FormatStackTrace{ |
| 994 | free_stack_trace, | 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 | if (alignment != slot_alignment) { | 1061 | if (alignment != slot_alignment) { |
| 1062 | const tty_config = std.Io.tty.detectConfig(.stderr()); | ||
| 998 | log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {f} Free: {f}", .{ | 1063 | log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {f} Free: {f}", .{ |
| 999 | slot_alignment.toByteUnits(), | 1064 | slot_alignment.toByteUnits(), |
| 1000 | alignment.toByteUnits(), | 1065 | alignment.toByteUnits(), |
| 1001 | bucketStackTrace(bucket, slot_count, slot_index, .alloc), | 1066 | std.debug.FormatStackTrace{ |
| 1002 | free_stack_trace, | 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,12 +5,14 @@ |
| 5 | //! slices as well as APIs which accept null-terminated WTF16LE byte buffers. | 5 | //! slices as well as APIs which accept null-terminated WTF16LE byte buffers. |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const native_arch = builtin.cpu.arch; | ||
| 9 | |||
| 8 | const std = @import("../std.zig"); | 10 | const std = @import("../std.zig"); |
| 11 | const Io = std.Io; | ||
| 9 | const mem = std.mem; | 12 | const mem = std.mem; |
| 10 | const assert = std.debug.assert; | 13 | const assert = std.debug.assert; |
| 11 | const math = std.math; | 14 | const math = std.math; |
| 12 | const maxInt = std.math.maxInt; | 15 | const maxInt = std.math.maxInt; |
| 13 | const native_arch = builtin.cpu.arch; | ||
| 14 | const UnexpectedError = std.posix.UnexpectedError; | 16 | const UnexpectedError = std.posix.UnexpectedError; |
| 15 | 17 | ||
| 16 | test { | 18 | test { |
| ... | @@ -2219,25 +2221,25 @@ pub fn peb() *PEB { | ... | @@ -2219,25 +2221,25 @@ pub fn peb() *PEB { |
| 2219 | /// Universal Time (UTC). | 2221 | /// Universal Time (UTC). |
| 2220 | /// This function returns the number of nanoseconds since the canonical epoch, | 2222 | /// This function returns the number of nanoseconds since the canonical epoch, |
| 2221 | /// which is the POSIX one (Jan 01, 1970 AD). | 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 | const adjusted_epoch: i128 = hns + std.time.epoch.windows * (std.time.ns_per_s / 100); | 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 { | 2229 | pub fn toSysTime(ns: Io.Timestamp) i64 { |
| 2228 | const hns = @divFloor(ns, 100); | 2230 | const hns = @divFloor(ns.nanoseconds, 100); |
| 2229 | return @as(i64, @intCast(hns)) - std.time.epoch.windows * (std.time.ns_per_s / 100); | 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 | const hns = (@as(i64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime; | 2235 | const hns = (@as(i64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime; |
| 2234 | return fromSysTime(hns); | 2236 | return fromSysTime(hns); |
| 2235 | } | 2237 | } |
| 2236 | 2238 | ||
| 2237 | /// Converts a number of nanoseconds since the POSIX epoch to a Windows FILETIME. | 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 | const adjusted: u64 = @bitCast(toSysTime(ns)); | 2241 | const adjusted: u64 = @bitCast(toSysTime(ns)); |
| 2240 | return FILETIME{ | 2242 | return .{ |
| 2241 | .dwHighDateTime = @as(u32, @truncate(adjusted >> 32)), | 2243 | .dwHighDateTime = @as(u32, @truncate(adjusted >> 32)), |
| 2242 | .dwLowDateTime = @as(u32, @truncate(adjusted)), | 2244 | .dwLowDateTime = @as(u32, @truncate(adjusted)), |
| 2243 | }; | 2245 | }; |
| ... | @@ -5740,11 +5742,15 @@ pub fn ProcessBaseAddress(handle: HANDLE) ProcessBaseAddressError!HMODULE { | ... | @@ -5740,11 +5742,15 @@ pub fn ProcessBaseAddress(handle: HANDLE) ProcessBaseAddressError!HMODULE { |
| 5740 | return ppeb.ImageBaseAddress; | 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 | // Each u8 in UTF-8/WTF-8 correlates to at most one u16 in UTF-16LE/WTF-16LE. | 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; | 5747 | if (wtf16le.len < wtf8.len) { |
| 5746 | const utf16_len = std.unicode.calcUtf16LeLenImpl(wtf8, .can_encode_surrogate_half) catch | 5748 | const utf16_len = std.unicode.calcUtf16LeLenImpl(wtf8, .can_encode_surrogate_half) catch |
| 5747 | return error.BadPathName; | 5749 | return error.BadPathName; |
| 5748 | if (utf16_len > wtf16le.len) | 5750 | if (utf16_len > wtf16le.len) |
| 5749 | return error.NameTooLong; | 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,6 +821,9 @@ pub const ReadError = std.Io.File.ReadStreamingError; |
| 821 | /// The corresponding POSIX limit is `maxInt(isize)`. | 821 | /// The corresponding POSIX limit is `maxInt(isize)`. |
| 822 | pub fn read(fd: fd_t, buf: []u8) ReadError!usize { | 822 | pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 823 | if (buf.len == 0) return 0; | 823 | if (buf.len == 0) return 0; |
| 824 | if (native_os == .windows) { | ||
| 825 | return windows.ReadFile(fd, buf, null); | ||
| 826 | } | ||
| 824 | if (native_os == .wasi and !builtin.link_libc) { | 827 | if (native_os == .wasi and !builtin.link_libc) { |
| 825 | const iovs = [1]iovec{iovec{ | 828 | const iovs = [1]iovec{iovec{ |
| 826 | .base = buf.ptr, | 829 | .base = buf.ptr, |
| ... | @@ -2918,8 +2921,7 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { | ... | @@ -2918,8 +2921,7 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { |
| 2918 | @compileError("WASI does not support os.chdir"); | 2921 | @compileError("WASI does not support os.chdir"); |
| 2919 | } else if (native_os == .windows) { | 2922 | } else if (native_os == .windows) { |
| 2920 | var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined; | 2923 | var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined; |
| 2921 | try windows.checkWtf8ToWtf16LeOverflow(dir_path, &wtf16_dir_path); | 2924 | const len = try windows.wtf8ToWtf16Le(&wtf16_dir_path, dir_path); |
| 2922 | const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path); | ||
| 2923 | return chdirW(wtf16_dir_path[0..len]); | 2925 | return chdirW(wtf16_dir_path[0..len]); |
| 2924 | } else { | 2926 | } else { |
| 2925 | const dir_path_c = try toPosixPath(dir_path); | 2927 | const dir_path_c = try toPosixPath(dir_path); |
| ... | @@ -2935,8 +2937,7 @@ pub fn chdirZ(dir_path: [*:0]const u8) ChangeCurDirError!void { | ... | @@ -2935,8 +2937,7 @@ pub fn chdirZ(dir_path: [*:0]const u8) ChangeCurDirError!void { |
| 2935 | if (native_os == .windows) { | 2937 | if (native_os == .windows) { |
| 2936 | const dir_path_span = mem.span(dir_path); | 2938 | const dir_path_span = mem.span(dir_path); |
| 2937 | var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined; | 2939 | var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined; |
| 2938 | try windows.checkWtf8ToWtf16LeOverflow(dir_path_span, &wtf16_dir_path); | 2940 | const len = try windows.wtf8ToWtf16Le(&wtf16_dir_path, dir_path_span); |
| 2939 | const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path_span); | ||
| 2940 | return chdirW(wtf16_dir_path[0..len]); | 2941 | return chdirW(wtf16_dir_path[0..len]); |
| 2941 | } else if (native_os == .wasi and !builtin.link_libc) { | 2942 | } else if (native_os == .wasi and !builtin.link_libc) { |
| 2942 | return chdir(mem.span(dir_path)); | 2943 | return chdir(mem.span(dir_path)); |
lib/std/posix/test.zig-14| ... | @@ -862,20 +862,6 @@ test "isatty" { | ... | @@ -862,20 +862,6 @@ test "isatty" { |
| 862 | try expectEqual(posix.isatty(file.handle), false); | 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 | test "pread with empty buffer" { | 865 | test "pread with empty buffer" { |
| 880 | var tmp = tmpDir(.{}); | 866 | var tmp = tmpDir(.{}); |
| 881 | defer tmp.cleanup(); | 867 | defer tmp.cleanup(); |
lib/std/testing.zig+5-1| ... | @@ -1148,6 +1148,7 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime | ... | @@ -1148,6 +1148,7 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime |
| 1148 | } else |err| switch (err) { | 1148 | } else |err| switch (err) { |
| 1149 | error.OutOfMemory => { | 1149 | error.OutOfMemory => { |
| 1150 | if (failing_allocator_inst.allocated_bytes != failing_allocator_inst.freed_bytes) { | 1150 | if (failing_allocator_inst.allocated_bytes != failing_allocator_inst.freed_bytes) { |
| 1151 | const tty_config = std.Io.tty.detectConfig(.stderr()); | ||
| 1151 | print( | 1152 | print( |
| 1152 | "\nfail_index: {d}/{d}\nallocated bytes: {d}\nfreed bytes: {d}\nallocations: {d}\ndeallocations: {d}\nallocation that was made to fail: {f}", | 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,7 +1158,10 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime |
| 1157 | failing_allocator_inst.freed_bytes, | 1158 | failing_allocator_inst.freed_bytes, |
| 1158 | failing_allocator_inst.allocations, | 1159 | failing_allocator_inst.allocations, |
| 1159 | failing_allocator_inst.deallocations, | 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 | return error.MemoryLeakDetected; | 1167 | return error.MemoryLeakDetected; |
tools/incr-check.zig+13-6| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const Io = std.Io; | ||
| 2 | const Allocator = std.mem.Allocator; | 3 | const Allocator = std.mem.Allocator; |
| 3 | const Cache = std.Build.Cache; | 4 | const Cache = std.Build.Cache; |
| 4 | 5 | ||
| ... | @@ -11,6 +12,12 @@ pub fn main() !void { | ... | @@ -11,6 +12,12 @@ pub fn main() !void { |
| 11 | defer arena_instance.deinit(); | 12 | defer arena_instance.deinit(); |
| 12 | const arena = arena_instance.allocator(); | 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 | var opt_zig_exe: ?[]const u8 = null; | 21 | var opt_zig_exe: ?[]const u8 = null; |
| 15 | var opt_input_file_name: ?[]const u8 = null; | 22 | var opt_input_file_name: ?[]const u8 = null; |
| 16 | var opt_lib_dir: ?[]const u8 = null; | 23 | var opt_lib_dir: ?[]const u8 = null; |
| ... | @@ -53,7 +60,7 @@ pub fn main() !void { | ... | @@ -53,7 +60,7 @@ pub fn main() !void { |
| 53 | const input_file_name = opt_input_file_name orelse fatal("missing input file\n{s}", .{usage}); | 60 | const input_file_name = opt_input_file_name orelse fatal("missing input file\n{s}", .{usage}); |
| 54 | 61 | ||
| 55 | const input_file_bytes = try std.fs.cwd().readFileAlloc(input_file_name, arena, .limited(std.math.maxInt(u32))); | 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 | // Check now: if there are any targets using the `cbe` backend, we need the lib dir. | 65 | // Check now: if there are any targets using the `cbe` backend, we need the lib dir. |
| 59 | if (opt_lib_dir == null) { | 66 | if (opt_lib_dir == null) { |
| ... | @@ -86,7 +93,7 @@ pub fn main() !void { | ... | @@ -86,7 +93,7 @@ pub fn main() !void { |
| 86 | else | 93 | else |
| 87 | null; | 94 | null; |
| 88 | 95 | ||
| 89 | const host = try std.zig.system.resolveTargetQuery(.{}); | 96 | const host = try std.zig.system.resolveTargetQuery(io, .{}); |
| 90 | 97 | ||
| 91 | const debug_log_verbose = debug_zcu or debug_dwarf or debug_link; | 98 | const debug_log_verbose = debug_zcu or debug_dwarf or debug_link; |
| 92 | 99 | ||
| ... | @@ -186,7 +193,7 @@ pub fn main() !void { | ... | @@ -186,7 +193,7 @@ pub fn main() !void { |
| 186 | 193 | ||
| 187 | try child.spawn(); | 194 | try child.spawn(); |
| 188 | 195 | ||
| 189 | var poller = std.Io.poll(arena, Eval.StreamEnum, .{ | 196 | var poller = Io.poll(arena, Eval.StreamEnum, .{ |
| 190 | .stdout = child.stdout.?, | 197 | .stdout = child.stdout.?, |
| 191 | .stderr = child.stderr.?, | 198 | .stderr = child.stderr.?, |
| 192 | }); | 199 | }); |
| ... | @@ -226,7 +233,7 @@ const Eval = struct { | ... | @@ -226,7 +233,7 @@ const Eval = struct { |
| 226 | cc_child_args: *std.ArrayListUnmanaged([]const u8), | 233 | cc_child_args: *std.ArrayListUnmanaged([]const u8), |
| 227 | 234 | ||
| 228 | const StreamEnum = enum { stdout, stderr }; | 235 | const StreamEnum = enum { stdout, stderr }; |
| 229 | const Poller = std.Io.Poller(StreamEnum); | 236 | const Poller = Io.Poller(StreamEnum); |
| 230 | 237 | ||
| 231 | /// Currently this function assumes the previous updates have already been written. | 238 | /// Currently this function assumes the previous updates have already been written. |
| 232 | fn write(eval: *Eval, update: Case.Update) void { | 239 | fn write(eval: *Eval, update: Case.Update) void { |
| ... | @@ -647,7 +654,7 @@ const Case = struct { | ... | @@ -647,7 +654,7 @@ const Case = struct { |
| 647 | msg: []const u8, | 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 | const fatal = std.process.fatal; | 658 | const fatal = std.process.fatal; |
| 652 | 659 | ||
| 653 | var targets: std.ArrayListUnmanaged(Target) = .empty; | 660 | var targets: std.ArrayListUnmanaged(Target) = .empty; |
| ... | @@ -683,7 +690,7 @@ const Case = struct { | ... | @@ -683,7 +690,7 @@ const Case = struct { |
| 683 | }, | 690 | }, |
| 684 | }) catch fatal("line {d}: invalid target query '{s}'", .{ line_n, query }); | 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 | try targets.append(arena, .{ | 695 | try targets.append(arena, .{ |
| 689 | .query = query, | 696 | .query = query, |