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 {...@@ -8897,7 +8897,7 @@ pub const FuncGen = struct {
8897 return union_llvm_ty.constInt(tag_int, .False);8897 return union_llvm_ty.constInt(tag_int, .False);
8898 }8898 }
8899 assert(isByRef(union_ty));8899 assert(isByRef(union_ty));
8900 // The llvm type of the alloca will the the named LLVM union type, which will not8900 // The llvm type of the alloca will be the named LLVM union type, and will not
8901 // necessarily match the format that we need, depending on which tag is active. We8901 // necessarily match the format that we need, depending on which tag is active. We
8902 // must construct the correct unnamed struct type here and bitcast, in order to8902 // must construct the correct unnamed struct type here and bitcast, in order to
8903 // then set the fields appropriately.8903 // then set the fields appropriately.
...@@ -8922,7 +8922,7 @@ pub const FuncGen = struct {...@@ -8922,7 +8922,7 @@ pub const FuncGen = struct {
8922 const fields: [2]*llvm.Type = .{8922 const fields: [2]*llvm.Type = .{
8923 field_llvm_ty, self.context.intType(8).arrayType(padding_len),8923 field_llvm_ty, self.context.intType(8).arrayType(padding_len),
8924 };8924 };
8925 break :p self.context.structType(&fields, fields.len, .False);8925 break :p self.context.structType(&fields, fields.len, .True);
8926 };8926 };
8927 if (layout.tag_size == 0) {8927 if (layout.tag_size == 0) {
8928 const fields: [1]*llvm.Type = .{payload};8928 const fields: [1]*llvm.Type = .{payload};
test/behavior.zig+1
...@@ -100,6 +100,7 @@ test {...@@ -100,6 +100,7 @@ test {
100 _ = @import("behavior/bugs/12928.zig");100 _ = @import("behavior/bugs/12928.zig");
101 _ = @import("behavior/bugs/12945.zig");101 _ = @import("behavior/bugs/12945.zig");
102 _ = @import("behavior/bugs/12984.zig");102 _ = @import("behavior/bugs/12984.zig");
103 _ = @import("behavior/bugs/13128.zig");
103 _ = @import("behavior/byteswap.zig");104 _ = @import("behavior/byteswap.zig");
104 _ = @import("behavior/byval_arg_var.zig");105 _ = @import("behavior/byval_arg_var.zig");
105 _ = @import("behavior/call.zig");106 _ = @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}