commit 1d0a77647a7a165215ee915e0857efa4d620f574
parent 131d90a4171e3ad38303c3a8d769233dde585802
Author: Eyal Sawady <ecs@d2evs.net>
Date: Fri, 13 Aug 2021 11:10:59 +0000
gen: fix off-by-one in slice/delete bounds check
foo[len(foo)..] is valid
Signed-off-by: Eyal Sawady <ecs@d2evs.net>
Diffstat:
3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/src/gen.c b/src/gen.c
@@ -1531,7 +1531,7 @@ gen_expr_delete(struct gen_context *ctx, const struct expression *expr)
struct qbe_value start_oob = mkqtmp(ctx, &qbe_word, ".%d");
struct qbe_value end_oob = mkqtmp(ctx, &qbe_word, ".%d");
struct qbe_value valid = mkqtmp(ctx, &qbe_word, ".%d");
- pushi(ctx->current, &start_oob, Q_CULTL, &qstart, &qlen, NULL);
+ pushi(ctx->current, &start_oob, Q_CULEL, &qstart, &qlen, NULL);
pushi(ctx->current, &end_oob, Q_CULEL, &qend, &qlen, NULL);
pushi(ctx->current, &valid, Q_AND, &start_oob, &end_oob, NULL);
@@ -2360,7 +2360,7 @@ gen_expr_slice_at(struct gen_context *ctx,
struct qbe_value start_oob = mkqtmp(ctx, &qbe_word, ".%d");
struct qbe_value end_oob = mkqtmp(ctx, &qbe_word, ".%d");
struct qbe_value valid = mkqtmp(ctx, &qbe_word, ".%d");
- pushi(ctx->current, &start_oob, Q_CULTL, &qstart, &qlength, NULL);
+ pushi(ctx->current, &start_oob, Q_CULEL, &qstart, &qlength, NULL);
pushi(ctx->current, &end_oob, Q_CULEL, &qend, &qlength, NULL);
pushi(ctx->current, &valid, Q_AND, &start_oob, &end_oob, NULL);
diff --git a/tests/08-slices.ha b/tests/08-slices.ha
@@ -108,19 +108,22 @@ fn slicing() void = {
assert_slice_eq(a[..3], [1, 2, 3]);
assert_slice_eq(a[1..3], [2, 3]);
assert_slice_eq(a[1..], [2, 3, 4, 5]);
+ assert_slice_eq(a[5..], []);
let b: []int = [1, 2, 3, 4, 5];
assert_slice_eq(b[..], [1, 2, 3, 4, 5]);
assert_slice_eq(b[..3], [1, 2, 3]);
assert_slice_eq(b[1..3], [2, 3]);
assert_slice_eq(b[1..], [2, 3, 4, 5]);
+ assert_slice_eq(b[5..], []);
let p = &a;
assert_slice_eq(p[..], [1, 2, 3, 4, 5]);
assert_slice_eq(p[..3], [1, 2, 3]);
assert_slice_eq(p[1..3], [2, 3]);
assert_slice_eq(p[1..], [2, 3, 4, 5]);
-
+ assert_slice_eq(p[5..], []);
+
assert(rt::compile(
"fn test() void = { let x = \"test\"; x[1..3]; };"
) != 0, "slicing non-array, non-slice object");
diff --git a/tests/22-delete.ha b/tests/22-delete.ha
@@ -25,6 +25,8 @@ fn slice() void = {
assert(len(x) == 2);
assert(x[0] == 4 && x[1] == 5);
+ delete(x[len(x)..]);
+
static delete(y[..]);
assert(len(x) == 0);
assert(s.capacity < 5);