frontend: comptime array slice-by-length OOB detection

This commit is contained in:
Andrew Kelley 2024-03-20 17:02:35 -07:00
parent ab22844176
commit 2583b389ea
3 changed files with 45 additions and 11 deletions

View file

@ -33285,15 +33285,34 @@ fn analyzeSlice(
} }
bounds_check: { bounds_check: {
const actual_len = if (array_ty.zigTypeTag(mod) == .Array) const actual_len = l: {
try mod.intRef(Type.usize, array_ty.arrayLenIncludingSentinel(mod)) if (array_ty.zigTypeTag(mod) == .Array) {
else if (slice_ty.isSlice(mod)) l: { const len = array_ty.arrayLenIncludingSentinel(mod);
const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice); // If the end is comptime-known, we can emit a
break :l if (slice_ty.sentinel(mod) == null) // compile error if it would be out-of-bounds even
slice_len_inst // with a start value of 0.
else if (uncasted_end_opt != .none) {
try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true); if (try sema.resolveDefinedValue(block, end_src, uncasted_end_opt)) |end_val| {
} else break :bounds_check; const end_int = end_val.getUnsignedInt(mod).?;
if (end_int > len) return sema.fail(
block,
end_src,
"slice end index {d} exceeds array length of type '{}'",
.{ end_int, array_ty.fmt(mod) },
);
}
}
break :l try mod.intRef(Type.usize, len);
}
if (slice_ty.isSlice(mod)) {
const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice);
break :l if (slice_ty.sentinel(mod) == null)
slice_len_inst
else
try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true);
}
break :bounds_check;
};
const actual_end = if (slice_sentinel != null) const actual_end = if (slice_sentinel != null)
try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src, true) try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src, true)

View file

@ -0,0 +1,15 @@
export fn b() void {
var buf: [5]u8 = undefined;
_ = buf[foo(6)..][0..10];
return error.TestFailed;
}
fn foo(a: u32) u32 {
return a;
}
// error
// backend=stage2
// target=native
//
// :3:26: error: slice end index 10 exceeds array length of type '[5]u8'

View file

@ -2,14 +2,14 @@ const std = @import("std");
pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
_ = stack_trace; _ = stack_trace;
if (std.mem.eql(u8, message, "index out of bounds: index 16, len 5")) { if (std.mem.eql(u8, message, "index out of bounds: index 9, len 5")) {
std.process.exit(0); std.process.exit(0);
} }
std.process.exit(1); std.process.exit(1);
} }
pub fn main() !void { pub fn main() !void {
var buf: [5]u8 = undefined; var buf: [5]u8 = undefined;
_ = buf[foo(6)..][0..10]; _ = buf[foo(6)..][0..3];
return error.TestFailed; return error.TestFailed;
} }
fn foo(a: u32) u32 { fn foo(a: u32) u32 {