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:
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 = {