authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-04-23 11:25:06+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-16 17:42:51-07:00
log0a7f3be42e96361ab8a9a567a11782fb81ea17da
tree00d7f058255cf7f812f9611206a43ab6874b9de7
parentab4ec35b8bb3a19361afa315f77cce5f6054b109

Sema: improve index out of bounds panic message


2 files changed, 60 insertions(+), 56 deletions(-)

lib/std/builtin.zig+6
...@@ -847,9 +847,15 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn...@@ -847,9 +847,15 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn
847}847}
848848
849pub fn panicUnwrapError(st: ?*StackTrace, err: anyerror) noreturn {849pub fn panicUnwrapError(st: ?*StackTrace, err: anyerror) noreturn {
850 @setCold(true);
850 std.debug.panicExtra(st, "attempt to unwrap error: {s}", .{@errorName(err)});851 std.debug.panicExtra(st, "attempt to unwrap error: {s}", .{@errorName(err)});
851}852}
852853
854pub fn panicOutOfBounds(index: usize, len: usize) noreturn {
855 @setCold(true);
856 std.debug.panic("attempt to index out of bound: index {d}, len {d}", .{ index, len });
857}
858
853pub noinline fn returnError(maybe_st: ?*StackTrace) void {859pub noinline fn returnError(maybe_st: ?*StackTrace) void {
854 @setCold(true);860 @setCold(true);
855 const st = maybe_st orelse return;861 const st = maybe_st orelse return;
src/Sema.zig+54-56
...@@ -16857,7 +16857,6 @@ pub const PanicId = enum {...@@ -16857,7 +16857,6 @@ pub const PanicId = enum {
16857 cast_to_null,16857 cast_to_null,
16858 incorrect_alignment,16858 incorrect_alignment,
16859 invalid_error_code,16859 invalid_error_code,
16860 index_out_of_bounds,
16861 cast_truncated_data,16860 cast_truncated_data,
16862 integer_overflow,16861 integer_overflow,
16863 shl_overflow,16862 shl_overflow,
...@@ -16886,6 +16885,17 @@ fn addSafetyCheck(...@@ -16886,6 +16885,17 @@ fn addSafetyCheck(
1688616885
16887 _ = try sema.safetyPanic(&fail_block, .unneeded, panic_id);16886 _ = try sema.safetyPanic(&fail_block, .unneeded, panic_id);
1688816887
16888 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
16889}
16890
16891fn addSafetyCheckExtra(
16892 sema: *Sema,
16893 parent_block: *Block,
16894 ok: Air.Inst.Ref,
16895 fail_block: *Block,
16896) !void {
16897 const gpa = sema.gpa;
16898
16889 try parent_block.instructions.ensureUnusedCapacity(gpa, 1);16899 try parent_block.instructions.ensureUnusedCapacity(gpa, 1);
1689016900
16891 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +16901 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
...@@ -16994,7 +17004,6 @@ fn panicUnwrapError(...@@ -16994,7 +17004,6 @@ fn panicUnwrapError(
1699417004
16995 {17005 {
16996 const this_feature_is_implemented_in_the_backend =17006 const this_feature_is_implemented_in_the_backend =
16997 sema.mod.comp.bin_file.options.object_format == .c or
16998 sema.mod.comp.bin_file.options.use_llvm;17007 sema.mod.comp.bin_file.options.use_llvm;
1699917008
17000 if (!this_feature_is_implemented_in_the_backend) {17009 if (!this_feature_is_implemented_in_the_backend) {
...@@ -17009,52 +17018,48 @@ fn panicUnwrapError(...@@ -17009,52 +17018,48 @@ fn panicUnwrapError(
17009 _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args);17018 _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args);
17010 }17019 }
17011 }17020 }
17021 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
17022}
1701217023
17013 try parent_block.instructions.ensureUnusedCapacity(gpa, 1);17024fn panicIndexOutOfBounds(
1701417025 sema: *Sema,
17015 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +17026 parent_block: *Block,
17016 1 + // The main block only needs space for the cond_br.17027 src: LazySrcLoc,
17017 @typeInfo(Air.CondBr).Struct.fields.len +17028 index: Air.Inst.Ref,
17018 1 + // The ok branch of the cond_br only needs space for the br.17029 len: Air.Inst.Ref,
17019 fail_block.instructions.items.len);17030 cmp_op: Air.Inst.Tag,
17031) !void {
17032 const ok = try parent_block.addBinOp(cmp_op, index, len);
17033 const gpa = sema.gpa;
1702017034
17021 try sema.air_instructions.ensureUnusedCapacity(gpa, 3);17035 var fail_block: Block = .{
17022 const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);17036 .parent = parent_block,
17023 const cond_br_inst = block_inst + 1;17037 .sema = sema,
17024 const br_inst = cond_br_inst + 1;17038 .src_decl = parent_block.src_decl,
17025 sema.air_instructions.appendAssumeCapacity(.{17039 .namespace = parent_block.namespace,
17026 .tag = .block,17040 .wip_capture_scope = parent_block.wip_capture_scope,
17027 .data = .{ .ty_pl = .{17041 .instructions = .{},
17028 .ty = .void_type,17042 .inlining = parent_block.inlining,
17029 .payload = sema.addExtraAssumeCapacity(Air.Block{17043 .is_comptime = parent_block.is_comptime,
17030 .body_len = 1,17044 };
17031 }),
17032 } },
17033 });
17034 sema.air_extra.appendAssumeCapacity(cond_br_inst);
1703517045
17036 sema.air_instructions.appendAssumeCapacity(.{17046 defer fail_block.instructions.deinit(gpa);
17037 .tag = .cond_br,
17038 .data = .{ .pl_op = .{
17039 .operand = ok,
17040 .payload = sema.addExtraAssumeCapacity(Air.CondBr{
17041 .then_body_len = 1,
17042 .else_body_len = @intCast(u32, fail_block.instructions.items.len),
17043 }),
17044 } },
17045 });
17046 sema.air_extra.appendAssumeCapacity(br_inst);
17047 sema.air_extra.appendSliceAssumeCapacity(fail_block.instructions.items);
1704817047
17049 sema.air_instructions.appendAssumeCapacity(.{17048 {
17050 .tag = .br,17049 const this_feature_is_implemented_in_the_backend =
17051 .data = .{ .br = .{17050 sema.mod.comp.bin_file.options.use_llvm;
17052 .block_inst = block_inst,
17053 .operand = .void_value,
17054 } },
17055 });
1705617051
17057 parent_block.instructions.appendAssumeCapacity(block_inst);17052 if (!this_feature_is_implemented_in_the_backend) {
17053 // TODO implement this feature in all the backends and then delete this branch
17054 _ = try fail_block.addNoOp(.breakpoint);
17055 _ = try fail_block.addNoOp(.unreach);
17056 } else {
17057 const panic_fn = try sema.getBuiltin(&fail_block, src, "panicOutOfBounds");
17058 const args: [2]Air.Inst.Ref = .{ index, len };
17059 _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args);
17060 }
17061 }
17062 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
17058}17063}
1705917064
17060fn safetyPanic(17065fn safetyPanic(
...@@ -17069,7 +17074,6 @@ fn safetyPanic(...@@ -17069,7 +17074,6 @@ fn safetyPanic(
17069 .cast_to_null => "cast causes pointer to be null",17074 .cast_to_null => "cast causes pointer to be null",
17070 .incorrect_alignment => "incorrect alignment",17075 .incorrect_alignment => "incorrect alignment",
17071 .invalid_error_code => "invalid error code",17076 .invalid_error_code => "invalid error code",
17072 .index_out_of_bounds => "attempt to index out of bounds",
17073 .cast_truncated_data => "integer cast truncated bits",17077 .cast_truncated_data => "integer cast truncated bits",
17074 .integer_overflow => "integer overflow",17078 .integer_overflow => "integer overflow",
17075 .shl_overflow => "left shift overflowed bits",17079 .shl_overflow => "left shift overflowed bits",
...@@ -18261,8 +18265,7 @@ fn elemValArray(...@@ -18261,8 +18265,7 @@ fn elemValArray(
18261 if (maybe_index_val == null) {18265 if (maybe_index_val == null) {
18262 const len_inst = try sema.addIntUnsigned(Type.usize, array_len);18266 const len_inst = try sema.addIntUnsigned(Type.usize, array_len);
18263 const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt;18267 const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt;
18264 const is_in_bounds = try block.addBinOp(cmp_op, elem_index, len_inst);18268 try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op);
18265 try sema.addSafetyCheck(block, is_in_bounds, .index_out_of_bounds);
18266 }18269 }
18267 }18270 }
18268 return block.addBinOp(.array_elem_val, array, elem_index);18271 return block.addBinOp(.array_elem_val, array, elem_index);
...@@ -18317,8 +18320,7 @@ fn elemPtrArray(...@@ -18317,8 +18320,7 @@ fn elemPtrArray(
18317 if (maybe_index_val == null) {18320 if (maybe_index_val == null) {
18318 const len_inst = try sema.addIntUnsigned(Type.usize, array_len);18321 const len_inst = try sema.addIntUnsigned(Type.usize, array_len);
18319 const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt;18322 const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt;
18320 const is_in_bounds = try block.addBinOp(cmp_op, elem_index, len_inst);18323 try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op);
18321 try sema.addSafetyCheck(block, is_in_bounds, .index_out_of_bounds);
18322 }18324 }
18323 }18325 }
18324 return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty);18326 return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty);
...@@ -18371,8 +18373,7 @@ fn elemValSlice(...@@ -18371,8 +18373,7 @@ fn elemValSlice(
18371 else18373 else
18372 try block.addTyOp(.slice_len, Type.usize, slice);18374 try block.addTyOp(.slice_len, Type.usize, slice);
18373 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;18375 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
18374 const is_in_bounds = try block.addBinOp(cmp_op, elem_index, len_inst);18376 try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op);
18375 try sema.addSafetyCheck(block, is_in_bounds, .index_out_of_bounds);
18376 }18377 }
18377 try sema.queueFullTypeResolution(sema.typeOf(slice));18378 try sema.queueFullTypeResolution(sema.typeOf(slice));
18378 return block.addBinOp(.slice_elem_val, slice, elem_index);18379 return block.addBinOp(.slice_elem_val, slice, elem_index);
...@@ -18425,8 +18426,7 @@ fn elemPtrSlice(...@@ -18425,8 +18426,7 @@ fn elemPtrSlice(
18425 break :len try block.addTyOp(.slice_len, Type.usize, slice);18426 break :len try block.addTyOp(.slice_len, Type.usize, slice);
18426 };18427 };
18427 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;18428 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
18428 const is_in_bounds = try block.addBinOp(cmp_op, elem_index, len_inst);18429 try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op);
18429 try sema.addSafetyCheck(block, is_in_bounds, .index_out_of_bounds);
18430 }18430 }
18431 return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty);18431 return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty);
18432}18432}
...@@ -21111,13 +21111,11 @@ fn analyzeSlice(...@@ -21111,13 +21111,11 @@ fn analyzeSlice(
21111 break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src);21111 break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src);
21112 } else null;21112 } else null;
21113 if (opt_len_inst) |len_inst| {21113 if (opt_len_inst) |len_inst| {
21114 const end_is_in_bounds = try block.addBinOp(.cmp_lte, end, len_inst);21114 try sema.panicIndexOutOfBounds(block, src, end, len_inst, .cmp_lte);
21115 try sema.addSafetyCheck(block, end_is_in_bounds, .index_out_of_bounds);
21116 }21115 }
2111721116
21118 // requirement: start <= end21117 // requirement: start <= end
21119 const start_is_in_bounds = try block.addBinOp(.cmp_lte, start, end);21118 try sema.panicIndexOutOfBounds(block, src, start, end, .cmp_lte);
21120 try sema.addSafetyCheck(block, start_is_in_bounds, .index_out_of_bounds);
21121 }21119 }
21122 return block.addInst(.{21120 return block.addInst(.{
21123 .tag = .slice,21121 .tag = .slice,