From 17485110589c953aa39de75a9fb75ac415e4f9cd Mon Sep 17 00:00:00 2001 From: dweiller <4678790+dweiller@users.noreply.github.com> Date: Sat, 30 Dec 2023 14:37:35 +1100 Subject: [PATCH] sema: add compile error for OOB by-length slice of array --- src/Sema.zig | 24 +++++++++++++++++++ .../slice_of_array_by-length_oversized.zig | 19 +++++++++++++++ .../array slice by-length oversized.zig | 21 ++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 test/cases/compile_errors/slice_of_array_by-length_oversized.zig create mode 100644 test/cases/safety/array slice by-length oversized.zig diff --git a/src/Sema.zig b/src/Sema.zig index d99e7827be..9ac69b7ae8 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