authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-14 19:50:52-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-15 10:48:15-07:00
log4aa5895d322c58cfa654e890beccc1009d49c6e5
treeddd3ff7b8cb424544beb4237df45aa0165b061c9
parent4f1382e58166c4324f842450fdad4d134d553085

std.Build: fix invalid assumption about fifos

Previously this code asserted that a fifo's readable length was greater than or equal to the length of its readable slice, which was an invalid assertion. This code avoids making that assumption.

2 files changed, 127 insertions(+), 125 deletions(-)

lib/std/Build/RunStep.zig+77-76
......@@ -949,85 +949,86 @@ fn evalZigTest(
949949 var sub_prog_node: ?std.Progress.Node = null;
950950 defer if (sub_prog_node) |*n| n.end();
951951
952 poll: while (try poller.poll()) {
953 while (true) {
954 const buf = stdout.readableSlice(0);
955 assert(stdout.readableLength() == buf.len);
956 if (buf.len < @sizeOf(Header)) continue :poll;
957 const header = @ptrCast(*align(1) const Header, buf[0..@sizeOf(Header)]);
958 const header_and_msg_len = header.bytes_len + @sizeOf(Header);
959 if (buf.len < header_and_msg_len) continue :poll;
960 const body = buf[@sizeOf(Header)..][0..header.bytes_len];
961 switch (header.tag) {
962 .zig_version => {
963 if (!std.mem.eql(u8, builtin.zig_version_string, body)) {
964 return self.step.fail(
965 "zig version mismatch build runner vs compiler: '{s}' vs '{s}'",
966 .{ builtin.zig_version_string, body },
967 );
968 }
969 },
970 .test_metadata => {
971 const TmHdr = std.zig.Server.Message.TestMetadata;
972 const tm_hdr = @ptrCast(*align(1) const TmHdr, body);
973 test_count = tm_hdr.tests_len;
974
975 const names_bytes = body[@sizeOf(TmHdr)..][0 .. test_count * @sizeOf(u32)];
976 const async_frame_lens_bytes = body[@sizeOf(TmHdr) + names_bytes.len ..][0 .. test_count * @sizeOf(u32)];
977 const expected_panic_msgs_bytes = body[@sizeOf(TmHdr) + names_bytes.len + async_frame_lens_bytes.len ..][0 .. test_count * @sizeOf(u32)];
978 const string_bytes = body[@sizeOf(TmHdr) + names_bytes.len + async_frame_lens_bytes.len + expected_panic_msgs_bytes.len ..][0..tm_hdr.string_bytes_len];
979
980 const names = std.mem.bytesAsSlice(u32, names_bytes);
981 const async_frame_lens = std.mem.bytesAsSlice(u32, async_frame_lens_bytes);
982 const expected_panic_msgs = std.mem.bytesAsSlice(u32, expected_panic_msgs_bytes);
983 const names_aligned = try arena.alloc(u32, names.len);
984 for (names_aligned, names) |*dest, src| dest.* = src;
985
986 const async_frame_lens_aligned = try arena.alloc(u32, async_frame_lens.len);
987 for (async_frame_lens_aligned, async_frame_lens) |*dest, src| dest.* = src;
988
989 const expected_panic_msgs_aligned = try arena.alloc(u32, expected_panic_msgs.len);
990 for (expected_panic_msgs_aligned, expected_panic_msgs) |*dest, src| dest.* = src;
991
992 prog_node.setEstimatedTotalItems(names.len);
993 metadata = .{
994 .string_bytes = try arena.dupe(u8, string_bytes),
995 .names = names_aligned,
996 .async_frame_lens = async_frame_lens_aligned,
997 .expected_panic_msgs = expected_panic_msgs_aligned,
998 .next_index = 0,
999 .prog_node = prog_node,
1000 };
1001
1002 try requestNextTest(child.stdin.?, &metadata.?, &sub_prog_node);
1003 },
1004 .test_results => {
1005 const md = metadata.?;
1006
1007 const TrHdr = std.zig.Server.Message.TestResults;
1008 const tr_hdr = @ptrCast(*align(1) const TrHdr, body);
1009 fail_count += @boolToInt(tr_hdr.flags.fail);
1010 skip_count += @boolToInt(tr_hdr.flags.skip);
1011 leak_count += @boolToInt(tr_hdr.flags.leak);
1012
1013 if (tr_hdr.flags.fail or tr_hdr.flags.leak) {
1014 const name = std.mem.sliceTo(md.string_bytes[md.names[tr_hdr.index]..], 0);
1015 const msg = std.mem.trim(u8, stderr.readableSlice(0), "\n");
1016 const label = if (tr_hdr.flags.fail) "failed" else "leaked";
1017 if (msg.len > 0) {
1018 try self.step.addError("'{s}' {s}: {s}", .{ name, label, msg });
1019 } else {
1020 try self.step.addError("'{s}' {s}", .{ name, label });
1021 }
1022 stderr.discard(msg.len);
952 poll: while (true) {
953 while (stdout.readableLength() < @sizeOf(Header)) {
954 if (!(try poller.poll())) break :poll;
955 }
956 const header = stdout.reader().readStruct(Header) catch unreachable;
957 while (stdout.readableLength() < header.bytes_len) {
958 if (!(try poller.poll())) break :poll;
959 }
960 const body = stdout.readableSliceOfLen(header.bytes_len);
961
962 switch (header.tag) {
963 .zig_version => {
964 if (!std.mem.eql(u8, builtin.zig_version_string, body)) {
965 return self.step.fail(
966 "zig version mismatch build runner vs compiler: '{s}' vs '{s}'",
967 .{ builtin.zig_version_string, body },
968 );
969 }
970 },
971 .test_metadata => {
972 const TmHdr = std.zig.Server.Message.TestMetadata;
973 const tm_hdr = @ptrCast(*align(1) const TmHdr, body);
974 test_count = tm_hdr.tests_len;
975
976 const names_bytes = body[@sizeOf(TmHdr)..][0 .. test_count * @sizeOf(u32)];
977 const async_frame_lens_bytes = body[@sizeOf(TmHdr) + names_bytes.len ..][0 .. test_count * @sizeOf(u32)];
978 const expected_panic_msgs_bytes = body[@sizeOf(TmHdr) + names_bytes.len + async_frame_lens_bytes.len ..][0 .. test_count * @sizeOf(u32)];
979 const string_bytes = body[@sizeOf(TmHdr) + names_bytes.len + async_frame_lens_bytes.len + expected_panic_msgs_bytes.len ..][0..tm_hdr.string_bytes_len];
980
981 const names = std.mem.bytesAsSlice(u32, names_bytes);
982 const async_frame_lens = std.mem.bytesAsSlice(u32, async_frame_lens_bytes);
983 const expected_panic_msgs = std.mem.bytesAsSlice(u32, expected_panic_msgs_bytes);
984 const names_aligned = try arena.alloc(u32, names.len);
985 for (names_aligned, names) |*dest, src| dest.* = src;
986
987 const async_frame_lens_aligned = try arena.alloc(u32, async_frame_lens.len);
988 for (async_frame_lens_aligned, async_frame_lens) |*dest, src| dest.* = src;
989
990 const expected_panic_msgs_aligned = try arena.alloc(u32, expected_panic_msgs.len);
991 for (expected_panic_msgs_aligned, expected_panic_msgs) |*dest, src| dest.* = src;
992
993 prog_node.setEstimatedTotalItems(names.len);
994 metadata = .{
995 .string_bytes = try arena.dupe(u8, string_bytes),
996 .names = names_aligned,
997 .async_frame_lens = async_frame_lens_aligned,
998 .expected_panic_msgs = expected_panic_msgs_aligned,
999 .next_index = 0,
1000 .prog_node = prog_node,
1001 };
1002
1003 try requestNextTest(child.stdin.?, &metadata.?, &sub_prog_node);
1004 },
1005 .test_results => {
1006 const md = metadata.?;
1007
1008 const TrHdr = std.zig.Server.Message.TestResults;
1009 const tr_hdr = @ptrCast(*align(1) const TrHdr, body);
1010 fail_count += @boolToInt(tr_hdr.flags.fail);
1011 skip_count += @boolToInt(tr_hdr.flags.skip);
1012 leak_count += @boolToInt(tr_hdr.flags.leak);
1013
1014 if (tr_hdr.flags.fail or tr_hdr.flags.leak) {
1015 const name = std.mem.sliceTo(md.string_bytes[md.names[tr_hdr.index]..], 0);
1016 const msg = std.mem.trim(u8, stderr.readableSlice(0), "\n");
1017 const label = if (tr_hdr.flags.fail) "failed" else "leaked";
1018 if (msg.len > 0) {
1019 try self.step.addError("'{s}' {s}: {s}", .{ name, label, msg });
1020 } else {
1021 try self.step.addError("'{s}' {s}", .{ name, label });
10231022 }
1023 stderr.discard(msg.len);
1024 }
10241025
1025 try requestNextTest(child.stdin.?, &metadata.?, &sub_prog_node);
1026 },
1027 else => {}, // ignore other messages
1028 }
1029 stdout.discard(header_and_msg_len);
1026 try requestNextTest(child.stdin.?, &metadata.?, &sub_prog_node);
1027 },
1028 else => {}, // ignore other messages
10301029 }
1030
1031 stdout.discard(body.len);
10311032 }
10321033
10331034 if (stderr.readableLength() > 0) {
lib/std/Build/Step.zig+50-49
......@@ -321,56 +321,57 @@ pub fn evalZigProcess(
321321
322322 const stdout = poller.fifo(.stdout);
323323
324 poll: while (try poller.poll()) {
325 while (true) {
326 const buf = stdout.readableSlice(0);
327 assert(stdout.readableLength() == buf.len);
328 if (buf.len < @sizeOf(Header)) continue :poll;
329 const header = @ptrCast(*align(1) const Header, buf[0..@sizeOf(Header)]);
330 const header_and_msg_len = header.bytes_len + @sizeOf(Header);
331 if (buf.len < header_and_msg_len) continue :poll;
332 const body = buf[@sizeOf(Header)..][0..header.bytes_len];
333 switch (header.tag) {
334 .zig_version => {
335 if (!std.mem.eql(u8, builtin.zig_version_string, body)) {
336 return s.fail(
337 "zig version mismatch build runner vs compiler: '{s}' vs '{s}'",
338 .{ builtin.zig_version_string, body },
339 );
340 }
341 },
342 .error_bundle => {
343 const EbHdr = std.zig.Server.Message.ErrorBundle;
344 const eb_hdr = @ptrCast(*align(1) const EbHdr, body);
345 const extra_bytes =
346 body[@sizeOf(EbHdr)..][0 .. @sizeOf(u32) * eb_hdr.extra_len];
347 const string_bytes =
348 body[@sizeOf(EbHdr) + extra_bytes.len ..][0..eb_hdr.string_bytes_len];
349 // TODO: use @ptrCast when the compiler supports it
350 const unaligned_extra = std.mem.bytesAsSlice(u32, extra_bytes);
351 const extra_array = try arena.alloc(u32, unaligned_extra.len);
352 // TODO: use @memcpy when it supports slices
353 for (extra_array, unaligned_extra) |*dst, src| dst.* = src;
354 s.result_error_bundle = .{
355 .string_bytes = try arena.dupe(u8, string_bytes),
356 .extra = extra_array,
357 };
358 },
359 .progress => {
360 node_name.clearRetainingCapacity();
361 try node_name.appendSlice(gpa, body);
362 sub_prog_node.setName(node_name.items);
363 },
364 .emit_bin_path => {
365 const EbpHdr = std.zig.Server.Message.EmitBinPath;
366 const ebp_hdr = @ptrCast(*align(1) const EbpHdr, body);
367 s.result_cached = ebp_hdr.flags.cache_hit;
368 result = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]);
369 },
370 else => {}, // ignore other messages
371 }
372 stdout.discard(header_and_msg_len);
324 poll: while (true) {
325 while (stdout.readableLength() < @sizeOf(Header)) {
326 if (!(try poller.poll())) break :poll;
327 }
328 const header = stdout.reader().readStruct(Header) catch unreachable;
329 while (stdout.readableLength() < header.bytes_len) {
330 if (!(try poller.poll())) break :poll;
373331 }
332 const body = stdout.readableSliceOfLen(header.bytes_len);
333
334 switch (header.tag) {
335 .zig_version => {
336 if (!std.mem.eql(u8, builtin.zig_version_string, body)) {
337 return s.fail(
338 "zig version mismatch build runner vs compiler: '{s}' vs '{s}'",
339 .{ builtin.zig_version_string, body },
340 );
341 }
342 },
343 .error_bundle => {
344 const EbHdr = std.zig.Server.Message.ErrorBundle;
345 const eb_hdr = @ptrCast(*align(1) const EbHdr, body);
346 const extra_bytes =
347 body[@sizeOf(EbHdr)..][0 .. @sizeOf(u32) * eb_hdr.extra_len];
348 const string_bytes =
349 body[@sizeOf(EbHdr) + extra_bytes.len ..][0..eb_hdr.string_bytes_len];
350 // TODO: use @ptrCast when the compiler supports it
351 const unaligned_extra = std.mem.bytesAsSlice(u32, extra_bytes);
352 const extra_array = try arena.alloc(u32, unaligned_extra.len);
353 // TODO: use @memcpy when it supports slices
354 for (extra_array, unaligned_extra) |*dst, src| dst.* = src;
355 s.result_error_bundle = .{
356 .string_bytes = try arena.dupe(u8, string_bytes),
357 .extra = extra_array,
358 };
359 },
360 .progress => {
361 node_name.clearRetainingCapacity();
362 try node_name.appendSlice(gpa, body);
363 sub_prog_node.setName(node_name.items);
364 },
365 .emit_bin_path => {
366 const EbpHdr = std.zig.Server.Message.EmitBinPath;
367 const ebp_hdr = @ptrCast(*align(1) const EbpHdr, body);
368 s.result_cached = ebp_hdr.flags.cache_hit;
369 result = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]);
370 },
371 else => {}, // ignore other messages
372 }
373
374 stdout.discard(body.len);
374375 }
375376
376377 const stderr = poller.fifo(.stderr);