authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-14 01:08:30-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-14 01:08:30-05:00
log63d37b7cff0907cdf2361f1d61f19410fd6cc626
tree9fb0e37d65a8cc01c6ff7fcba5a93cbed7075f6c
parent0931b85bd04fb671dce980728a3692de2bd496a5

add runtime debug safety for dividing integer min value by -1

closes #260

4 files changed, 39 insertions(+), 7 deletions(-)

src/analyze.cpp+1-1
...@@ -3447,7 +3447,7 @@ static int64_t max_signed_val(TypeTableEntry *type_entry) {...@@ -3447,7 +3447,7 @@ static int64_t max_signed_val(TypeTableEntry *type_entry) {
3447 }3447 }
3448}3448}
34493449
3450static int64_t min_signed_val(TypeTableEntry *type_entry) {3450int64_t min_signed_val(TypeTableEntry *type_entry) {
3451 assert(type_entry->id == TypeTableEntryIdInt);3451 assert(type_entry->id == TypeTableEntryIdInt);
3452 if (type_entry->data.integral.bit_count == 64) {3452 if (type_entry->data.integral.bit_count == 64) {
3453 return INT64_MIN;3453 return INT64_MIN;
src/analyze.hpp+1
...@@ -81,6 +81,7 @@ void complete_enum(CodeGen *g, TypeTableEntry *enum_type);...@@ -81,6 +81,7 @@ void complete_enum(CodeGen *g, TypeTableEntry *enum_type);
81bool ir_get_var_is_comptime(VariableTableEntry *var);81bool ir_get_var_is_comptime(VariableTableEntry *var);
82bool const_values_equal(ConstExprValue *a, ConstExprValue *b);82bool const_values_equal(ConstExprValue *a, ConstExprValue *b);
83void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max);83void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max);
84int64_t min_signed_val(TypeTableEntry *type_entry);
8485
85void render_const_value(Buf *buf, ConstExprValue *const_val);86void render_const_value(Buf *buf, ConstExprValue *const_val);
86void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, VariableTableEntry **arg_vars);87void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, VariableTableEntry **arg_vars);
src/codegen.cpp+21-5
...@@ -846,14 +846,30 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, LLVMValueRef val...@@ -846,14 +846,30 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, LLVMValueRef val
846 } else {846 } else {
847 zig_unreachable();847 zig_unreachable();
848 }848 }
849 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroOk");849 LLVMBasicBlockRef div_zero_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroOk");
850 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroFail");850 LLVMBasicBlockRef div_zero_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroFail");
851 LLVMBuildCondBr(g->builder, is_zero_bit, fail_block, ok_block);851 LLVMBuildCondBr(g->builder, is_zero_bit, div_zero_fail_block, div_zero_ok_block);
852852
853 LLVMPositionBuilderAtEnd(g->builder, fail_block);853 LLVMPositionBuilderAtEnd(g->builder, div_zero_fail_block);
854 gen_debug_safety_crash(g, PanicMsgIdDivisionByZero);854 gen_debug_safety_crash(g, PanicMsgIdDivisionByZero);
855855
856 LLVMPositionBuilderAtEnd(g->builder, ok_block);856 LLVMPositionBuilderAtEnd(g->builder, div_zero_ok_block);
857
858 if (type_entry->id == TypeTableEntryIdInt && type_entry->data.integral.is_signed) {
859 LLVMValueRef neg_1_value = LLVMConstInt(type_entry->type_ref, -1, true);
860 LLVMValueRef int_min_value = LLVMConstInt(type_entry->type_ref, min_signed_val(type_entry), true);
861 LLVMBasicBlockRef overflow_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowOk");
862 LLVMBasicBlockRef overflow_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowFail");
863 LLVMValueRef num_is_int_min = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, int_min_value, "");
864 LLVMValueRef den_is_neg_1 = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, neg_1_value, "");
865 LLVMValueRef overflow_fail_bit = LLVMBuildAnd(g->builder, num_is_int_min, den_is_neg_1, "");
866 LLVMBuildCondBr(g->builder, overflow_fail_bit, overflow_fail_block, overflow_ok_block);
867
868 LLVMPositionBuilderAtEnd(g->builder, overflow_fail_block);
869 gen_debug_safety_crash(g, PanicMsgIdIntegerOverflow);
870
871 LLVMPositionBuilderAtEnd(g->builder, overflow_ok_block);
872 }
857 }873 }
858874
859 if (type_entry->id == TypeTableEntryIdFloat) {875 if (type_entry->id == TypeTableEntryIdFloat) {
test/run_tests.cpp+16-1
...@@ -1700,13 +1700,28 @@ pub fn panic(message: []const u8) -> unreachable {...@@ -1700,13 +1700,28 @@ pub fn panic(message: []const u8) -> unreachable {
1700error Whatever;1700error Whatever;
1701pub fn main(args: [][]u8) -> %void {1701pub fn main(args: [][]u8) -> %void {
1702 const x = neg(-32768);1702 const x = neg(-32768);
1703 if (x == 0) return error.Whatever;1703 if (x == 32767) return error.Whatever;
1704}1704}
1705fn neg(a: i16) -> i16 {1705fn neg(a: i16) -> i16 {
1706 -a1706 -a
1707}1707}
1708 )SOURCE");1708 )SOURCE");
17091709
1710 add_debug_safety_case("signed integer division overflow", R"SOURCE(
1711pub fn panic(message: []const u8) -> unreachable {
1712 @breakpoint();
1713 while (true) {}
1714}
1715error Whatever;
1716pub fn main(args: [][]u8) -> %void {
1717 const x = div(-32768, -1);
1718 if (x == 32767) return error.Whatever;
1719}
1720fn div(a: i16, b: i16) -> i16 {
1721 a / b
1722}
1723 )SOURCE");
1724
1710 add_debug_safety_case("signed shift left overflow", R"SOURCE(1725 add_debug_safety_case("signed shift left overflow", R"SOURCE(
1711pub fn panic(message: []const u8) -> unreachable {1726pub fn panic(message: []const u8) -> unreachable {
1712 @breakpoint();1727 @breakpoint();