diff options
| author | Alex Rønne Petersen <alex@alexrp.com> | 2025-02-15 02:44:58 +0100 |
|---|---|---|
| committer | Alex Rønne Petersen <alex@alexrp.com> | 2025-02-22 04:12:46 +0100 |
| commit | fc7a0c4878dac2d721ec18cafe1b6bcff7faa771 (patch) | |
| tree | 5b9e4ef2d18e3daaf4bee34ae1bfe5af97916e8a /src | |
| parent | d31bda13cb1ece7dd2ba22339172a8704a84823c (diff) | |
| download | zig-fc7a0c4878dac2d721ec18cafe1b6bcff7faa771.tar.gz zig-fc7a0c4878dac2d721ec18cafe1b6bcff7faa771.zip | |
Sema: Fix fnptr alignment safety checks to account for potential ISA tag.
As seen on e.g. Arm/Thumb and MIPS (MIPS16/microMIPS).
Fixes #22888.
Diffstat (limited to 'src')
| -rw-r--r-- | src/Sema.zig | 30 | ||||
| -rw-r--r-- | src/Type.zig | 7 | ||||
| -rw-r--r-- | src/target.zig | 11 |
3 files changed, 42 insertions, 6 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index cbfeef6339..7e3ab51a29 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -23099,8 +23099,14 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! } if (ptr_align.compare(.gt, .@"1")) { const align_bytes_minus_1 = ptr_align.toByteUnits().? - 1; - const align_minus_1 = Air.internedToRef((try sema.splat(operand_ty, try pt.intValue(Type.usize, align_bytes_minus_1))).toIntern()); - const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1); + const align_mask = Air.internedToRef((try sema.splat(operand_ty, try pt.intValue( + Type.usize, + if (elem_ty.fnPtrMaskOrNull(zcu)) |mask| + align_bytes_minus_1 & mask + else + align_bytes_minus_1, + ))).toIntern()); + const remainder = try block.addBinOp(.bit_and, operand_coerced, align_mask); const is_aligned = if (is_vector) all_aligned: { const splat_zero_usize = Air.internedToRef((try sema.splat(operand_ty, .zero_usize)).toIntern()); const is_aligned = try block.addCmpVector(remainder, splat_zero_usize, .eq); @@ -23129,8 +23135,14 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! } if (ptr_align.compare(.gt, .@"1")) { const align_bytes_minus_1 = ptr_align.toByteUnits().? - 1; - const align_minus_1 = Air.internedToRef((try pt.intValue(Type.usize, align_bytes_minus_1)).toIntern()); - const remainder = try block.addBinOp(.bit_and, elem_coerced, align_minus_1); + const align_mask = Air.internedToRef((try pt.intValue( + Type.usize, + if (elem_ty.fnPtrMaskOrNull(zcu)) |mask| + align_bytes_minus_1 & mask + else + align_bytes_minus_1, + )).toIntern()); + const remainder = try block.addBinOp(.bit_and, elem_coerced, align_mask); const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment); } @@ -23710,13 +23722,19 @@ fn ptrCastFull( try Type.fromInterned(dest_info.child).hasRuntimeBitsSema(pt)) { const align_bytes_minus_1 = dest_align.toByteUnits().? - 1; - const align_minus_1 = Air.internedToRef((try pt.intValue(Type.usize, align_bytes_minus_1)).toIntern()); + const align_mask = Air.internedToRef((try pt.intValue( + Type.usize, + if (Type.fromInterned(dest_info.child).fnPtrMaskOrNull(zcu)) |mask| + align_bytes_minus_1 & mask + else + align_bytes_minus_1, + )).toIntern()); const actual_ptr = if (src_info.flags.size == .slice) try sema.analyzeSlicePtr(block, src, ptr, operand_ty) else ptr; const ptr_int = try block.addBitCast(.usize, actual_ptr); - const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1); + const remainder = try block.addBinOp(.bit_and, ptr_int, align_mask); const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); const ok = if (src_info.flags.size == .slice and dest_info.flags.size == .slice) ok: { const len = try sema.analyzeSliceLen(block, operand_src, ptr); diff --git a/src/Type.zig b/src/Type.zig index 7ddd43b034..883c752ef1 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -2541,6 +2541,13 @@ pub fn fnIsVarArgs(ty: Type, zcu: *const Zcu) bool { return zcu.intern_pool.indexToKey(ty.toIntern()).func_type.is_var_args; } +pub fn fnPtrMaskOrNull(ty: Type, zcu: *const Zcu) ?u64 { + return switch (ty.zigTypeTag(zcu)) { + .@"fn" => target_util.functionPointerMask(zcu.getTarget()), + else => null, + }; +} + pub fn isNumeric(ty: Type, zcu: *const Zcu) bool { return switch (ty.toIntern()) { .f16_type, diff --git a/src/target.zig b/src/target.zig index 8ccec7f7a8..d032b0d16e 100644 --- a/src/target.zig +++ b/src/target.zig @@ -626,6 +626,17 @@ pub fn supportsFunctionAlignment(target: std.Target) bool { }; } +pub fn functionPointerMask(target: std.Target) ?u64 { + // 32-bit Arm uses the LSB to mean that the target function contains Thumb code. + // MIPS uses the LSB to mean that the target function contains MIPS16/microMIPS code. + return if (target.cpu.arch.isArm() or target.cpu.arch.isMIPS32()) + ~@as(u32, 1) + else if (target.cpu.arch.isMIPS64()) + ~@as(u64, 1) + else + null; +} + pub fn supportsTailCall(target: std.Target, backend: std.builtin.CompilerBackend) bool { switch (backend) { .stage1, .stage2_llvm => return @import("codegen/llvm.zig").supportsTailCall(target), |
