| author | |
| committer | |
| log | e6ebdcb82ed9fd226ef18670115b8b2617c0a392 |
| tree | 1015c798799df19173c85908dec4a0e2c63adbb0 |
| parent | 8635c18e4091bd3034121ca98439bf40bce72324 |
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 not | 8900 | // 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. We | 8901 | // 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 to | 8902 | // 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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | |||
| 5 | const U = union(enum) { | ||
| 6 | x: u128, | ||
| 7 | y: [17]u8, | ||
| 8 | }; | ||
| 9 | |||
| 10 | fn foo(val: U) !void { | ||
| 11 | try expect(val.x == 1); | ||
| 12 | } | ||
| 13 | |||
| 14 | test "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 | } | ||