Commit 5605f6e0e3

Veikka Tuominen <git@vexu.eu>
2022-08-05 16:08:31
Sema: account for sentinel in bounds check
1 parent 6aa438f
src/Sema.zig
@@ -25574,6 +25574,22 @@ fn analyzeSlice(
                     const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true);
                     try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
                 }
+
+                if (slice_ty.isSlice()) {
+                    const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice);
+                    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);
+
+                    const actual_end = if (slice_sentinel != null)
+                        try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src)
+                    else
+                        end;
+
+                    try sema.panicIndexOutOfBounds(block, src, actual_end, actual_len, .cmp_lte);
+                }
+
                 // requirement: result[new_len] == slice_sentinel
                 try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len);
             }
@@ -25635,7 +25651,11 @@ fn analyzeSlice(
             break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src);
         } else null;
         if (opt_len_inst) |len_inst| {
-            try sema.panicIndexOutOfBounds(block, src, end, len_inst, .cmp_lte);
+            const actual_end = if (slice_sentinel != null)
+                try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src)
+            else
+                end;
+            try sema.panicIndexOutOfBounds(block, src, actual_end, len_inst, .cmp_lte);
         }
 
         // requirement: start <= end
test/cases/safety/cast []u8 to bigger slice of wrong size.zig
@@ -1,9 +1,11 @@
 const std = @import("std");
 
 pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
-    _ = message;
     _ = stack_trace;
-    std.process.exit(0);
+    if (std.mem.eql(u8, message, "exact division produced remainder")) {
+        std.process.exit(0);
+    }
+    std.process.exit(1);
 }
 
 pub fn main() !void {
@@ -15,5 +17,5 @@ fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {
     return std.mem.bytesAsSlice(i32, slice);
 }
 // run
-// backend=stage1
-// target=native
\ No newline at end of file
+// backend=llvm
+// target=native
test/cases/safety/empty slice with sentinel out of bounds.zig
@@ -2,7 +2,7 @@ const std = @import("std");
 
 pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
     _ = stack_trace;
-    if (std.mem.eql(u8, message, "index out of bounds")) {
+    if (std.mem.eql(u8, message, "attempt to index out of bound: index 1, len 0")) {
         std.process.exit(0);
     }
     std.process.exit(1);
@@ -17,5 +17,5 @@ pub fn main() !void {
 }
 
 // run
-// backend=stage1
+// backend=llvm
 // target=native
test/cases/safety/slice with sentinel out of bounds - runtime len.zig
@@ -0,0 +1,22 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+    _ = stack_trace;
+    if (std.mem.eql(u8, message, "attempt to index out of bound: index 5, len 4")) {
+        std.process.exit(0);
+    }
+    std.process.exit(1);
+}
+
+pub fn main() !void {
+    var buf = [4]u8{ 'a', 'b', 'c', 0 };
+    const input: []u8 = &buf;
+    var len: usize = 4;
+    const slice = input[0..len :0];
+    _ = slice;
+    return error.TestFailed;
+}
+
+// run
+// backend=llvm
+// target=native
test/cases/safety/slice with sentinel out of bounds.zig
@@ -2,7 +2,7 @@ const std = @import("std");
 
 pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
     _ = stack_trace;
-    if (std.mem.eql(u8, message, "index out of bounds")) {
+    if (std.mem.eql(u8, message, "attempt to index out of bound: index 5, len 4")) {
         std.process.exit(0);
     }
     std.process.exit(1);
@@ -17,5 +17,5 @@ pub fn main() !void {
 }
 
 // run
-// backend=stage1
+// backend=llvm
 // target=native