aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/std/json/static.zig12
-rw-r--r--src/Sema.zig24
-rw-r--r--test/cases/compile_errors/slice_of_array_by-length_oversized.zig19
-rw-r--r--test/cases/safety/array slice by-length oversized.zig21
4 files changed, 76 insertions, 0 deletions
diff --git a/lib/std/json/static.zig b/lib/std/json/static.zig
index ea0bb6c0f2..d4ae6053f4 100644
--- a/lib/std/json/static.zig
+++ b/lib/std/json/static.zig
@@ -402,21 +402,33 @@ pub fn innerParse(
},
.partial_string_escaped_1 => |arr| {
if (i + arr.len > r.len) return error.LengthMismatch;
+ // tell the compiler that the by-length slice below is valid;
+ // this assert is required for the inequality to be comptime-known
+ if (arr.len > r.len) unreachable;
@memcpy(r[i..][0..arr.len], arr[0..]);
i += arr.len;
},
.partial_string_escaped_2 => |arr| {
if (i + arr.len > r.len) return error.LengthMismatch;
+ // tell the compiler that the by-length slice below is valid;
+ // this assert is required for the inequality to be comptime-known
+ if (arr.len > r.len) unreachable;
@memcpy(r[i..][0..arr.len], arr[0..]);
i += arr.len;
},
.partial_string_escaped_3 => |arr| {
if (i + arr.len > r.len) return error.LengthMismatch;
+ // tell the compiler that the by-length slice below is valid;
+ // this assert is required for the inequality to be comptime-known
+ if (arr.len > r.len) unreachable;
@memcpy(r[i..][0..arr.len], arr[0..]);
i += arr.len;
},
.partial_string_escaped_4 => |arr| {
if (i + arr.len > r.len) return error.LengthMismatch;
+ // tell the compiler that the by-length slice below is valid;
+ // this assert is required for the inequality to be comptime-known
+ if (arr.len > r.len) unreachable;
@memcpy(r[i..][0..arr.len], arr[0..]);
i += arr.len;
},
diff --git a/src/Sema.zig b/src/Sema.zig
index 2f1dc07328..e9af6d1740 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -32160,6 +32160,30 @@ fn analyzeSlice(
if (!end_is_len) {
const end = if (by_length) end: {
const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
+ if (try sema.resolveValue(len)) |slice_len_val| {
+ const len_s_val = try mod.intValue(
+ Type.usize,
+ array_ty.arrayLenIncludingSentinel(mod),
+ );
+ if (!(try sema.compareScalar(slice_len_val, .lte, len_s_val, Type.usize))) {
+ const sentinel_label: []const u8 = if (array_ty.sentinel(mod) != null)
+ " +1 (sentinel)"
+ else
+ "";
+
+ return sema.fail(
+ block,
+ end_src,
+ "length {} out of bounds for array of length {}{s}",
+ .{
+ slice_len_val.fmtValue(Type.usize, mod),
+ len_val.fmtValue(Type.usize, mod),
+ sentinel_label,
+ },
+ );
+ }
+ }
+ // check len is less than array size if comptime known
const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false);
break :end try sema.coerce(block, Type.usize, uncasted_end, end_src);
} else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
diff --git a/test/cases/compile_errors/slice_of_array_by-length_oversized.zig b/test/cases/compile_errors/slice_of_array_by-length_oversized.zig
new file mode 100644
index 0000000000..e482197d1a
--- /dev/null
+++ b/test/cases/compile_errors/slice_of_array_by-length_oversized.zig
@@ -0,0 +1,19 @@
+export fn entry1() void {
+ var buf: [5]u8 = undefined;
+ var a: u32 = 6;
+ _ = &a;
+ _ = buf[a..][0..10];
+}
+
+export fn entry2() void {
+ var buf: [5]u8 = undefined;
+ const a: u32 = 6;
+ _ = buf[a..][0..10];
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :5:21: error: length 10 out of bounds for array of length 5
+// :11:21: error: length 10 out of bounds for array of length 5
diff --git a/test/cases/safety/array slice by-length oversized.zig b/test/cases/safety/array slice by-length oversized.zig
new file mode 100644
index 0000000000..a8b33e428a
--- /dev/null
+++ b/test/cases/safety/array slice by-length oversized.zig
@@ -0,0 +1,21 @@
+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, "index out of bounds: index 12, len 5")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+pub fn main() !void {
+ var buf: [5]u8 = undefined;
+ var a: u32 = 6;
+ _ = &a;
+ _ = buf[a..][0..a];
+ return error.TestFailed;
+}
+
+// run
+// backend=llvm
+// target=native