diff options
| author | Veikka Tuominen <git@vexu.eu> | 2024-01-29 14:33:53 +0200 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2024-01-29 17:35:07 -0800 |
| commit | 7d75c3d3b80c86bbd47e60f85a98e8decc52c611 (patch) | |
| tree | c52ddac06bfb3495f19e426020c5a693d3f8f480 /src/codegen/llvm.zig | |
| parent | 4dfca01de4fda9a195048011b3339686dce4e936 (diff) | |
| download | zig-7d75c3d3b80c86bbd47e60f85a98e8decc52c611.tar.gz zig-7d75c3d3b80c86bbd47e60f85a98e8decc52c611.zip | |
llvm: ensure returned undef is 0xaa bytes when runtime safety is enabled
Closes #13178
Diffstat (limited to 'src/codegen/llvm.zig')
| -rw-r--r-- | src/codegen/llvm.zig | 54 |
1 files changed, 51 insertions, 3 deletions
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 5cbcf6b3d6..a425511e51 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -5078,7 +5078,8 @@ pub const FuncGen = struct { .load => try self.airLoad(body[i..]), .loop => try self.airLoop(inst), .not => try self.airNot(inst), - .ret => try self.airRet(inst), + .ret => try self.airRet(inst, false), + .ret_safe => try self.airRet(inst, true), .ret_load => try self.airRetLoad(inst), .store => try self.airStore(inst, false), .store_safe => try self.airStore(inst, true), @@ -5551,15 +5552,42 @@ pub const FuncGen = struct { _ = try fg.wip.@"unreachable"(); } - fn airRet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { + fn airRet(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !Builder.Value { const o = self.dg.object; const mod = o.module; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const ret_ty = self.typeOf(un_op); + if (self.ret_ptr != .none) { - const operand = try self.resolveInst(un_op); const ptr_ty = try mod.singleMutPtrType(ret_ty); + const operand = try self.resolveInst(un_op); + const val_is_undef = if (try self.air.value(un_op, mod)) |val| val.isUndefDeep(mod) else false; + if (val_is_undef and safety) undef: { + const ptr_info = ptr_ty.ptrInfo(mod); + const needs_bitmask = (ptr_info.packed_offset.host_size != 0); + if (needs_bitmask) { + // TODO: only some bits are to be undef, we cannot write with a simple memset. + // meanwhile, ignore the write rather than stomping over valid bits. + // https://github.com/ziglang/zig/issues/15337 + break :undef; + } + const len = try o.builder.intValue(try o.lowerType(Type.usize), ret_ty.abiSize(mod)); + _ = try self.wip.callMemSet( + self.ret_ptr, + ptr_ty.ptrAlignment(mod).toLlvm(), + try o.builder.intValue(.i8, 0xaa), + len, + if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal, + ); + const owner_mod = self.dg.ownerModule(); + if (owner_mod.valgrind) { + try self.valgrindMarkUndef(self.ret_ptr, len); + } + _ = try self.wip.retVoid(); + return .none; + } + const unwrapped_operand = operand.unwrap(); const unwrapped_ret = self.ret_ptr.unwrap(); @@ -5588,8 +5616,28 @@ pub const FuncGen = struct { const abi_ret_ty = try lowerFnRetTy(o, fn_info); const operand = try self.resolveInst(un_op); + const val_is_undef = if (try self.air.value(un_op, mod)) |val| val.isUndefDeep(mod) else false; const alignment = ret_ty.abiAlignment(mod).toLlvm(); + if (val_is_undef and safety) { + const llvm_ret_ty = operand.typeOfWip(&self.wip); + const rp = try self.buildAlloca(llvm_ret_ty, alignment); + const len = try o.builder.intValue(try o.lowerType(Type.usize), ret_ty.abiSize(mod)); + _ = try self.wip.callMemSet( + rp, + alignment, + try o.builder.intValue(.i8, 0xaa), + len, + .normal, + ); + const owner_mod = self.dg.ownerModule(); + if (owner_mod.valgrind) { + try self.valgrindMarkUndef(rp, len); + } + _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, rp, alignment, "")); + return .none; + } + if (isByRef(ret_ty, mod)) { // operand is a pointer however self.ret_ptr is null so that means // we need to return a value. |
