Skip to content

Commit

Permalink
Add mask before truncating dereferenced bit pointers (#9584)
Browse files Browse the repository at this point in the history
  • Loading branch information
Snektron committed Aug 19, 2021
1 parent 4c9d417 commit 5cd1d42
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 5 deletions.
13 changes: 8 additions & 5 deletions src/stage1/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3831,23 +3831,26 @@ 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);
return result_loc;
}

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) {
Expand Down
1 change: 1 addition & 0 deletions test/behavior.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
60 changes: 60 additions & 0 deletions test/behavior/bugs/9584.zig
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit 5cd1d42

Please sign in to comment.