authorgravatar for mitchell.hashimoto@gmail.comMitchell Hashimoto <mitchell.hashimoto@gmail.com> 2022-03-25 09:40:11-07:00
committergravatar for mitchell.hashimoto@gmail.comMitchell Hashimoto <mitchell.hashimoto@gmail.com> 2022-03-27 09:20:37-07:00
log8fbac2e86d35bf363b67aba0f1915b7c9d32dcd0
tree76a8a0dc223a24db92c680fc70262ab80ca9b702
parent01698528d1dff627b7e057651b137c20df7c7231
signaturelock-open Commit is signed but in an unrecognized format.

stage2: runtime safety check integer cast truncating bits


5 files changed, 22 insertions(+), 3 deletions(-)

src/Sema.zig+18-3
...@@ -6781,14 +6781,27 @@ fn intCast(...@@ -6781,14 +6781,27 @@ fn intCast(
6781 return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_int'", .{});6781 return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_int'", .{});
6782 }6782 }
67836783
6784 // TODO insert safety check to make sure the value fits in the dest type
6785 _ = runtime_safety;
6786
6787 if ((try sema.typeHasOnePossibleValue(block, dest_ty_src, dest_ty))) |opv| {6784 if ((try sema.typeHasOnePossibleValue(block, dest_ty_src, dest_ty))) |opv| {
6788 return sema.addConstant(dest_ty, opv);6785 return sema.addConstant(dest_ty, opv);
6789 }6786 }
67906787
6791 try sema.requireRuntimeBlock(block, operand_src);6788 try sema.requireRuntimeBlock(block, operand_src);
6789 if (runtime_safety) {
6790 const target = sema.mod.getTarget();
6791 const operand_ty = sema.typeOf(operand);
6792 const actual_info = operand_ty.intInfo(target);
6793 const wanted_info = dest_ty.intInfo(target);
6794 const actual_bits = actual_info.bits;
6795 const wanted_bits = wanted_info.bits;
6796
6797 // requirement: operand can fit into bit size of destination type
6798 if (actual_bits > wanted_bits) {
6799 const max_int = try dest_ty.maxInt(sema.arena, target);
6800 const max_int_inst = try sema.addConstant(operand_ty, max_int);
6801 const is_in_range = try block.addBinOp(.cmp_lte, operand, max_int_inst);
6802 try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data);
6803 }
6804 }
6792 return block.addTyOp(.intcast, dest_ty, operand);6805 return block.addTyOp(.intcast, dest_ty, operand);
6793}6806}
67946807
...@@ -16166,6 +16179,7 @@ pub const PanicId = enum {...@@ -16166,6 +16179,7 @@ pub const PanicId = enum {
16166 incorrect_alignment,16179 incorrect_alignment,
16167 invalid_error_code,16180 invalid_error_code,
16168 index_out_of_bounds,16181 index_out_of_bounds,
16182 cast_truncated_data,
16169};16183};
1617016184
16171fn addSafetyCheck(16185fn addSafetyCheck(
...@@ -16288,6 +16302,7 @@ fn safetyPanic(...@@ -16288,6 +16302,7 @@ fn safetyPanic(
16288 .incorrect_alignment => "incorrect alignment",16302 .incorrect_alignment => "incorrect alignment",
16289 .invalid_error_code => "invalid error code",16303 .invalid_error_code => "invalid error code",
16290 .index_out_of_bounds => "attempt to index out of bounds",16304 .index_out_of_bounds => "attempt to index out of bounds",
16305 .cast_truncated_data => "integer cast truncated bits",
16291 };16306 };
1629216307
16293 const msg_inst = msg_inst: {16308 const msg_inst = msg_inst: {
test/behavior/eval.zig+1
...@@ -443,6 +443,7 @@ fn copyWithPartialInline(s: []u32, b: []u8) void {...@@ -443,6 +443,7 @@ fn copyWithPartialInline(s: []u32, b: []u8) void {
443test "binary math operator in partially inlined function" {443test "binary math operator in partially inlined function" {
444 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO444 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
445 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO445 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
446 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
446447
447 var s: [4]u32 = undefined;448 var s: [4]u32 = undefined;
448 var b: [16]u8 = undefined;449 var b: [16]u8 = undefined;
test/behavior/fn.zig+1
...@@ -315,6 +315,7 @@ test "function pointers" {...@@ -315,6 +315,7 @@ test "function pointers" {
315 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO315 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
316 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO316 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
317 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO317 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
318 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
318319
319 const fns = [_]*const @TypeOf(fn1){320 const fns = [_]*const @TypeOf(fn1){
320 &fn1,321 &fn1,
test/behavior/for.zig+1
...@@ -69,6 +69,7 @@ test "basic for loop" {...@@ -69,6 +69,7 @@ test "basic for loop" {
69 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;69 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
70 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;70 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
72 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
7273
73 const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;74 const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;
7475
test/behavior/int128.zig+1
...@@ -46,6 +46,7 @@ test "int128" {...@@ -46,6 +46,7 @@ test "int128" {
46 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO46 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
47 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO47 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO48 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
49 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
4950
50 var buff: i128 = -1;51 var buff: i128 = -1;
51 try expect(buff < 0 and (buff + 1) == 0);52 try expect(buff < 0 and (buff + 1) == 0);