authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-19 14:08:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:50-07:00
log10b1eef2d3901d17cf8810689a9e1eaf6d7901d9
treec5312175f5f2716813322196dc10cdabf6b73f51
parentb215f8667a0cc59888926fcfcbb4be4370bd2216

std: fix compilation errors on Windows


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 {
332pub fn dump(step: *Step, w: *Io.Writer, tty_config: Io.tty.Config) void {332pub 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;
31const splat_buffer_size = 64;31const splat_buffer_size = 64;
3232
33comptime {33comptime {
34 assert(max_iovecs_len <= posix.IOV_MAX);34 if (@TypeOf(posix.IOV_MAX) != void) assert(max_iovecs_len <= posix.IOV_MAX);
35}35}
3636
37const Closure = struct {37const Closure = struct {
...@@ -91,9 +91,7 @@ pub fn init(...@@ -91,9 +91,7 @@ pub fn init(
9191
92/// Statically initialize such that any call to the following functions will92/// 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.
98pub const init_single_threaded: Threaded = .{96pub 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 };
583583
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: {
37pub const StackTrace = struct {37pub 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};
5441
55/// This data structure is used by the Zig language code generation and42/// 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 @@
1const std = @import("std.zig");1const std = @import("std.zig");
2const Io = std.Io;
3const Writer = std.Io.Writer;
4const tty = std.Io.tty;
2const math = std.math;5const math = std.math;
3const mem = std.mem;6const mem = std.mem;
4const posix = std.posix;7const posix = std.posix;
...@@ -7,12 +10,11 @@ const testing = std.testing;...@@ -7,12 +10,11 @@ const testing = std.testing;
7const Allocator = mem.Allocator;10const Allocator = mem.Allocator;
8const File = std.fs.File;11const File = std.fs.File;
9const windows = std.os.windows;12const windows = std.os.windows;
10const Writer = std.Io.Writer;
11const tty = std.Io.tty;
1213
13const builtin = @import("builtin");14const builtin = @import("builtin");
14const native_arch = builtin.cpu.arch;15const native_arch = builtin.cpu.arch;
15const native_os = builtin.os.tag;16const native_os = builtin.os.tag;
17const StackTrace = std.builtin.StackTrace;
1618
17const root = @import("root");19const root = @import("root");
1820
...@@ -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;
551553
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.
610pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) std.builtin.StackTrace {612pub 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.
648pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_config: tty.Config) Writer.Error!void {650pub 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}
756761
762pub 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.
758pub fn writeStackTrace(st: *const std.builtin.StackTrace, writer: *Writer, tty_config: tty.Config) Writer.Error!void {773pub 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 if785 // 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.
791pub fn dumpStackTrace(st: *const std.builtin.StackTrace) void {811pub 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}
10771097
1078fn printSourceAtAddress(gpa: Allocator, debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: tty.Config) Writer.Error!void {1098fn 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}
3232
33pub fn getSymbol(si: *SelfInfo, gpa: Allocator, address: usize) Error!std.debug.Symbol {33pub 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();
3637
...@@ -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}
971972
972const std = @import("std");973const std = @import("std");
974const Io = std.Io;
973const Allocator = std.mem.Allocator;975const Allocator = std.mem.Allocator;
974const Dwarf = std.debug.Dwarf;976const Dwarf = std.debug.Dwarf;
975const Error = std.debug.SelfInfoError;977const 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 };
480480
...@@ -484,6 +484,7 @@ const Module = struct {...@@ -484,6 +484,7 @@ const Module = struct {
484484
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));
10641064
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 in1575 // 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 if1580 // 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.
83const builtin = @import("builtin");
84const StackTrace = std.builtin.StackTrace;
8385
84const std = @import("std");86const std = @import("std");
85const builtin = @import("builtin");
86const log = std.log.scoped(.gpa);87const log = std.log.scoped(.gpa);
87const math = std.math;88const math = std.math;
88const assert = std.debug.assert;89const assert = std.debug.assert;
89const mem = std.mem;90const mem = std.mem;
90const Allocator = std.mem.Allocator;91const Allocator = std.mem.Allocator;
91const StackTrace = std.builtin.StackTrace;
9292
93const default_page_size: usize = switch (builtin.os.tag) {93const 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 }
423423
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;
451462
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 }
526555
...@@ -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 }
571607
...@@ -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 }
677720
...@@ -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.
66
7const builtin = @import("builtin");7const builtin = @import("builtin");
8const native_arch = builtin.cpu.arch;
9
8const std = @import("../std.zig");10const std = @import("../std.zig");
11const Io = std.Io;
9const mem = std.mem;12const mem = std.mem;
10const assert = std.debug.assert;13const assert = std.debug.assert;
11const math = std.math;14const math = std.math;
12const maxInt = std.math.maxInt;15const maxInt = std.math.maxInt;
13const native_arch = builtin.cpu.arch;
14const UnexpectedError = std.posix.UnexpectedError;16const UnexpectedError = std.posix.UnexpectedError;
1517
16test {18test {
...@@ -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).
2222pub fn fromSysTime(hns: i64) i128 {2224pub 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}
22262228
2227pub fn toSysTime(ns: i128) i64 {2229pub 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}
22312233
2232pub fn fileTimeToNanoSeconds(ft: FILETIME) i128 {2234pub 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}
22362238
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.
2238pub fn nanoSecondsToFileTime(ns: i128) FILETIME {2240pub 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}
57425744
5743pub fn checkWtf8ToWtf16LeOverflow(wtf8: []const u8, wtf16le: []const u16) error{ BadPathName, NameTooLong }!void {5745pub 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) catch5748 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)`.
822pub fn read(fd: fd_t, buf: []u8) ReadError!usize {822pub 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}
864864
865test "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
879test "pread with empty buffer" {865test "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 @@
1const std = @import("std");1const std = @import("std");
2const Io = std.Io;
2const Allocator = std.mem.Allocator;3const Allocator = std.mem.Allocator;
3const Cache = std.Build.Cache;4const Cache = std.Build.Cache;
45
...@@ -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();
1314
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});
5461
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);
5764
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 else93 else
87 null;94 null;
8895
89 const host = try std.zig.system.resolveTargetQuery(.{});96 const host = try std.zig.system.resolveTargetQuery(io, .{});
9097
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;
9299
...@@ -186,7 +193,7 @@ pub fn main() !void {...@@ -186,7 +193,7 @@ pub fn main() !void {
186193
187 try child.spawn();194 try child.spawn();
188195
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),
227234
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);
230237
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 };
649656
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;
652659
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 });
685692
686 const resolved = try std.zig.system.resolveTargetQuery(parsed_query);693 const resolved = try std.zig.system.resolveTargetQuery(io, parsed_query);
687694
688 try targets.append(arena, .{695 try targets.append(arena, .{
689 .query = query,696 .query = query,