authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-25 16:10:36-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-25 16:15:48-07:00
logd2ad8afff4c404f6e1a566cce3fa6e7f768503e5
tree28ca64fb5e60cf15fdff8a4c6be921c83b7ce8b1
parent9d231c4991ec1e33c3f4a96e5941848705ef5050

LLVM: fix missing alignment on wrapping instructions

Previously, when lowering AIR instructions `wrap_errunion_payload`, `wrap_errunion_err`, and `wrap_optional`, the LLVM backend would create an alloca instruction to store the result, but did not set the alignment on it. This caused UB which went undetected for a long time until we started enabling the stack protector. Closes #12594 Unblocks #12508 Inspires #12634 Tests passed locally: * test-behavior * test-cases

3 files changed, 39 insertions(+), 3 deletions(-)

src/codegen/llvm.zig+7-3
......@@ -6188,7 +6188,9 @@ pub const FuncGen = struct {
61886188 }
61896189 const llvm_optional_ty = try self.dg.lowerType(optional_ty);
61906190 if (isByRef(optional_ty)) {
6191 const target = self.dg.module.getTarget();
61916192 const optional_ptr = self.buildAlloca(llvm_optional_ty);
6193 optional_ptr.setAlignment(optional_ty.abiAlignment(target));
61926194 const payload_ptr = self.builder.buildStructGEP(optional_ptr, 0, "");
61936195 var ptr_ty_payload: Type.Payload.ElemType = .{
61946196 .base = .{ .tag = .single_mut_pointer },
......@@ -6208,20 +6210,21 @@ pub const FuncGen = struct {
62086210 if (self.liveness.isUnused(inst)) return null;
62096211
62106212 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
6211 const inst_ty = self.air.typeOfIndex(inst);
6213 const err_un_ty = self.air.typeOfIndex(inst);
62126214 const operand = try self.resolveInst(ty_op.operand);
62136215 const payload_ty = self.air.typeOf(ty_op.operand);
62146216 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
62156217 return operand;
62166218 }
62176219 const ok_err_code = (try self.dg.lowerType(Type.anyerror)).constNull();
6218 const err_un_llvm_ty = try self.dg.lowerType(inst_ty);
6220 const err_un_llvm_ty = try self.dg.lowerType(err_un_ty);
62196221
62206222 const target = self.dg.module.getTarget();
62216223 const payload_offset = errUnionPayloadOffset(payload_ty, target);
62226224 const error_offset = errUnionErrorOffset(payload_ty, target);
6223 if (isByRef(inst_ty)) {
6225 if (isByRef(err_un_ty)) {
62246226 const result_ptr = self.buildAlloca(err_un_llvm_ty);
6227 result_ptr.setAlignment(err_un_ty.abiAlignment(target));
62256228 const err_ptr = self.builder.buildStructGEP(result_ptr, error_offset, "");
62266229 const store_inst = self.builder.buildStore(ok_err_code, err_ptr);
62276230 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
......@@ -6256,6 +6259,7 @@ pub const FuncGen = struct {
62566259 const error_offset = errUnionErrorOffset(payload_ty, target);
62576260 if (isByRef(err_un_ty)) {
62586261 const result_ptr = self.buildAlloca(err_un_llvm_ty);
6262 result_ptr.setAlignment(err_un_ty.abiAlignment(target));
62596263 const err_ptr = self.builder.buildStructGEP(result_ptr, error_offset, "");
62606264 const store_inst = self.builder.buildStore(operand, err_ptr);
62616265 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
test/behavior/error.zig+16
......@@ -796,3 +796,19 @@ test "error union of noreturn used with catch" {
796796 const err = NoReturn.testCatch();
797797 try expect(err == error.OtherFailure);
798798}
799
800test "alignment of wrapping an error union payload" {
801 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
802 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
803 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
804
805 const S = struct {
806 const I = extern struct { x: i128 };
807
808 fn foo() anyerror!I {
809 var i: I = .{ .x = 1234 };
810 return i;
811 }
812 };
813 try expect((S.foo() catch unreachable).x == 1234);
814}
test/behavior/optional.zig+16
......@@ -412,3 +412,19 @@ test "orelse on C pointer" {
412412 const d = foo orelse @compileError("bad");
413413 try expectEqual([*c]const u8, @TypeOf(d));
414414}
415
416test "alignment of wrapping an optional payload" {
417 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
418 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
419 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
420
421 const S = struct {
422 const I = extern struct { x: i128 };
423
424 fn foo() ?I {
425 var i: I = .{ .x = 1234 };
426 return i;
427 }
428 };
429 try expect(S.foo().?.x == 1234);
430}