authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-29 14:29:50+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-29 15:47:02+02:00
log6337c04244d9c27cc6535340347d4c127f4742eb
tree3e70b1474b28a0f10428255648b59ab64a71b35d
parent6f9c7e33b956686ebfd4690c7f85a602d0ac9ffe

Sema: improve panic for slice start index being greater than end index

Closes #13689

3 files changed, 86 insertions(+), 12 deletions(-)

lib/std/builtin.zig+8-3
...@@ -863,10 +863,9 @@ pub fn panicOutOfBounds(index: usize, len: usize) noreturn {...@@ -863,10 +863,9 @@ pub fn panicOutOfBounds(index: usize, len: usize) noreturn {
863 std.debug.panicExtra(null, @returnAddress(), "index out of bounds: index {d}, len {d}", .{ index, len });863 std.debug.panicExtra(null, @returnAddress(), "index out of bounds: index {d}, len {d}", .{ index, len });
864}864}
865865
866pub noinline fn returnError(st: *StackTrace) void {866pub fn panicStartGreaterThanEnd(start: usize, end: usize) noreturn {
867 @setCold(true);867 @setCold(true);
868 @setRuntimeSafety(false);868 std.debug.panicExtra(null, @returnAddress(), "start index {d} is larger than end index {d}", .{ start, end });
869 addErrRetTraceAddr(st, @returnAddress());
870}869}
871870
872pub const panic_messages = struct {871pub const panic_messages = struct {
...@@ -889,6 +888,12 @@ pub const panic_messages = struct {...@@ -889,6 +888,12 @@ pub const panic_messages = struct {
889 pub const invalid_enum_value = "invalid enum value";888 pub const invalid_enum_value = "invalid enum value";
890};889};
891890
891pub noinline fn returnError(st: *StackTrace) void {
892 @setCold(true);
893 @setRuntimeSafety(false);
894 addErrRetTraceAddr(st, @returnAddress());
895}
896
892pub inline fn addErrRetTraceAddr(st: *StackTrace, addr: usize) void {897pub inline fn addErrRetTraceAddr(st: *StackTrace, addr: usize) void {
893 if (st.index < st.instruction_addresses.len)898 if (st.index < st.instruction_addresses.len)
894 st.instruction_addresses[st.index] = addr;899 st.instruction_addresses[st.index] = addr;
src/Sema.zig+55-9
...@@ -12437,7 +12437,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -12437,7 +12437,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
12437 else12437 else
12438 try sema.resolveInst(.zero);12438 try sema.resolveInst(.zero);
1243912439
12440 return sema.analyzeArithmetic(block, .sub, lhs, rhs, src, lhs_src, rhs_src);12440 return sema.analyzeArithmetic(block, .sub, lhs, rhs, src, lhs_src, rhs_src, true);
12441}12441}
1244212442
12443fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {12443fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -12460,7 +12460,7 @@ fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -12460,7 +12460,7 @@ fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
12460 else12460 else
12461 try sema.resolveInst(.zero);12461 try sema.resolveInst(.zero);
1246212462
12463 return sema.analyzeArithmetic(block, .subwrap, lhs, rhs, src, lhs_src, rhs_src);12463 return sema.analyzeArithmetic(block, .subwrap, lhs, rhs, src, lhs_src, rhs_src, true);
12464}12464}
1246512465
12466fn zirArithmetic(12466fn zirArithmetic(
...@@ -12480,7 +12480,7 @@ fn zirArithmetic(...@@ -12480,7 +12480,7 @@ fn zirArithmetic(
12480 const lhs = try sema.resolveInst(extra.lhs);12480 const lhs = try sema.resolveInst(extra.lhs);
12481 const rhs = try sema.resolveInst(extra.rhs);12481 const rhs = try sema.resolveInst(extra.rhs);
1248212482
12483 return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src);12483 return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src, true);
12484}12484}
1248512485
12486fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {12486fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -13776,6 +13776,7 @@ fn analyzeArithmetic(...@@ -13776,6 +13776,7 @@ fn analyzeArithmetic(
13776 src: LazySrcLoc,13776 src: LazySrcLoc,
13777 lhs_src: LazySrcLoc,13777 lhs_src: LazySrcLoc,
13778 rhs_src: LazySrcLoc,13778 rhs_src: LazySrcLoc,
13779 want_safety: bool,
13779) CompileError!Air.Inst.Ref {13780) CompileError!Air.Inst.Ref {
13780 const lhs_ty = sema.typeOf(lhs);13781 const lhs_ty = sema.typeOf(lhs);
13781 const rhs_ty = sema.typeOf(rhs);13782 const rhs_ty = sema.typeOf(rhs);
...@@ -14204,7 +14205,7 @@ fn analyzeArithmetic(...@@ -14204,7 +14205,7 @@ fn analyzeArithmetic(
14204 };14205 };
1420514206
14206 try sema.requireRuntimeBlock(block, src, rs.src);14207 try sema.requireRuntimeBlock(block, src, rs.src);
14207 if (block.wantSafety()) {14208 if (block.wantSafety() and want_safety) {
14208 if (scalar_tag == .Int) {14209 if (scalar_tag == .Int) {
14209 const maybe_op_ov: ?Air.Inst.Tag = switch (rs.air_tag) {14210 const maybe_op_ov: ?Air.Inst.Tag = switch (rs.air_tag) {
14210 .add => .add_with_overflow,14211 .add => .add_with_overflow,
...@@ -22334,6 +22335,47 @@ fn panicIndexOutOfBounds(...@@ -22334,6 +22335,47 @@ fn panicIndexOutOfBounds(
22334 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);22335 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
22335}22336}
2233622337
22338fn panicStartLargerThanEnd(
22339 sema: *Sema,
22340 parent_block: *Block,
22341 src: LazySrcLoc,
22342 start: Air.Inst.Ref,
22343 end: Air.Inst.Ref,
22344) !void {
22345 assert(!parent_block.is_comptime);
22346 const ok = try parent_block.addBinOp(.cmp_lte, start, end);
22347 const gpa = sema.gpa;
22348
22349 var fail_block: Block = .{
22350 .parent = parent_block,
22351 .sema = sema,
22352 .src_decl = parent_block.src_decl,
22353 .namespace = parent_block.namespace,
22354 .wip_capture_scope = parent_block.wip_capture_scope,
22355 .instructions = .{},
22356 .inlining = parent_block.inlining,
22357 .is_comptime = false,
22358 };
22359
22360 defer fail_block.instructions.deinit(gpa);
22361
22362 {
22363 const this_feature_is_implemented_in_the_backend =
22364 sema.mod.comp.bin_file.options.use_llvm;
22365
22366 if (!this_feature_is_implemented_in_the_backend) {
22367 // TODO implement this feature in all the backends and then delete this branch
22368 _ = try fail_block.addNoOp(.breakpoint);
22369 _ = try fail_block.addNoOp(.unreach);
22370 } else {
22371 const panic_fn = try sema.getBuiltin("panicStartGreaterThanEnd");
22372 const args: [2]Air.Inst.Ref = .{ start, end };
22373 _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args, null);
22374 }
22375 }
22376 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
22377}
22378
22337fn panicSentinelMismatch(22379fn panicSentinelMismatch(
22338 sema: *Sema,22380 sema: *Sema,
22339 parent_block: *Block,22381 parent_block: *Block,
...@@ -28028,7 +28070,11 @@ fn analyzeSlice(...@@ -28028,7 +28070,11 @@ fn analyzeSlice(
28028 }28070 }
28029 }28071 }
2803028072
28031 const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src);28073 if (block.wantSafety() and !block.is_comptime) {
28074 // requirement: start <= end
28075 try sema.panicStartLargerThanEnd(block, src, start, end);
28076 }
28077 const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false);
28032 const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len);28078 const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len);
2803328079
28034 const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data;28080 const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data;
...@@ -28063,10 +28109,10 @@ fn analyzeSlice(...@@ -28063,10 +28109,10 @@ fn analyzeSlice(
28063 const actual_len = if (slice_ty.sentinel() == null)28109 const actual_len = if (slice_ty.sentinel() == null)
28064 slice_len_inst28110 slice_len_inst
28065 else28111 else
28066 try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src);28112 try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true);
2806728113
28068 const actual_end = if (slice_sentinel != null)28114 const actual_end = if (slice_sentinel != null)
28069 try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src)28115 try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src, true)
28070 else28116 else
28071 end;28117 end;
2807228118
...@@ -28131,11 +28177,11 @@ fn analyzeSlice(...@@ -28131,11 +28177,11 @@ fn analyzeSlice(
28131 if (slice_ty.sentinel() == null) break :blk slice_len_inst;28177 if (slice_ty.sentinel() == null) break :blk slice_len_inst;
2813228178
28133 // we have to add one because slice lengths don't include the sentinel28179 // we have to add one because slice lengths don't include the sentinel
28134 break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src);28180 break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true);
28135 } else null;28181 } else null;
28136 if (opt_len_inst) |len_inst| {28182 if (opt_len_inst) |len_inst| {
28137 const actual_end = if (slice_sentinel != null)28183 const actual_end = if (slice_sentinel != null)
28138 try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src)28184 try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src, true)
28139 else28185 else
28140 end;28186 end;
28141 try sema.panicIndexOutOfBounds(block, src, actual_end, len_inst, .cmp_lte);28187 try sema.panicIndexOutOfBounds(block, src, actual_end, len_inst, .cmp_lte);
test/cases/safety/slice start index greater than end index.zig created+23
...@@ -0,0 +1,23 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "start index 10 is larger than end index 1")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 var a: usize = 1;
13 var b: usize = 10;
14 var buf: [16]u8 = undefined;
15
16 const slice = buf[b..a];
17 _ = slice;
18 return error.TestFailed;
19}
20
21// run
22// backend=llvm
23// target=native