Commit 5cd1d42a35

Robin Voetter <robin@voetter.nl>
2021-08-19 07:20:50
Add mask before truncating dereferenced bit pointers (#9584)
1 parent 4c9d417
Changed files (3)
src
test
behavior
src/stage1/codegen.cpp
@@ -3831,10 +3831,14 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, Stage1Air *executable,
     LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
     LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");
 
+    LLVMTypeRef same_size_int = LLVMIntType(size_in_bits);
+    LLVMValueRef mask = LLVMConstAllOnes(LLVMIntType(size_in_bits));
+    mask = LLVMConstZExt(mask, LLVMTypeOf(containing_int));
+    LLVMValueRef masked_value = LLVMBuildAnd(g->builder, shifted_value, mask, "");
+
     if (handle_is_ptr(g, child_type)) {
         LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc);
-        LLVMTypeRef same_size_int = LLVMIntType(size_in_bits);
-        LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, "");
+        LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, masked_value, same_size_int, "");
         LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, result_loc,
                                                       LLVMPointerType(same_size_int, 0), "");
         LLVMBuildStore(g->builder, truncated_int, bitcasted_ptr);
@@ -3842,12 +3846,11 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, Stage1Air *executable,
     }
 
     if (child_type->id == ZigTypeIdFloat) {
-        LLVMTypeRef same_size_int = LLVMIntType(size_in_bits);
-        LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, "");
+        LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, masked_value, same_size_int, "");
         return LLVMBuildBitCast(g->builder, truncated_int, get_llvm_type(g, child_type), "");
     }
 
-    return LLVMBuildTrunc(g->builder, shifted_value, get_llvm_type(g, child_type), "");
+    return LLVMBuildTrunc(g->builder, masked_value, get_llvm_type(g, child_type), "");
 }
 
 static bool value_is_all_undef_array(CodeGen *g, ZigValue *const_val, size_t len) {
test/behavior/bugs/9584.zig
@@ -0,0 +1,60 @@
+const std = @import("std");
+
+const A = packed struct {
+    a: bool,
+    b: bool,
+    c: bool,
+    d: bool,
+
+    e: bool,
+    f: bool,
+    g: bool,
+    h: bool,
+};
+
+const X = union {
+    x: A,
+    y: u64,
+};
+
+pub fn a(
+    x0: i32,
+    x1: i32,
+    x2: i32,
+    x3: i32,
+    x4: i32,
+    flag_a: bool,
+    flag_b: bool,
+) !void {
+    _ = x0;
+    _ = x1;
+    _ = x2;
+    _ = x3;
+    _ = x4;
+    _ = flag_a;
+    // With this bug present, `flag_b` would actually contain the value 17.
+    // Note: this bug only presents itself on debug mode.
+    try std.testing.expect(@ptrCast(*const u8, &flag_b).* == 1);
+}
+
+pub fn b(x: *X) !void {
+    try a(0, 1, 2, 3, 4, x.x.a, x.x.b);
+}
+
+test "bug 9584" {
+    var flags = A{
+        .a = false,
+        .b = true,
+        .c = false,
+        .d = false,
+
+        .e = false,
+        .f = true,
+        .g = false,
+        .h = false,
+    };
+    var x = X{
+        .x = flags,
+    };
+    try b(&x);
+}
test/behavior.zig
@@ -71,6 +71,7 @@ test {
         _ = @import("behavior/bugs/7047.zig");
         _ = @import("behavior/bugs/7003.zig");
         _ = @import("behavior/bugs/7250.zig");
+        _ = @import("behavior/bugs/9584.zig");
         _ = @import("behavior/bugs/394.zig");
         _ = @import("behavior/bugs/421.zig");
         _ = @import("behavior/bugs/529.zig");