authorgravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-10-10 23:57:48-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-11 15:42:01-04:00
loge6ebdcb82ed9fd226ef18670115b8b2617c0a392
tree1015c798799df19173c85908dec4a0e2c63adbb0
parent8635c18e4091bd3034121ca98439bf40bce72324

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.

3 files changed, 32 insertions(+), 2 deletions(-)

src/codegen/llvm.zig+2-2
......@@ -8897,7 +8897,7 @@ pub const FuncGen = struct {
88978897 return union_llvm_ty.constInt(tag_int, .False);
88988898 }
88998899 assert(isByRef(union_ty));
8900 // The llvm type of the alloca will the the named LLVM union type, which will not
8900 // The llvm type of the alloca will be the named LLVM union type, and will not
89018901 // necessarily match the format that we need, depending on which tag is active. We
89028902 // must construct the correct unnamed struct type here and bitcast, in order to
89038903 // then set the fields appropriately.
......@@ -8922,7 +8922,7 @@ pub const FuncGen = struct {
89228922 const fields: [2]*llvm.Type = .{
89238923 field_llvm_ty, self.context.intType(8).arrayType(padding_len),
89248924 };
8925 break :p self.context.structType(&fields, fields.len, .False);
8925 break :p self.context.structType(&fields, fields.len, .True);
89268926 };
89278927 if (layout.tag_size == 0) {
89288928 const fields: [1]*llvm.Type = .{payload};
test/behavior.zig+1
......@@ -100,6 +100,7 @@ test {
100100 _ = @import("behavior/bugs/12928.zig");
101101 _ = @import("behavior/bugs/12945.zig");
102102 _ = @import("behavior/bugs/12984.zig");
103 _ = @import("behavior/bugs/13128.zig");
103104 _ = @import("behavior/byteswap.zig");
104105 _ = @import("behavior/byval_arg_var.zig");
105106 _ = @import("behavior/call.zig");
test/behavior/bugs/13128.zig created+29
......@@ -0,0 +1,29 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4
5const U = union(enum) {
6 x: u128,
7 y: [17]u8,
8};
9
10fn foo(val: U) !void {
11 try expect(val.x == 1);
12}
13
14test "runtime union init, most-aligned field != largest" {
15 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
19 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
20
21 var x: u8 = 1;
22 try foo(.{ .x = x });
23
24 const val: U = @unionInit(U, "x", x);
25 try expect(val.x == 1);
26
27 const val2: U = .{ .x = x };
28 try expect(val2.x == 1);
29}