stage2 LLVM: Use a packed aggregate for union payload init

Without the packed qualifier, the type layout that we use to
initialize doesn't match the correct layout of the underlying
storage, causing corrupted data and past-the-end writes.
This commit is contained in:
Cody Tapscott 2022-10-10 23:57:48 -07:00 committed by Andrew Kelley
parent 8635c18e40
commit e6ebdcb82e
3 changed files with 32 additions and 2 deletions

View File

@ -8897,7 +8897,7 @@ pub const FuncGen = struct {
return union_llvm_ty.constInt(tag_int, .False);
}
assert(isByRef(union_ty));
// The llvm type of the alloca will the the named LLVM union type, which will not
// The llvm type of the alloca will be the named LLVM union type, and will not
// necessarily match the format that we need, depending on which tag is active. We
// must construct the correct unnamed struct type here and bitcast, in order to
// then set the fields appropriately.
@ -8922,7 +8922,7 @@ pub const FuncGen = struct {
const fields: [2]*llvm.Type = .{
field_llvm_ty, self.context.intType(8).arrayType(padding_len),
};
break :p self.context.structType(&fields, fields.len, .False);
break :p self.context.structType(&fields, fields.len, .True);
};
if (layout.tag_size == 0) {
const fields: [1]*llvm.Type = .{payload};

View File

@ -100,6 +100,7 @@ test {
_ = @import("behavior/bugs/12928.zig");
_ = @import("behavior/bugs/12945.zig");
_ = @import("behavior/bugs/12984.zig");
_ = @import("behavior/bugs/13128.zig");
_ = @import("behavior/byteswap.zig");
_ = @import("behavior/byval_arg_var.zig");
_ = @import("behavior/call.zig");

View File

@ -0,0 +1,29 @@
const std = @import("std");
const builtin = @import("builtin");
const expect = std.testing.expect;
const U = union(enum) {
x: u128,
y: [17]u8,
};
fn foo(val: U) !void {
try expect(val.x == 1);
}
test "runtime union init, most-aligned field != largest" {
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
var x: u8 = 1;
try foo(.{ .x = x });
const val: U = @unionInit(U, "x", x);
try expect(val.x == 1);
const val2: U = .{ .x = x };
try expect(val2.x == 1);
}