harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

commit 43c2ab14fd8ee84072f850936118795ab46342b6
parent 84fc04c060cf92d0eace6533ed8ef4ebec9cd571
Author: Sebastian <sebastian@sebsite.pw>
Date:   Thu,  5 Jan 2023 18:00:40 -0500

check: add compile-time bounds check for array index

If the index is a constant expression and the length of the array is
defined, a bounds check is performed at compile-time.

Signed-off-by: Sebastian <sebastian@sebsite.pw>

Diffstat:
Msrc/check.c | 29++++++++++++++++++++++++-----
Msrc/eval.c | 1-
Mtests/01-arrays.ha | 7+++++++
3 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/src/check.c b/src/check.c @@ -228,6 +228,23 @@ check_expr_access(struct context *ctx, &builtin_type_size, expr->access.index); expr->result = type_store_lookup_with_flags(ctx->store, atype->array.members, atype->flags | atype->array.members->flags); + + // Compile-time bounds check + if (atype->storage == STORAGE_ARRAY + && atype->array.length != SIZE_UNDEFINED) { + struct expression *evaled = xcalloc(1, sizeof(struct expression)); + enum eval_result r = eval_expr(ctx, expr->access.index, evaled); + if (r == EVAL_OK) { + if (evaled->constant.uval >= atype->array.length) { + error(ctx, aexpr->loc, expr, + "Index must not be greater than array length"); + free(evaled); + return; + } + } + free(evaled); + } + break; case ACCESS_FIELD: expr->access._struct = xcalloc(1, sizeof(struct expression)); @@ -2447,8 +2464,8 @@ slice_bounds_check(struct context *ctx, struct expression *expr) return; } - if (dtype->storage == STORAGE_ARRAY) { - assert(dtype->array.length != SIZE_UNDEFINED); + if (dtype->storage == STORAGE_ARRAY + && dtype->array.length != SIZE_UNDEFINED) { if (end->constant.uval > dtype->array.length) { error(ctx, expr->loc, expr, "End index must not be greater than array length"); @@ -2456,9 +2473,11 @@ slice_bounds_check(struct context *ctx, struct expression *expr) return; } } - } else if (dtype->storage != STORAGE_ARRAY - || dtype->array.length == SIZE_UNDEFINED) { - return; + } else { + if (dtype->storage != STORAGE_ARRAY) { + return; + } + assert(dtype->array.length != SIZE_UNDEFINED); } if (expr->slice.start == NULL) { diff --git a/src/eval.c b/src/eval.c @@ -988,7 +988,6 @@ eval_expr(struct context *ctx, struct expression *in, struct expression *out) case EXPR_VAEND: case EXPR_VASTART: case EXPR_YIELD: - error(ctx, in->loc, "unavailable at translation time"); return EVAL_INVALID; } assert(0); // Unreachable diff --git a/tests/01-arrays.ha b/tests/01-arrays.ha @@ -17,6 +17,13 @@ fn indexing() void = { let q = &x[0]; *q = 1337; assert(x[0] == 1337 && y[0] == 1337); + + assert(compile(" + export fn main() void = { + let a = [1, 2, 3]; + a[3]; + }; + ") as exited != EXIT_SUCCESS); }; fn measurements() void = {