| author | |
| committer | |
| log | d9d840a33ac8abb0e616de862f592821a7f4a35e |
| tree | dd17b4f37cf2b08816af8a99159e5630c6268b35 |
| parent | a04d4330945565b8d6f298ace993f6954c42d0f3 |
| parent | 41d5aa1b365516c5f1bad63bfa3bdd7ad0ba6842 |
| signature |
sema: add compile error for OOB by-length slice of array4 files changed, 76 insertions(+), 0 deletions(-)
lib/std/json/static.zig+12| ... | @@ -402,21 +402,33 @@ pub fn innerParse( | ... | @@ -402,21 +402,33 @@ pub fn innerParse( |
| 402 | }, | 402 | }, |
| 403 | .partial_string_escaped_1 => |arr| { | 403 | .partial_string_escaped_1 => |arr| { |
| 404 | if (i + arr.len > r.len) return error.LengthMismatch; | 404 | if (i + arr.len > r.len) return error.LengthMismatch; |
| 405 | // tell the compiler that the by-length slice below is valid; | ||
| 406 | // this assert is required for the inequality to be comptime-known | ||
| 407 | if (arr.len > r.len) unreachable; | ||
| 405 | @memcpy(r[i..][0..arr.len], arr[0..]); | 408 | @memcpy(r[i..][0..arr.len], arr[0..]); |
| 406 | i += arr.len; | 409 | i += arr.len; |
| 407 | }, | 410 | }, |
| 408 | .partial_string_escaped_2 => |arr| { | 411 | .partial_string_escaped_2 => |arr| { |
| 409 | if (i + arr.len > r.len) return error.LengthMismatch; | 412 | if (i + arr.len > r.len) return error.LengthMismatch; |
| 413 | // tell the compiler that the by-length slice below is valid; | ||
| 414 | // this assert is required for the inequality to be comptime-known | ||
| 415 | if (arr.len > r.len) unreachable; | ||
| 410 | @memcpy(r[i..][0..arr.len], arr[0..]); | 416 | @memcpy(r[i..][0..arr.len], arr[0..]); |
| 411 | i += arr.len; | 417 | i += arr.len; |
| 412 | }, | 418 | }, |
| 413 | .partial_string_escaped_3 => |arr| { | 419 | .partial_string_escaped_3 => |arr| { |
| 414 | if (i + arr.len > r.len) return error.LengthMismatch; | 420 | if (i + arr.len > r.len) return error.LengthMismatch; |
| 421 | // tell the compiler that the by-length slice below is valid; | ||
| 422 | // this assert is required for the inequality to be comptime-known | ||
| 423 | if (arr.len > r.len) unreachable; | ||
| 415 | @memcpy(r[i..][0..arr.len], arr[0..]); | 424 | @memcpy(r[i..][0..arr.len], arr[0..]); |
| 416 | i += arr.len; | 425 | i += arr.len; |
| 417 | }, | 426 | }, |
| 418 | .partial_string_escaped_4 => |arr| { | 427 | .partial_string_escaped_4 => |arr| { |
| 419 | if (i + arr.len > r.len) return error.LengthMismatch; | 428 | if (i + arr.len > r.len) return error.LengthMismatch; |
| 429 | // tell the compiler that the by-length slice below is valid; | ||
| 430 | // this assert is required for the inequality to be comptime-known | ||
| 431 | if (arr.len > r.len) unreachable; | ||
| 420 | @memcpy(r[i..][0..arr.len], arr[0..]); | 432 | @memcpy(r[i..][0..arr.len], arr[0..]); |
| 421 | i += arr.len; | 433 | i += arr.len; |
| 422 | }, | 434 | }, |
src/Sema.zig+24| ... | @@ -32160,6 +32160,30 @@ fn analyzeSlice( | ... | @@ -32160,6 +32160,30 @@ fn analyzeSlice( |
| 32160 | if (!end_is_len) { | 32160 | if (!end_is_len) { |
| 32161 | const end = if (by_length) end: { | 32161 | const end = if (by_length) end: { |
| 32162 | const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); | 32162 | const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); |
| 32163 | if (try sema.resolveValue(len)) |slice_len_val| { | ||
| 32164 | const len_s_val = try mod.intValue( | ||
| 32165 | Type.usize, | ||
| 32166 | array_ty.arrayLenIncludingSentinel(mod), | ||
| 32167 | ); | ||
| 32168 | if (!(try sema.compareScalar(slice_len_val, .lte, len_s_val, Type.usize))) { | ||
| 32169 | const sentinel_label: []const u8 = if (array_ty.sentinel(mod) != null) | ||
| 32170 | " +1 (sentinel)" | ||
| 32171 | else | ||
| 32172 | ""; | ||
| 32173 | |||
| 32174 | return sema.fail( | ||
| 32175 | block, | ||
| 32176 | end_src, | ||
| 32177 | "length {} out of bounds for array of length {}{s}", | ||
| 32178 | .{ | ||
| 32179 | slice_len_val.fmtValue(Type.usize, mod), | ||
| 32180 | len_val.fmtValue(Type.usize, mod), | ||
| 32181 | sentinel_label, | ||
| 32182 | }, | ||
| 32183 | ); | ||
| 32184 | } | ||
| 32185 | } | ||
| 32186 | // check len is less than array size if comptime known | ||
| 32163 | const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false); | 32187 | const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false); |
| 32164 | break :end try sema.coerce(block, Type.usize, uncasted_end, end_src); | 32188 | break :end try sema.coerce(block, Type.usize, uncasted_end, end_src); |
| 32165 | } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); | 32189 | } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); |
test/cases/compile_errors/slice_of_array_by-length_oversized.zig created+19| ... | @@ -0,0 +1,19 @@ | ||
| 1 | export fn entry1() void { | ||
| 2 | var buf: [5]u8 = undefined; | ||
| 3 | var a: u32 = 6; | ||
| 4 | _ = &a; | ||
| 5 | _ = buf[a..][0..10]; | ||
| 6 | } | ||
| 7 | |||
| 8 | export fn entry2() void { | ||
| 9 | var buf: [5]u8 = undefined; | ||
| 10 | const a: u32 = 6; | ||
| 11 | _ = buf[a..][0..10]; | ||
| 12 | } | ||
| 13 | |||
| 14 | // error | ||
| 15 | // backend=stage2 | ||
| 16 | // target=native | ||
| 17 | // | ||
| 18 | // :5:21: error: length 10 out of bounds for array of length 5 | ||
| 19 | // :11:21: error: length 10 out of bounds for array of length 5 | ||
test/cases/safety/array slice by-length oversized.zig	 created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { | ||
| 4 | _ = stack_trace; | ||
| 5 | if (std.mem.eql(u8, message, "index out of bounds: index 12, len 5")) { | ||
| 6 | std.process.exit(0); | ||
| 7 | } | ||
| 8 | std.process.exit(1); | ||
| 9 | } | ||
| 10 | |||
| 11 | pub fn main() !void { | ||
| 12 | var buf: [5]u8 = undefined; | ||
| 13 | var a: u32 = 6; | ||
| 14 | _ = &a; | ||
| 15 | _ = buf[a..][0..a]; | ||
| 16 | return error.TestFailed; | ||
| 17 | } | ||
| 18 | |||
| 19 | // run | ||
| 20 | // backend=llvm | ||
| 21 | // target=native | ||