Skip to content

Commit

Permalink
fix endianness when using test-runner in qemu
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewrk committed Mar 13, 2023
1 parent 79d057a commit 6015d51
Showing 1 changed file with 63 additions and 12 deletions.
75 changes: 63 additions & 12 deletions lib/std/zig/Server.zig
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,17 @@ pub fn receiveMessage(s: *Server) !InMessage.Header {
assert(fifo.readableLength() == buf.len);
if (buf.len >= @sizeOf(Header)) {
const header = @ptrCast(*align(1) const Header, buf[0..@sizeOf(Header)]);
const bytes_len = bswap(header.bytes_len);
const tag = bswap(header.tag);

if (buf.len - @sizeOf(Header) >= header.bytes_len) {
const result = header.*;
if (buf.len - @sizeOf(Header) >= bytes_len) {
fifo.discard(@sizeOf(Header));
return result;
return .{
.tag = tag,
.bytes_len = bytes_len,
};
} else {
const needed = header.bytes_len - (buf.len - @sizeOf(Header));
const needed = bytes_len - (buf.len - @sizeOf(Header));
const write_buffer = try fifo.writableWithSize(needed);
const amt = try s.in.read(write_buffer);
fifo.update(amt);
Expand All @@ -130,7 +134,7 @@ pub fn receiveBody_u32(s: *Server) !u32 {
const buf = fifo.readableSlice(0);
const result = @ptrCast(*align(1) const u32, buf[0..4]).*;
fifo.discard(4);
return result;
return bswap(result);
}

pub fn serveStringMessage(s: *Server, tag: OutMessage.Tag, msg: []const u8) !void {
Expand All @@ -146,8 +150,9 @@ pub fn serveMessage(
bufs: []const []const u8,
) !void {
var iovecs: [10]std.os.iovec_const = undefined;
const header_le = bswap(header);
iovecs[0] = .{
.iov_base = @ptrCast([*]const u8, &header),
.iov_base = @ptrCast([*]const u8, &header_le),
.iov_len = @sizeOf(OutMessage.Header),
};
for (bufs, iovecs[1 .. bufs.len + 1]) |buf, *iovec| {
Expand Down Expand Up @@ -177,11 +182,12 @@ pub fn serveTestResults(
s: *Server,
msg: OutMessage.TestResults,
) !void {
const msg_le = bswap(msg);
try s.serveMessage(.{
.tag = .test_results,
.bytes_len = @intCast(u32, @sizeOf(OutMessage.TestResults)),
}, &.{
std.mem.asBytes(&msg),
std.mem.asBytes(&msg_le),
});
}

Expand All @@ -204,19 +210,31 @@ pub fn serveErrorBundle(s: *Server, error_bundle: std.zig.ErrorBundle) !void {
}

pub const TestMetadata = struct {
names: []const u32,
async_frame_sizes: []const u32,
expected_panic_msgs: []const u32,
names: []u32,
async_frame_sizes: []u32,
expected_panic_msgs: []u32,
string_bytes: []const u8,
};

pub fn serveTestMetadata(s: *Server, test_metadata: TestMetadata) !void {
const header: OutMessage.TestMetadata = .{
.tests_len = @intCast(u32, test_metadata.names.len),
.string_bytes_len = @intCast(u32, test_metadata.string_bytes.len),
.tests_len = bswap(@intCast(u32, test_metadata.names.len)),
.string_bytes_len = bswap(@intCast(u32, test_metadata.string_bytes.len)),
};
const bytes_len = @sizeOf(OutMessage.TestMetadata) +
3 * 4 * test_metadata.names.len + test_metadata.string_bytes.len;

if (need_bswap) {
bswap_u32_array(test_metadata.names);
bswap_u32_array(test_metadata.async_frame_sizes);
bswap_u32_array(test_metadata.expected_panic_msgs);
}
defer if (need_bswap) {
bswap_u32_array(test_metadata.names);
bswap_u32_array(test_metadata.async_frame_sizes);
bswap_u32_array(test_metadata.expected_panic_msgs);
};

return s.serveMessage(.{
.tag = .test_metadata,
.bytes_len = @intCast(u32, bytes_len),
Expand All @@ -230,10 +248,43 @@ pub fn serveTestMetadata(s: *Server, test_metadata: TestMetadata) !void {
});
}

fn bswap(x: anytype) @TypeOf(x) {
if (!need_bswap) return x;

const T = @TypeOf(x);
switch (@typeInfo(T)) {
.Enum => return @intToEnum(T, @byteSwap(@enumToInt(x))),
.Int => return @byteSwap(x),
.Struct => |info| switch (info.layout) {
.Extern => {
var result: T = undefined;
inline for (info.fields) |field| {
@field(result, field.name) = bswap(@field(x, field.name));
}
return result;
},
.Packed => {
const I = info.backing_integer.?;
return @bitCast(T, @byteSwap(@bitCast(I, x)));
},
.Auto => @compileError("auto layout struct"),
},
else => @compileError("bswap on type " ++ @typeName(T)),
}
}

fn bswap_u32_array(slice: []u32) void {
comptime assert(need_bswap);
for (slice) |*elem| elem.* = @byteSwap(elem.*);
}

const OutMessage = std.zig.Server.Message;
const InMessage = std.zig.Client.Message;

const Server = @This();
const builtin = @import("builtin");
const std = @import("std");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const native_endian = builtin.target.cpu.arch.endian();
const need_bswap = native_endian != .Little;

0 comments on commit 6015d51

Please sign in to comment.