verbose_air: zero padding in Air.Inst.Data when collecting

Air.Inst.Data is a union; variants smaller than 8 bytes (un_op,
no_op, ty, repeat) leave padding bytes uninitialised.  Zero the
destination buffer and copy only the meaningful bytes per instruction
so that byte-level comparisons in tests are deterministic and
valgrind-clean.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-20 08:42:53 +00:00
parent b359a8d5f8
commit 67b821e925

View File

@@ -10,6 +10,34 @@ const Compilation = zig_internals.Compilation;
const Package = zig_internals.Package;
const Air = zig_internals.Air;
/// Number of meaningful bytes in Air.Inst.Data for a given tag.
/// Variants smaller than 8 bytes leave padding uninitialised; callers
/// must only copy this many bytes and zero the rest.
fn airInstDataSize(tag: Air.Inst.Tag) usize {
return switch (tag) {
// no_op: 0 meaningful bytes
.ret_addr, .frame_addr => 0,
// un_op: 4 meaningful bytes (single Ref / u32)
.sqrt, .sin, .cos, .tan, .exp, .exp2,
.log, .log2, .log10,
.floor, .ceil, .round, .trunc_float,
.neg, .neg_optimized,
.is_null, .is_non_null, .is_null_ptr, .is_non_null_ptr,
.is_err, .is_non_err, .is_err_ptr, .is_non_err_ptr,
.ret, .ret_safe, .ret_load,
.is_named_enum_value, .tag_name, .error_name,
.cmp_lt_errors_len,
.c_va_end,
=> 4,
// ty: 4 meaningful bytes (single Type / u32)
.alloc, .ret_ptr, .c_va_start => 4,
// repeat: 4 meaningful bytes (single Index / u32)
.repeat => 4,
// All other variants use the full 8 bytes.
else => 8,
};
}
/// Matches C `Air` struct layout (air.h).
const CAir = extern struct {
inst_len: u32,
@@ -64,20 +92,20 @@ const AirCollector = struct {
break :blk dst.ptr;
} else null;
// Copy datas (8 bytes per instruction)
// Copy datas (8 bytes per instruction).
// Air.Inst.Data is a union; variants smaller than 8 bytes
// (un_op, no_op, ty, repeat) leave padding bytes uninitialised.
// Zero the buffer first, then copy only the meaningful bytes
// per instruction so that padding is deterministically zero.
const datas_byte_len = inst_len * 8;
const datas_copy: ?[*]u8 = if (inst_len > 0) blk: {
const dst = try gpa.alloc(u8, datas_byte_len);
@memset(dst, 0);
const zig_datas = air.instructions.items(.data);
if (@sizeOf(Air.Inst.Data) == 8) {
const src = @as([*]const u8, @ptrCast(zig_datas.ptr))[0..datas_byte_len];
@memcpy(dst, src);
} else {
// Safety build: @sizeOf(Data) may be > 8, copy first 8 bytes per element
for (zig_datas, 0..) |*d, i| {
const src = @as(*const [8]u8, @ptrCast(d));
@memcpy(dst[i * 8 ..][0..8], src);
}
for (0..inst_len) |i| {
const src = @as(*const [8]u8, @ptrCast(&zig_datas[i]));
const n = airInstDataSize(zig_tags[i]);
@memcpy(dst[i * 8 ..][0..n], src[0..n]);
}
break :blk dst.ptr;
} else null;