zig

fork of https://codeberg.org/ziglang/zig
Log | Tree | Refs | README | LICENSE

commit cf87026e52f7faa090c5fa922d5649f5ec2f1831 (tree)
parent 711b656773fe1d3840c74a4ea1e526ae9bf589fb
Author: Veikka Tuominen <git@vexu.eu>
Date:   Sat, 16 Jul 2022 23:46:24 +0300

Sema: `@alignCast` safety

Diffstat:
Msrc/Sema.zig | 32++++++++++++++++++++++++++++++--
Atest/cases/compile_errors/bad_alignCast_at_comptime.zig | 11+++++++++++
Dtest/cases/compile_errors/stage1/obj/bad_alignCast_at_comptime.zig | 11-----------
Mtest/cases/safety/@alignCast misaligned.zig | 11++++++-----
4 files changed, 47 insertions(+), 18 deletions(-)

diff --git a/src/Sema.zig b/src/Sema.zig @@ -16278,8 +16278,6 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A // TODO compile error if the result pointer is comptime known and would have an // alignment that disagrees with the Decl's alignment. - // TODO insert safety check that the alignment is correct - const ptr_info = ptr_ty.ptrInfo().data; const dest_ty = try Type.ptr(sema.arena, sema.mod, .{ .pointee_type = ptr_info.pointee_type, @@ -16290,6 +16288,36 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A .@"volatile" = ptr_info.@"volatile", .size = ptr_info.size, }); + + if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |val| { + if (try val.getUnsignedIntAdvanced(sema.mod.getTarget(), null)) |addr| { + if (addr % dest_align != 0) { + return sema.fail(block, ptr_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, dest_align }); + } + } + return sema.addConstant(dest_ty, val); + } + + try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src); + if (block.wantSafety() and dest_align > 1) { + const val_payload = try sema.arena.create(Value.Payload.U64); + val_payload.* = .{ + .base = .{ .tag = .int_u64 }, + .data = dest_align - 1, + }; + const align_minus_1 = try sema.addConstant( + Type.usize, + Value.initPayload(&val_payload.base), + ); + const actual_ptr = if (ptr_ty.isSlice()) + try sema.analyzeSlicePtr(block, ptr_src, ptr, ptr_ty) + else + ptr; + const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr); + const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1); + const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); + try sema.addSafetyCheck(block, is_aligned, .incorrect_alignment); + } return sema.coerceCompatiblePtrs(block, dest_ty, ptr, ptr_src); } diff --git a/test/cases/compile_errors/bad_alignCast_at_comptime.zig b/test/cases/compile_errors/bad_alignCast_at_comptime.zig @@ -0,0 +1,11 @@ +comptime { + const ptr = @intToPtr(*align(1) i32, 0x1); + const aligned = @alignCast(4, ptr); + _ = aligned; +} + +// error +// backend=stage2 +// target=native +// +// :3:35: error: pointer address 0x1 is not aligned to 4 bytes diff --git a/test/cases/compile_errors/stage1/obj/bad_alignCast_at_comptime.zig b/test/cases/compile_errors/stage1/obj/bad_alignCast_at_comptime.zig @@ -1,11 +0,0 @@ -comptime { - const ptr = @intToPtr(*align(1) i32, 0x1); - const aligned = @alignCast(4, ptr); - _ = aligned; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:35: error: pointer address 0x1 is not aligned to 4 bytes diff --git a/test/cases/safety/@alignCast misaligned.zig b/test/cases/safety/@alignCast misaligned.zig @@ -1,9 +1,11 @@ const std = @import("std"); pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { - _ = message; _ = stack_trace; - std.process.exit(0); + if (std.mem.eql(u8, message, "incorrect alignment")) { + std.process.exit(0); + } + std.process.exit(1); } pub fn main() !void { @@ -18,5 +20,5 @@ fn foo(bytes: []u8) u32 { return int_slice[0]; } // run -// backend=stage1 -// target=native -\ No newline at end of file +// backend=llvm +// target=native