Commit cf87026e52

Veikka Tuominen <git@vexu.eu>
2022-07-16 22:46:24
Sema: `@alignCast` safety
1 parent 711b656
Changed files (3)
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);
 }
 
test/cases/compile_errors/stage1/obj/bad_alignCast_at_comptime.zig → test/cases/compile_errors/bad_alignCast_at_comptime.zig
@@ -5,7 +5,7 @@ comptime {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:3:35: error: pointer address 0x1 is not aligned to 4 bytes
+// :3:35: error: pointer address 0x1 is not aligned to 4 bytes
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