Commit 6337c04244
Changed files (3)
lib/std/builtin.zig
@@ -863,10 +863,9 @@ pub fn panicOutOfBounds(index: usize, len: usize) noreturn {
std.debug.panicExtra(null, @returnAddress(), "index out of bounds: index {d}, len {d}", .{ index, len });
}
-pub noinline fn returnError(st: *StackTrace) void {
+pub fn panicStartGreaterThanEnd(start: usize, end: usize) noreturn {
@setCold(true);
- @setRuntimeSafety(false);
- addErrRetTraceAddr(st, @returnAddress());
+ std.debug.panicExtra(null, @returnAddress(), "start index {d} is larger than end index {d}", .{ start, end });
}
pub const panic_messages = struct {
@@ -889,6 +888,12 @@ pub const panic_messages = struct {
pub const invalid_enum_value = "invalid enum value";
};
+pub noinline fn returnError(st: *StackTrace) void {
+ @setCold(true);
+ @setRuntimeSafety(false);
+ addErrRetTraceAddr(st, @returnAddress());
+}
+
pub inline fn addErrRetTraceAddr(st: *StackTrace, addr: usize) void {
if (st.index < st.instruction_addresses.len)
st.instruction_addresses[st.index] = addr;
src/Sema.zig
@@ -12437,7 +12437,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
else
try sema.resolveInst(.zero);
- return sema.analyzeArithmetic(block, .sub, lhs, rhs, src, lhs_src, rhs_src);
+ return sema.analyzeArithmetic(block, .sub, lhs, rhs, src, lhs_src, rhs_src, true);
}
fn 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!
else
try sema.resolveInst(.zero);
- return sema.analyzeArithmetic(block, .subwrap, lhs, rhs, src, lhs_src, rhs_src);
+ return sema.analyzeArithmetic(block, .subwrap, lhs, rhs, src, lhs_src, rhs_src, true);
}
fn zirArithmetic(
@@ -12480,7 +12480,7 @@ fn zirArithmetic(
const lhs = try sema.resolveInst(extra.lhs);
const rhs = try sema.resolveInst(extra.rhs);
- return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src);
+ return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src, true);
}
fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -13776,6 +13776,7 @@ fn analyzeArithmetic(
src: LazySrcLoc,
lhs_src: LazySrcLoc,
rhs_src: LazySrcLoc,
+ want_safety: bool,
) CompileError!Air.Inst.Ref {
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
@@ -14204,7 +14205,7 @@ fn analyzeArithmetic(
};
try sema.requireRuntimeBlock(block, src, rs.src);
- if (block.wantSafety()) {
+ if (block.wantSafety() and want_safety) {
if (scalar_tag == .Int) {
const maybe_op_ov: ?Air.Inst.Tag = switch (rs.air_tag) {
.add => .add_with_overflow,
@@ -22334,6 +22335,47 @@ fn panicIndexOutOfBounds(
try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
}
+fn panicStartLargerThanEnd(
+ sema: *Sema,
+ parent_block: *Block,
+ src: LazySrcLoc,
+ start: Air.Inst.Ref,
+ end: Air.Inst.Ref,
+) !void {
+ assert(!parent_block.is_comptime);
+ const ok = try parent_block.addBinOp(.cmp_lte, start, end);
+ const gpa = sema.gpa;
+
+ var fail_block: Block = .{
+ .parent = parent_block,
+ .sema = sema,
+ .src_decl = parent_block.src_decl,
+ .namespace = parent_block.namespace,
+ .wip_capture_scope = parent_block.wip_capture_scope,
+ .instructions = .{},
+ .inlining = parent_block.inlining,
+ .is_comptime = false,
+ };
+
+ defer fail_block.instructions.deinit(gpa);
+
+ {
+ const this_feature_is_implemented_in_the_backend =
+ sema.mod.comp.bin_file.options.use_llvm;
+
+ if (!this_feature_is_implemented_in_the_backend) {
+ // TODO implement this feature in all the backends and then delete this branch
+ _ = try fail_block.addNoOp(.breakpoint);
+ _ = try fail_block.addNoOp(.unreach);
+ } else {
+ const panic_fn = try sema.getBuiltin("panicStartGreaterThanEnd");
+ const args: [2]Air.Inst.Ref = .{ start, end };
+ _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args, null);
+ }
+ }
+ try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
+}
+
fn panicSentinelMismatch(
sema: *Sema,
parent_block: *Block,
@@ -28028,7 +28070,11 @@ fn analyzeSlice(
}
}
- const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src);
+ if (block.wantSafety() and !block.is_comptime) {
+ // requirement: start <= end
+ try sema.panicStartLargerThanEnd(block, src, start, end);
+ }
+ const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false);
const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len);
const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data;
@@ -28063,10 +28109,10 @@ fn analyzeSlice(
const actual_len = if (slice_ty.sentinel() == null)
slice_len_inst
else
- try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src);
+ try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true);
const actual_end = if (slice_sentinel != null)
- try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src)
+ try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src, true)
else
end;
@@ -28131,11 +28177,11 @@ fn analyzeSlice(
if (slice_ty.sentinel() == null) break :blk slice_len_inst;
// we have to add one because slice lengths don't include the sentinel
- break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src);
+ break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true);
} else null;
if (opt_len_inst) |len_inst| {
const actual_end = if (slice_sentinel != null)
- try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src)
+ try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src, true)
else
end;
try sema.panicIndexOutOfBounds(block, src, actual_end, len_inst, .cmp_lte);
test/cases/safety/slice start index greater than end index.zig
@@ -0,0 +1,23 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "start index 10 is larger than end index 1")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+pub fn main() !void {
+ var a: usize = 1;
+ var b: usize = 10;
+ var buf: [16]u8 = undefined;
+
+ const slice = buf[b..a];
+ _ = slice;
+ return error.TestFailed;
+}
+
+// run
+// backend=llvm
+// target=native