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 {
148148 error.SkipZigTest => .skip,
149149 else => s: {
150150 if (@errorReturnTrace()) |trace| {
151 std.debug.dumpStackTrace(trace);
151 std.debug.dumpStackTrace(trace.*);
152152 }
153153 break :s .fail;
154154 },
......@@ -269,7 +269,7 @@ fn mainTerminal() void {
269269 std.debug.print("FAIL ({t})\n", .{err});
270270 }
271271 if (@errorReturnTrace()) |trace| {
272 std.debug.dumpStackTrace(trace);
272 std.debug.dumpStackTrace(trace.*);
273273 }
274274 test_node.end();
275275 },
lib/std/Build/Step.zig+1-1
......@@ -332,7 +332,7 @@ pub fn cast(step: *Step, comptime T: type) ?*T {
332332pub fn dump(step: *Step, w: *Io.Writer, tty_config: Io.tty.Config) void {
333333 if (step.debug_stack_trace.instruction_addresses.len > 0) {
334334 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 {};
336336 } else {
337337 const field = "debug_stack_frames_count";
338338 comptime assert(@hasField(Build, field));
lib/std/Io/Threaded.zig+1-3
......@@ -31,7 +31,7 @@ const max_iovecs_len = 8;
3131const splat_buffer_size = 64;
3232
3333comptime {
34 assert(max_iovecs_len <= posix.IOV_MAX);
34 if (@TypeOf(posix.IOV_MAX) != void) assert(max_iovecs_len <= posix.IOV_MAX);
3535}
3636
3737const Closure = struct {
......@@ -91,9 +91,7 @@ pub fn init(
9191
9292/// Statically initialize such that any call to the following functions will
9393/// fail with `error.OutOfMemory`:
94/// * `Io.VTable.async`
9594/// * `Io.VTable.concurrent`
96/// * `Io.VTable.groupAsync`
9795/// When initialized this way, `deinit` is safe, but unnecessary to call.
9896pub const init_single_threaded: Threaded = .{
9997 .allocator = .failing,
lib/std/Io/net/HostName.zig+1-1
......@@ -221,7 +221,7 @@ pub fn connect(
221221 defer {
222222 connect_many.cancel(io);
223223 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,
225225 .end => break,
226226 };
227227 }
lib/std/Thread.zig+1-1
......@@ -577,7 +577,7 @@ fn callFn(comptime f: anytype, args: anytype) switch (Impl) {
577577 @call(.auto, f, args) catch |err| {
578578 std.debug.print("error: {s}\n", .{@errorName(err)});
579579 if (@errorReturnTrace()) |trace| {
580 std.debug.dumpStackTrace(trace);
580 std.debug.dumpStackTrace(trace.*);
581581 }
582582 };
583583
lib/std/builtin.zig-13
......@@ -37,19 +37,6 @@ pub const subsystem: ?std.Target.SubSystem = blk: {
3737pub const StackTrace = struct {
3838 index: usize,
3939 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 }
5340};
5441
5542/// This data structure is used by the Zig language code generation and
lib/std/debug.zig+38-15
......@@ -1,4 +1,7 @@
11const std = @import("std.zig");
2const Io = std.Io;
3const Writer = std.Io.Writer;
4const tty = std.Io.tty;
25const math = std.math;
36const mem = std.mem;
47const posix = std.posix;
......@@ -7,12 +10,11 @@ const testing = std.testing;
710const Allocator = mem.Allocator;
811const File = std.fs.File;
912const windows = std.os.windows;
10const Writer = std.Io.Writer;
11const tty = std.Io.tty;
1213
1314const builtin = @import("builtin");
1415const native_arch = builtin.cpu.arch;
1516const native_os = builtin.os.tag;
17const StackTrace = std.builtin.StackTrace;
1618
1719const root = @import("root");
1820
......@@ -545,13 +547,13 @@ pub fn defaultPanic(
545547 stderr.print("panic: ", .{}) catch break :trace;
546548 } else {
547549 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;
549551 }
550552 stderr.print("{s}\n", .{msg}) catch break :trace;
551553
552554 if (@errorReturnTrace()) |t| if (t.index > 0) {
553555 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;
555557 stderr.writeAll("\nstack trace:\n") catch break :trace;
556558 };
557559 writeCurrentStackTrace(.{
......@@ -607,8 +609,8 @@ pub const StackUnwindOptions = struct {
607609/// the given buffer, so `addr_buf` must have a lifetime at least equal to the `StackTrace`.
608610///
609611/// See `writeCurrentStackTrace` to immediately print the trace instead of capturing it.
610pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) std.builtin.StackTrace {
611 const empty_trace: std.builtin.StackTrace = .{ .index = 0, .instruction_addresses = &.{} };
612pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) StackTrace {
613 const empty_trace: StackTrace = .{ .index = 0, .instruction_addresses = &.{} };
612614 if (!std.options.allow_stack_tracing) return empty_trace;
613615 var it = StackIterator.init(options.context) catch return empty_trace;
614616 defer it.deinit();
......@@ -646,6 +648,9 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf:
646648///
647649/// See `captureCurrentStackTrace` to capture the trace addresses into a buffer instead of printing.
648650pub 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
649654 if (!std.options.allow_stack_tracing) {
650655 tty_config.setColor(writer, .dim) catch {};
651656 try writer.print("Cannot print stack trace: stack tracing is disabled\n", .{});
......@@ -730,7 +735,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Wri
730735 }
731736 // `ret_addr` is the return address, which is *after* the function call.
732737 // 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);
734739 printed_any_frame = true;
735740 },
736741 };
......@@ -754,14 +759,29 @@ pub fn dumpCurrentStackTrace(options: StackUnwindOptions) void {
754759 };
755760}
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
757772/// 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 {
759774 if (!std.options.allow_stack_tracing) {
760775 tty_config.setColor(writer, .dim) catch {};
761776 try writer.print("Cannot print stack trace: stack tracing is disabled\n", .{});
762777 tty_config.setColor(writer, .reset) catch {};
763778 return;
764779 }
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
765785 // Fetch `st.index` straight away. Aside from avoiding redundant loads, this prevents issues if
766786 // `st` is `@errorReturnTrace()` and errors are encountered while writing the stack trace.
767787 const n_frames = st.index;
......@@ -779,7 +799,7 @@ pub fn writeStackTrace(st: *const std.builtin.StackTrace, writer: *Writer, tty_c
779799 for (st.instruction_addresses[0..captured_frames]) |ret_addr| {
780800 // `ret_addr` is the return address, which is *after* the function call.
781801 // 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);
783803 }
784804 if (n_frames > captured_frames) {
785805 tty_config.setColor(writer, .bold) catch {};
......@@ -788,7 +808,7 @@ pub fn writeStackTrace(st: *const std.builtin.StackTrace, writer: *Writer, tty_c
788808 }
789809}
790810/// 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 {
792812 const tty_config = tty.detectConfig(.stderr());
793813 const stderr = lockStderrWriter(&.{});
794814 defer unlockStderrWriter();
......@@ -1075,8 +1095,8 @@ pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize {
10751095 return ptr;
10761096}
10771097
1078fn printSourceAtAddress(gpa: Allocator, debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: tty.Config) Writer.Error!void {
1079 const symbol: Symbol = debug_info.getSymbol(gpa, address) catch |err| switch (err) {
1098fn printSourceAtAddress(gpa: Allocator, io: Io, debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: tty.Config) Writer.Error!void {
1099 const symbol: Symbol = debug_info.getSymbol(gpa, io, address) catch |err| switch (err) {
10801100 error.MissingDebugInfo,
10811101 error.UnsupportedDebugInfo,
10821102 error.InvalidDebugInfo,
......@@ -1581,11 +1601,14 @@ test "manage resources correctly" {
15811601 }
15821602 };
15831603 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(&.{});
15851607 var di: SelfInfo = .init;
15861608 defer di.deinit(gpa);
15871609 try printSourceAtAddress(
15881610 gpa,
1611 io,
15891612 &di,
15901613 &discarding.writer,
15911614 S.showMyTrace(),
......@@ -1659,11 +1682,11 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize
16591682 stderr.print("{s}:\n", .{t.notes[i]}) catch return;
16601683 var frames_array_mutable = frames_array;
16611684 const frames = mem.sliceTo(frames_array_mutable[0..], 0);
1662 const stack_trace: std.builtin.StackTrace = .{
1685 const stack_trace: StackTrace = .{
16631686 .index = frames.len,
16641687 .instruction_addresses = frames,
16651688 };
1666 writeStackTrace(&stack_trace, stderr, tty_config) catch return;
1689 writeStackTrace(stack_trace, stderr, tty_config) catch return;
16671690 }
16681691 if (t.index > end) {
16691692 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 {
3030 si.ofiles.deinit(gpa);
3131}
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;
3435 const module = try si.findModule(gpa, address);
3536 defer si.mutex.unlock();
3637
......@@ -970,6 +971,7 @@ fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile {
970971}
971972
972973const std = @import("std");
974const Io = std.Io;
973975const Allocator = std.mem.Allocator;
974976const Dwarf = std.debug.Dwarf;
975977const Error = std.debug.SelfInfoError;
lib/std/debug/SelfInfo/Windows.zig+2-1
......@@ -474,7 +474,7 @@ const Module = struct {
474474 break :pdb pdb;
475475 };
476476 errdefer if (opt_pdb) |*pdb| {
477 pdb.file_reader.file.close();
477 pdb.file_reader.file.close(io);
478478 pdb.deinit();
479479 };
480480
......@@ -484,6 +484,7 @@ const Module = struct {
484484
485485 return .{
486486 .arena = arena_instance.state,
487 .io = io,
487488 .coff_image_base = coff_image_base,
488489 .mapped_file = mapped_file,
489490 .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
10621062 w.SYNCHRONIZE | w.FILE_TRAVERSE |
10631063 (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);
10661066 },
10671067 else => {
10681068 return self.openDir(sub_path, open_dir_options) catch |err| switch (err) {
......@@ -1575,8 +1575,7 @@ pub fn symLink(
15751575 // when converting to an NT namespaced path. CreateSymbolicLink in
15761576 // symLinkW will handle the necessary conversion.
15771577 var target_path_w: windows.PathSpace = undefined;
1578 try windows.checkWtf8ToWtf16LeOverflow(target_path, &target_path_w.data);
1579 target_path_w.len = try std.unicode.wtf8ToWtf16Le(&target_path_w.data, target_path);
1578 target_path_w.len = try windows.wtf8ToWtf16Le(&target_path_w.data, target_path);
15801579 target_path_w.data[target_path_w.len] = 0;
15811580 // However, we need to canonicalize any path separators to `\`, since if
15821581 // 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(
564564 mtime: Io.Timestamp,
565565) UpdateTimesError!void {
566566 if (builtin.os.tag == .windows) {
567 const atime_ft = windows.nanoSecondsToFileTime(atime.nanoseconds);
568 const mtime_ft = windows.nanoSecondsToFileTime(mtime.nanoseconds);
567 const atime_ft = windows.nanoSecondsToFileTime(atime);
568 const mtime_ft = windows.nanoSecondsToFileTime(mtime);
569569 return windows.SetFileTime(self.handle, null, &atime_ft, &mtime_ft);
570570 }
571571 const times = [2]posix.timespec{
lib/std/heap/debug_allocator.zig+90-19
......@@ -80,15 +80,15 @@
8080//!
8181//! Resizing and remapping are forwarded directly to the backing allocator,
8282//! except where such operations would change the category from large to small.
83const builtin = @import("builtin");
84const StackTrace = std.builtin.StackTrace;
8385
8486const std = @import("std");
85const builtin = @import("builtin");
8687const log = std.log.scoped(.gpa);
8788const math = std.math;
8889const assert = std.debug.assert;
8990const mem = std.mem;
9091const Allocator = std.mem.Allocator;
91const StackTrace = std.builtin.StackTrace;
9292
9393const default_page_size: usize = switch (builtin.os.tag) {
9494 // Makes `std.heap.PageAllocator` take the happy path.
......@@ -421,7 +421,12 @@ pub fn DebugAllocator(comptime config: Config) type {
421421 return usedBitsCount(slot_count) * @sizeOf(usize);
422422 }
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 {
425430 const size_class = @as(usize, 1) << @as(Log2USize, @intCast(size_class_index));
426431 const slot_count = slot_counts[size_class_index];
427432 var leaks: usize = 0;
......@@ -436,7 +441,13 @@ pub fn DebugAllocator(comptime config: Config) type {
436441 const stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc);
437442 const page_addr = @intFromPtr(bucket) & ~(page_size - 1);
438443 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 });
440451 leaks += 1;
441452 }
442453 }
......@@ -449,12 +460,14 @@ pub fn DebugAllocator(comptime config: Config) type {
449460 pub fn detectLeaks(self: *Self) usize {
450461 var leaks: usize = 0;
451462
463 const tty_config = std.Io.tty.detectConfig(.stderr());
464
452465 for (self.buckets, 0..) |init_optional_bucket, size_class_index| {
453466 var optional_bucket = init_optional_bucket;
454467 const slot_count = slot_counts[size_class_index];
455468 const used_bits_count = usedBitsCount(slot_count);
456469 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);
458471 optional_bucket = bucket.prev;
459472 }
460473 }
......@@ -464,7 +477,11 @@ pub fn DebugAllocator(comptime config: Config) type {
464477 if (config.retain_metadata and large_alloc.freed) continue;
465478 const stack_trace = large_alloc.getStackTrace(.alloc);
466479 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 },
468485 });
469486 leaks += 1;
470487 }
......@@ -519,8 +536,20 @@ pub fn DebugAllocator(comptime config: Config) type {
519536 fn reportDoubleFree(ret_addr: usize, alloc_stack_trace: StackTrace, free_stack_trace: StackTrace) void {
520537 var addr_buf: [stack_n]usize = undefined;
521538 const second_free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = ret_addr }, &addr_buf);
539 const tty_config = std.Io.tty.detectConfig(.stderr());
522540 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 },
524553 });
525554 }
526555
......@@ -561,11 +590,18 @@ pub fn DebugAllocator(comptime config: Config) type {
561590 if (config.safety and old_mem.len != entry.value_ptr.bytes.len) {
562591 var addr_buf: [stack_n]usize = undefined;
563592 const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = ret_addr }, &addr_buf);
593 const tty_config = std.Io.tty.detectConfig(.stderr());
564594 log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{
565595 entry.value_ptr.bytes.len,
566596 old_mem.len,
567 entry.value_ptr.getStackTrace(.alloc),
568 free_stack_trace,
597 std.debug.FormatStackTrace{
598 .stack_trace = entry.value_ptr.getStackTrace(.alloc),
599 .tty_config = tty_config,
600 },
601 std.debug.FormatStackTrace{
602 .stack_trace = free_stack_trace,
603 .tty_config = tty_config,
604 },
569605 });
570606 }
571607
......@@ -667,11 +703,18 @@ pub fn DebugAllocator(comptime config: Config) type {
667703 if (config.safety and old_mem.len != entry.value_ptr.bytes.len) {
668704 var addr_buf: [stack_n]usize = undefined;
669705 const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = ret_addr }, &addr_buf);
706 const tty_config = std.Io.tty.detectConfig(.stderr());
670707 log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{
671708 entry.value_ptr.bytes.len,
672709 old_mem.len,
673 entry.value_ptr.getStackTrace(.alloc),
674 free_stack_trace,
710 std.debug.FormatStackTrace{
711 .stack_trace = entry.value_ptr.getStackTrace(.alloc),
712 .tty_config = tty_config,
713 },
714 std.debug.FormatStackTrace{
715 .stack_trace = free_stack_trace,
716 .tty_config = tty_config,
717 },
675718 });
676719 }
677720
......@@ -892,19 +935,33 @@ pub fn DebugAllocator(comptime config: Config) type {
892935 var addr_buf: [stack_n]usize = undefined;
893936 const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = return_address }, &addr_buf);
894937 if (old_memory.len != requested_size) {
938 const tty_config = std.Io.tty.detectConfig(.stderr());
895939 log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{
896940 requested_size,
897941 old_memory.len,
898 bucketStackTrace(bucket, slot_count, slot_index, .alloc),
899 free_stack_trace,
942 std.debug.FormatStackTrace{
943 .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc),
944 .tty_config = tty_config,
945 },
946 std.debug.FormatStackTrace{
947 .stack_trace = free_stack_trace,
948 .tty_config = tty_config,
949 },
900950 });
901951 }
902952 if (alignment != slot_alignment) {
953 const tty_config = std.Io.tty.detectConfig(.stderr());
903954 log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {f} Free: {f}", .{
904955 slot_alignment.toByteUnits(),
905956 alignment.toByteUnits(),
906 bucketStackTrace(bucket, slot_count, slot_index, .alloc),
907 free_stack_trace,
957 std.debug.FormatStackTrace{
958 .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc),
959 .tty_config = tty_config,
960 },
961 std.debug.FormatStackTrace{
962 .stack_trace = free_stack_trace,
963 .tty_config = tty_config,
964 },
908965 });
909966 }
910967 }
......@@ -987,19 +1044,33 @@ pub fn DebugAllocator(comptime config: Config) type {
9871044 var addr_buf: [stack_n]usize = undefined;
9881045 const free_stack_trace = std.debug.captureCurrentStackTrace(.{ .first_address = return_address }, &addr_buf);
9891046 if (memory.len != requested_size) {
1047 const tty_config = std.Io.tty.detectConfig(.stderr());
9901048 log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{
9911049 requested_size,
9921050 memory.len,
993 bucketStackTrace(bucket, slot_count, slot_index, .alloc),
994 free_stack_trace,
1051 std.debug.FormatStackTrace{
1052 .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc),
1053 .tty_config = tty_config,
1054 },
1055 std.debug.FormatStackTrace{
1056 .stack_trace = free_stack_trace,
1057 .tty_config = tty_config,
1058 },
9951059 });
9961060 }
9971061 if (alignment != slot_alignment) {
1062 const tty_config = std.Io.tty.detectConfig(.stderr());
9981063 log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {f} Free: {f}", .{
9991064 slot_alignment.toByteUnits(),
10001065 alignment.toByteUnits(),
1001 bucketStackTrace(bucket, slot_count, slot_index, .alloc),
1002 free_stack_trace,
1066 std.debug.FormatStackTrace{
1067 .stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc),
1068 .tty_config = tty_config,
1069 },
1070 std.debug.FormatStackTrace{
1071 .stack_trace = free_stack_trace,
1072 .tty_config = tty_config,
1073 },
10031074 });
10041075 }
10051076 }
lib/std/os/windows.zig+20-14
......@@ -5,12 +5,14 @@
55//! slices as well as APIs which accept null-terminated WTF16LE byte buffers.
66
77const builtin = @import("builtin");
8const native_arch = builtin.cpu.arch;
9
810const std = @import("../std.zig");
11const Io = std.Io;
912const mem = std.mem;
1013const assert = std.debug.assert;
1114const math = std.math;
1215const maxInt = std.math.maxInt;
13const native_arch = builtin.cpu.arch;
1416const UnexpectedError = std.posix.UnexpectedError;
1517
1618test {
......@@ -2219,25 +2221,25 @@ pub fn peb() *PEB {
22192221/// Universal Time (UTC).
22202222/// This function returns the number of nanoseconds since the canonical epoch,
22212223/// which is the POSIX one (Jan 01, 1970 AD).
2222pub fn fromSysTime(hns: i64) i128 {
2224pub fn fromSysTime(hns: i64) Io.Timestamp {
22232225 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));
22252227}
22262228
2227pub fn toSysTime(ns: i128) i64 {
2228 const hns = @divFloor(ns, 100);
2229pub fn toSysTime(ns: Io.Timestamp) i64 {
2230 const hns = @divFloor(ns.nanoseconds, 100);
22292231 return @as(i64, @intCast(hns)) - std.time.epoch.windows * (std.time.ns_per_s / 100);
22302232}
22312233
2232pub fn fileTimeToNanoSeconds(ft: FILETIME) i128 {
2234pub fn fileTimeToNanoSeconds(ft: FILETIME) Io.Timestamp {
22332235 const hns = (@as(i64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
22342236 return fromSysTime(hns);
22352237}
22362238
22372239/// 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 {
22392241 const adjusted: u64 = @bitCast(toSysTime(ns));
2240 return FILETIME{
2242 return .{
22412243 .dwHighDateTime = @as(u32, @truncate(adjusted >> 32)),
22422244 .dwLowDateTime = @as(u32, @truncate(adjusted)),
22432245 };
......@@ -5740,11 +5742,15 @@ pub fn ProcessBaseAddress(handle: HANDLE) ProcessBaseAddressError!HMODULE {
57405742 return ppeb.ImageBaseAddress;
57415743}
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 {
57445746 // Each u8 in UTF-8/WTF-8 correlates to at most one u16 in UTF-16LE/WTF-16LE.
5745 if (wtf16le.len >= wtf8.len) return;
5746 const utf16_len = std.unicode.calcUtf16LeLenImpl(wtf8, .can_encode_surrogate_half) catch
5747 return error.BadPathName;
5748 if (utf16_len > wtf16le.len)
5749 return error.NameTooLong;
5747 if (wtf16le.len < wtf8.len) {
5748 const utf16_len = std.unicode.calcUtf16LeLenImpl(wtf8, .can_encode_surrogate_half) catch
5749 return error.BadPathName;
5750 if (utf16_len > wtf16le.len)
5751 return error.NameTooLong;
5752 }
5753 return std.unicode.wtf8ToWtf16Le(wtf16le, wtf8) catch |err| switch (err) {
5754 error.InvalidWtf8 => return error.BadPathName,
5755 };
57505756}
lib/std/posix.zig+5-4
......@@ -821,6 +821,9 @@ pub const ReadError = std.Io.File.ReadStreamingError;
821821/// The corresponding POSIX limit is `maxInt(isize)`.
822822pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
823823 if (buf.len == 0) return 0;
824 if (native_os == .windows) {
825 return windows.ReadFile(fd, buf, null);
826 }
824827 if (native_os == .wasi and !builtin.link_libc) {
825828 const iovs = [1]iovec{iovec{
826829 .base = buf.ptr,
......@@ -2918,8 +2921,7 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
29182921 @compileError("WASI does not support os.chdir");
29192922 } else if (native_os == .windows) {
29202923 var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined;
2921 try windows.checkWtf8ToWtf16LeOverflow(dir_path, &wtf16_dir_path);
2922 const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path);
2924 const len = try windows.wtf8ToWtf16Le(&wtf16_dir_path, dir_path);
29232925 return chdirW(wtf16_dir_path[0..len]);
29242926 } else {
29252927 const dir_path_c = try toPosixPath(dir_path);
......@@ -2935,8 +2937,7 @@ pub fn chdirZ(dir_path: [*:0]const u8) ChangeCurDirError!void {
29352937 if (native_os == .windows) {
29362938 const dir_path_span = mem.span(dir_path);
29372939 var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined;
2938 try windows.checkWtf8ToWtf16LeOverflow(dir_path_span, &wtf16_dir_path);
2939 const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path_span);
2940 const len = try windows.wtf8ToWtf16Le(&wtf16_dir_path, dir_path_span);
29402941 return chdirW(wtf16_dir_path[0..len]);
29412942 } else if (native_os == .wasi and !builtin.link_libc) {
29422943 return chdir(mem.span(dir_path));
lib/std/posix/test.zig-14
......@@ -862,20 +862,6 @@ test "isatty" {
862862 try expectEqual(posix.isatty(file.handle), false);
863863}
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
879865test "pread with empty buffer" {
880866 var tmp = tmpDir(.{});
881867 defer tmp.cleanup();
lib/std/testing.zig+5-1
......@@ -1148,6 +1148,7 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime
11481148 } else |err| switch (err) {
11491149 error.OutOfMemory => {
11501150 if (failing_allocator_inst.allocated_bytes != failing_allocator_inst.freed_bytes) {
1151 const tty_config = std.Io.tty.detectConfig(.stderr());
11511152 print(
11521153 "\nfail_index: {d}/{d}\nallocated bytes: {d}\nfreed bytes: {d}\nallocations: {d}\ndeallocations: {d}\nallocation that was made to fail: {f}",
11531154 .{
......@@ -1157,7 +1158,10 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime
11571158 failing_allocator_inst.freed_bytes,
11581159 failing_allocator_inst.allocations,
11591160 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 },
11611165 },
11621166 );
11631167 return error.MemoryLeakDetected;
tools/incr-check.zig+13-6
......@@ -1,4 +1,5 @@
11const std = @import("std");
2const Io = std.Io;
23const Allocator = std.mem.Allocator;
34const Cache = std.Build.Cache;
45
......@@ -11,6 +12,12 @@ pub fn main() !void {
1112 defer arena_instance.deinit();
1213 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
1421 var opt_zig_exe: ?[]const u8 = null;
1522 var opt_input_file_name: ?[]const u8 = null;
1623 var opt_lib_dir: ?[]const u8 = null;
......@@ -53,7 +60,7 @@ pub fn main() !void {
5360 const input_file_name = opt_input_file_name orelse fatal("missing input file\n{s}", .{usage});
5461
5562 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
5865 // Check now: if there are any targets using the `cbe` backend, we need the lib dir.
5966 if (opt_lib_dir == null) {
......@@ -86,7 +93,7 @@ pub fn main() !void {
8693 else
8794 null;
8895
89 const host = try std.zig.system.resolveTargetQuery(.{});
96 const host = try std.zig.system.resolveTargetQuery(io, .{});
9097
9198 const debug_log_verbose = debug_zcu or debug_dwarf or debug_link;
9299
......@@ -186,7 +193,7 @@ pub fn main() !void {
186193
187194 try child.spawn();
188195
189 var poller = std.Io.poll(arena, Eval.StreamEnum, .{
196 var poller = Io.poll(arena, Eval.StreamEnum, .{
190197 .stdout = child.stdout.?,
191198 .stderr = child.stderr.?,
192199 });
......@@ -226,7 +233,7 @@ const Eval = struct {
226233 cc_child_args: *std.ArrayListUnmanaged([]const u8),
227234
228235 const StreamEnum = enum { stdout, stderr };
229 const Poller = std.Io.Poller(StreamEnum);
236 const Poller = Io.Poller(StreamEnum);
230237
231238 /// Currently this function assumes the previous updates have already been written.
232239 fn write(eval: *Eval, update: Case.Update) void {
......@@ -647,7 +654,7 @@ const Case = struct {
647654 msg: []const u8,
648655 };
649656
650 fn parse(arena: Allocator, bytes: []const u8) !Case {
657 fn parse(arena: Allocator, io: Io, bytes: []const u8) !Case {
651658 const fatal = std.process.fatal;
652659
653660 var targets: std.ArrayListUnmanaged(Target) = .empty;
......@@ -683,7 +690,7 @@ const Case = struct {
683690 },
684691 }) 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
688695 try targets.append(arena, .{
689696 .query = query,