authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-19 21:53:48-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-19 22:12:37-07:00
logc40fb96ca358e2ef28aecc2b7ebc5ffab43ccac8
tree3aa9f1c66c4558472fbdd3c212a3b116385298e8
parent741a66e03cd8644d01b38849f2bd8f70cae6beca

std.Io.Writer: fix writeSliceSwap

tried to be too clever, wrote bad code

7 files changed, 35 insertions(+), 46 deletions(-)

lib/compiler/test_runner.zig+6-6
...@@ -10,10 +10,10 @@ pub const std_options: std.Options = .{...@@ -10,10 +10,10 @@ pub const std_options: std.Options = .{
10};10};
1111
12var log_err_count: usize = 0;12var log_err_count: usize = 0;
13var fba_buffer: [8192]u8 = undefined;
14var fba = std.heap.FixedBufferAllocator.init(&fba_buffer);13var fba = std.heap.FixedBufferAllocator.init(&fba_buffer);
15var stdin_buffer: [std.heap.page_size_min]u8 align(std.heap.page_size_min) = undefined;14var fba_buffer: [8192]u8 = undefined;
16var stdout_buffer: [std.heap.page_size_min]u8 align(std.heap.page_size_min) = undefined;15var stdin_buffer: [4096]u8 = undefined;
16var stdout_buffer: [4096]u8 = undefined;
1717
18const crippled = switch (builtin.zig_backend) {18const crippled = switch (builtin.zig_backend) {
19 .stage2_powerpc,19 .stage2_powerpc,
...@@ -68,8 +68,8 @@ pub fn main() void {...@@ -68,8 +68,8 @@ pub fn main() void {
6868
69fn mainServer() !void {69fn mainServer() !void {
70 @disableInstrumentation();70 @disableInstrumentation();
71 var stdin_reader = std.fs.File.stdin().reader(&stdin_buffer);71 var stdin_reader = std.fs.File.stdin().readerStreaming(&stdin_buffer);
72 var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);72 var stdout_writer = std.fs.File.stdout().writerStreaming(&stdout_buffer);
73 var server = try std.zig.Server.init(.{73 var server = try std.zig.Server.init(.{
74 .in = &stdin_reader.interface,74 .in = &stdin_reader.interface,
75 .out = &stdout_writer.interface,75 .out = &stdout_writer.interface,
...@@ -104,7 +104,7 @@ fn mainServer() !void {...@@ -104,7 +104,7 @@ fn mainServer() !void {
104 defer testing.allocator.free(expected_panic_msgs);104 defer testing.allocator.free(expected_panic_msgs);
105105
106 for (test_fns, names, expected_panic_msgs) |test_fn, *name, *expected_panic_msg| {106 for (test_fns, names, expected_panic_msgs) |test_fn, *name, *expected_panic_msg| {
107 name.* = @as(u32, @intCast(string_bytes.items.len));107 name.* = @intCast(string_bytes.items.len);
108 try string_bytes.ensureUnusedCapacity(testing.allocator, test_fn.name.len + 1);108 try string_bytes.ensureUnusedCapacity(testing.allocator, test_fn.name.len + 1);
109 string_bytes.appendSliceAssumeCapacity(test_fn.name);109 string_bytes.appendSliceAssumeCapacity(test_fn.name);
110 string_bytes.appendAssumeCapacity(0);110 string_bytes.appendAssumeCapacity(0);
lib/std/Build/Step/Run.zig+1-1
...@@ -1742,7 +1742,7 @@ fn sendMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag) !void {...@@ -1742,7 +1742,7 @@ fn sendMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag) !void {
1742 .tag = tag,1742 .tag = tag,
1743 .bytes_len = 0,1743 .bytes_len = 0,
1744 };1744 };
1745 try file.writeAll(std.mem.asBytes(&header));1745 try file.writeAll(@ptrCast(&header));
1746}1746}
17471747
1748fn sendRunTestMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag, index: u32) !void {1748fn sendRunTestMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag, index: u32) !void {
lib/std/Io/Reader.zig+17-17
...@@ -1108,9 +1108,9 @@ pub fn takeVarInt(r: *Reader, comptime Int: type, endian: std.builtin.Endian, n:...@@ -1108,9 +1108,9 @@ pub fn takeVarInt(r: *Reader, comptime Int: type, endian: std.builtin.Endian, n:
1108/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.1108/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.
1109///1109///
1110/// See also:1110/// See also:
1111/// * `peekStructReference`1111/// * `peekStructPointer`
1112/// * `takeStruct`1112/// * `takeStruct`
1113pub fn takeStructReference(r: *Reader, comptime T: type) Error!*align(1) T {1113pub fn takeStructPointer(r: *Reader, comptime T: type) Error!*align(1) T {
1114 // Only extern and packed structs have defined in-memory layout.1114 // Only extern and packed structs have defined in-memory layout.
1115 comptime assert(@typeInfo(T).@"struct".layout != .auto);1115 comptime assert(@typeInfo(T).@"struct".layout != .auto);
1116 return @ptrCast(try r.takeArray(@sizeOf(T)));1116 return @ptrCast(try r.takeArray(@sizeOf(T)));
...@@ -1122,9 +1122,9 @@ pub fn takeStructReference(r: *Reader, comptime T: type) Error!*align(1) T {...@@ -1122,9 +1122,9 @@ pub fn takeStructReference(r: *Reader, comptime T: type) Error!*align(1) T {
1122/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.1122/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.
1123///1123///
1124/// See also:1124/// See also:
1125/// * `takeStructReference`1125/// * `takeStructPointer`
1126/// * `peekStruct`1126/// * `peekStruct`
1127pub fn peekStructReference(r: *Reader, comptime T: type) Error!*align(1) T {1127pub fn peekStructPointer(r: *Reader, comptime T: type) Error!*align(1) T {
1128 // Only extern and packed structs have defined in-memory layout.1128 // Only extern and packed structs have defined in-memory layout.
1129 comptime assert(@typeInfo(T).@"struct".layout != .auto);1129 comptime assert(@typeInfo(T).@"struct".layout != .auto);
1130 return @ptrCast(try r.peekArray(@sizeOf(T)));1130 return @ptrCast(try r.peekArray(@sizeOf(T)));
...@@ -1136,14 +1136,14 @@ pub fn peekStructReference(r: *Reader, comptime T: type) Error!*align(1) T {...@@ -1136,14 +1136,14 @@ pub fn peekStructReference(r: *Reader, comptime T: type) Error!*align(1) T {
1136/// when `endian` is comptime-known and matches the host endianness.1136/// when `endian` is comptime-known and matches the host endianness.
1137///1137///
1138/// See also:1138/// See also:
1139/// * `takeStructReference`1139/// * `takeStructPointer`
1140/// * `peekStruct`1140/// * `peekStruct`
1141pub inline fn takeStruct(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {1141pub inline fn takeStruct(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
1142 switch (@typeInfo(T)) {1142 switch (@typeInfo(T)) {
1143 .@"struct" => |info| switch (info.layout) {1143 .@"struct" => |info| switch (info.layout) {
1144 .auto => @compileError("ill-defined memory layout"),1144 .auto => @compileError("ill-defined memory layout"),
1145 .@"extern" => {1145 .@"extern" => {
1146 var res = (try r.takeStructReference(T)).*;1146 var res = (try r.takeStructPointer(T)).*;
1147 if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);1147 if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);
1148 return res;1148 return res;
1149 },1149 },
...@@ -1162,13 +1162,13 @@ pub inline fn takeStruct(r: *Reader, comptime T: type, endian: std.builtin.Endia...@@ -1162,13 +1162,13 @@ pub inline fn takeStruct(r: *Reader, comptime T: type, endian: std.builtin.Endia
1162///1162///
1163/// See also:1163/// See also:
1164/// * `takeStruct`1164/// * `takeStruct`
1165/// * `peekStructReference`1165/// * `peekStructPointer`
1166pub inline fn peekStruct(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {1166pub inline fn peekStruct(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
1167 switch (@typeInfo(T)) {1167 switch (@typeInfo(T)) {
1168 .@"struct" => |info| switch (info.layout) {1168 .@"struct" => |info| switch (info.layout) {
1169 .auto => @compileError("ill-defined memory layout"),1169 .auto => @compileError("ill-defined memory layout"),
1170 .@"extern" => {1170 .@"extern" => {
1171 var res = (try r.peekStructReference(T)).*;1171 var res = (try r.peekStructPointer(T)).*;
1172 if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);1172 if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);
1173 return res;1173 return res;
1174 },1174 },
...@@ -1557,27 +1557,27 @@ test takeVarInt {...@@ -1557,27 +1557,27 @@ test takeVarInt {
1557 try testing.expectError(error.EndOfStream, r.takeVarInt(u16, .little, 1));1557 try testing.expectError(error.EndOfStream, r.takeVarInt(u16, .little, 1));
1558}1558}
15591559
1560test takeStructReference {1560test takeStructPointer {
1561 var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });1561 var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
1562 const S = extern struct { a: u8, b: u16 };1562 const S = extern struct { a: u8, b: u16 };
1563 switch (native_endian) {1563 switch (native_endian) {
1564 .little => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.takeStructReference(S)).*),1564 .little => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.takeStructPointer(S)).*),
1565 .big => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.takeStructReference(S)).*),1565 .big => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.takeStructPointer(S)).*),
1566 }1566 }
1567 try testing.expectError(error.EndOfStream, r.takeStructReference(S));1567 try testing.expectError(error.EndOfStream, r.takeStructPointer(S));
1568}1568}
15691569
1570test peekStructReference {1570test peekStructPointer {
1571 var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });1571 var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
1572 const S = extern struct { a: u8, b: u16 };1572 const S = extern struct { a: u8, b: u16 };
1573 switch (native_endian) {1573 switch (native_endian) {
1574 .little => {1574 .little => {
1575 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStructReference(S)).*);1575 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStructPointer(S)).*);
1576 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStructReference(S)).*);1576 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStructPointer(S)).*);
1577 },1577 },
1578 .big => {1578 .big => {
1579 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStructReference(S)).*);1579 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStructPointer(S)).*);
1580 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStructReference(S)).*);1580 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStructPointer(S)).*);
1581 },1581 },
1582 }1582 }
1583}1583}
lib/std/Io/Writer.zig+7-16
...@@ -851,9 +851,6 @@ pub inline fn writeStruct(w: *Writer, value: anytype, endian: std.builtin.Endian...@@ -851,9 +851,6 @@ pub inline fn writeStruct(w: *Writer, value: anytype, endian: std.builtin.Endian
851 }851 }
852}852}
853853
854/// If, `endian` is not native,
855/// * Asserts that the buffer storage capacity is at least enough to store `@sizeOf(Elem)`
856/// * Asserts that the buffer is aligned enough for `@alignOf(Elem)`.
857pub inline fn writeSliceEndian(854pub inline fn writeSliceEndian(
858 w: *Writer,855 w: *Writer,
859 Elem: type,856 Elem: type,
...@@ -867,18 +864,11 @@ pub inline fn writeSliceEndian(...@@ -867,18 +864,11 @@ pub inline fn writeSliceEndian(
867 }864 }
868}865}
869866
870/// Asserts that the buffer storage capacity is at least enough to store `@sizeOf(Elem)`
871///
872/// Asserts that the buffer is aligned enough for `@alignOf(Elem)`.
873pub fn writeSliceSwap(w: *Writer, Elem: type, slice: []const Elem) Error!void {867pub fn writeSliceSwap(w: *Writer, Elem: type, slice: []const Elem) Error!void {
874 var i: usize = 0;868 for (slice) |elem| {
875 while (i < slice.len) {869 var tmp = elem;
876 const dest_bytes = try w.writableSliceGreedy(@sizeOf(Elem));870 std.mem.byteSwapAllFields(Elem, &tmp);
877 const dest: []Elem = @alignCast(@ptrCast(dest_bytes[0 .. dest_bytes.len - dest_bytes.len % @sizeOf(Elem)]));871 try w.writeAll(@ptrCast(&tmp));
878 const copy_len = @min(dest.len, slice.len - i);
879 @memcpy(dest[0..copy_len], slice[i..][0..copy_len]);
880 i += copy_len;
881 std.mem.byteSwapAllElements(Elem, dest);
882 }872 }
883}873}
884874
...@@ -2650,9 +2640,10 @@ test writeStruct {...@@ -2650,9 +2640,10 @@ test writeStruct {
2650}2640}
26512641
2652test writeSliceEndian {2642test writeSliceEndian {
2653 var buffer: [4]u8 align(2) = undefined;2643 var buffer: [5]u8 align(2) = undefined;
2654 var w: Writer = .fixed(&buffer);2644 var w: Writer = .fixed(&buffer);
2645 try w.writeByte('x');
2655 const array: [2]u16 = .{ 0x1234, 0x5678 };2646 const array: [2]u16 = .{ 0x1234, 0x5678 };
2656 try writeSliceEndian(&w, u16, &array, .big);2647 try writeSliceEndian(&w, u16, &array, .big);
2657 try testing.expectEqualSlices(u8, &.{ 0x12, 0x34, 0x56, 0x78 }, &buffer);2648 try testing.expectEqualSlices(u8, &.{ 'x', 0x12, 0x34, 0x56, 0x78 }, &buffer);
2658}2649}
lib/std/zig/Server.zig+2-4
...@@ -118,8 +118,6 @@ pub fn init(options: Options) !Server {...@@ -118,8 +118,6 @@ pub fn init(options: Options) !Server {
118 .in = options.in,118 .in = options.in,
119 .out = options.out,119 .out = options.out,
120 };120 };
121 assert(s.out.buffer.len >= 4);
122 std.debug.assertAligned(s.out.buffer.ptr, .@"4");
123 try s.serveStringMessage(.zig_version, options.zig_version);121 try s.serveStringMessage(.zig_version, options.zig_version);
124 return s;122 return s;
125}123}
...@@ -203,8 +201,8 @@ pub const TestMetadata = struct {...@@ -203,8 +201,8 @@ pub const TestMetadata = struct {
203201
204pub fn serveTestMetadata(s: *Server, test_metadata: TestMetadata) !void {202pub fn serveTestMetadata(s: *Server, test_metadata: TestMetadata) !void {
205 const header: OutMessage.TestMetadata = .{203 const header: OutMessage.TestMetadata = .{
206 .tests_len = @as(u32, @intCast(test_metadata.names.len)),204 .tests_len = @intCast(test_metadata.names.len),
207 .string_bytes_len = @as(u32, @intCast(test_metadata.string_bytes.len)),205 .string_bytes_len = @intCast(test_metadata.string_bytes.len),
208 };206 };
209 const trailing = 2;207 const trailing = 2;
210 const bytes_len = @sizeOf(OutMessage.TestMetadata) +208 const bytes_len = @sizeOf(OutMessage.TestMetadata) +
src/Zcu.zig+1-1
...@@ -2821,7 +2821,7 @@ pub fn loadZirCache(gpa: Allocator, cache_file: std.fs.File) !Zir {...@@ -2821,7 +2821,7 @@ pub fn loadZirCache(gpa: Allocator, cache_file: std.fs.File) !Zir {
2821 var buffer: [2000]u8 = undefined;2821 var buffer: [2000]u8 = undefined;
2822 var file_reader = cache_file.reader(&buffer);2822 var file_reader = cache_file.reader(&buffer);
2823 return result: {2823 return result: {
2824 const header = file_reader.interface.takeStructReference(Zir.Header) catch |err| break :result err;2824 const header = file_reader.interface.takeStructPointer(Zir.Header) catch |err| break :result err;
2825 break :result loadZirCacheBody(gpa, header.*, &file_reader.interface);2825 break :result loadZirCacheBody(gpa, header.*, &file_reader.interface);
2826 } catch |err| switch (err) {2826 } catch |err| switch (err) {
2827 error.ReadFailed => return file_reader.err.?,2827 error.ReadFailed => return file_reader.err.?,
src/Zcu/PerThread.zig+1-1
...@@ -349,7 +349,7 @@ fn loadZirZoirCache(...@@ -349,7 +349,7 @@ fn loadZirZoirCache(
349 const cache_br = &cache_fr.interface;349 const cache_br = &cache_fr.interface;
350350
351 // First we read the header to determine the lengths of arrays.351 // First we read the header to determine the lengths of arrays.
352 const header = (cache_br.takeStructReference(Header) catch |err| switch (err) {352 const header = (cache_br.takeStructPointer(Header) catch |err| switch (err) {
353 error.ReadFailed => return cache_fr.err.?,353 error.ReadFailed => return cache_fr.err.?,
354 // This can happen if Zig bails out of this function between creating354 // This can happen if Zig bails out of this function between creating
355 // the cached file and writing it.355 // the cached file and writing it.