mirror of
https://github.com/odin-lang/Odin.git
synced 2026-01-08 22:13:17 +00:00
Fix constant bounds checking for slicing
This commit is contained in:
@@ -2777,7 +2777,7 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
|
||||
update_expr_type(c, operand->expr, target_type, true);
|
||||
}
|
||||
|
||||
bool check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *value) {
|
||||
bool check_index_value(Checker *c, bool open_range, AstNode *index_value, i64 max_count, i64 *value) {
|
||||
Operand operand = {Addressing_Invalid};
|
||||
check_expr(c, &operand, index_value);
|
||||
if (operand.mode == Addressing_Invalid) {
|
||||
@@ -2812,7 +2812,13 @@ bool check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *val
|
||||
|
||||
if (max_count >= 0) { // NOTE(bill): Do array bound checking
|
||||
if (value) *value = i;
|
||||
if (i >= max_count) {
|
||||
bool out_of_bounds = false;
|
||||
if (open_range) {
|
||||
out_of_bounds = i >= max_count;
|
||||
} else {
|
||||
out_of_bounds = i > max_count;
|
||||
}
|
||||
if (out_of_bounds) {
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
error_node(operand.expr, "Index `%s` is out of bounds range 0..<%lld", expr_str, max_count);
|
||||
gb_string_free(expr_str);
|
||||
@@ -3323,7 +3329,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
||||
isize size_count = 0;
|
||||
for (isize i = 1; i < arg_count; i++) {
|
||||
i64 val = 0;
|
||||
bool ok = check_index_value(c, ce->args.e[i], -1, &val);
|
||||
bool ok = check_index_value(c, false, ce->args.e[i], -1, &val);
|
||||
if (ok && val >= 0) {
|
||||
GB_ASSERT(size_count < gb_count_of(sizes));
|
||||
sizes[size_count++] = val;
|
||||
@@ -4129,7 +4135,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
||||
isize size_count = 0;
|
||||
for (isize i = 1; i < arg_count; i++) {
|
||||
i64 val = 0;
|
||||
bool ok = check_index_value(c, ce->args.e[i], -1, &val);
|
||||
bool ok = check_index_value(c, false, ce->args.e[i], -1, &val);
|
||||
if (ok && val >= 0) {
|
||||
GB_ASSERT(size_count < gb_count_of(sizes));
|
||||
sizes[size_count++] = val;
|
||||
@@ -5664,7 +5670,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
|
||||
}
|
||||
|
||||
i64 index = 0;
|
||||
bool ok = check_index_value(c, ie->index, max_count, &index);
|
||||
bool ok = check_index_value(c, false, ie->index, max_count, &index);
|
||||
|
||||
case_end;
|
||||
|
||||
@@ -5767,7 +5773,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
|
||||
capacity = max_count;
|
||||
}
|
||||
i64 j = 0;
|
||||
if (check_index_value(c, nodes[i], capacity, &j)) {
|
||||
if (check_index_value(c, interval_kind == Token_Ellipsis, nodes[i], capacity, &j)) {
|
||||
index = j;
|
||||
}
|
||||
} else if (i == 0) {
|
||||
|
||||
15
src/ir.c
15
src/ir.c
@@ -4913,16 +4913,12 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
||||
if (se->high != NULL) high = ir_build_expr(proc, se->high);
|
||||
if (se->max != NULL) max = ir_build_expr(proc, se->max);
|
||||
|
||||
bool add_one_to_len = false;
|
||||
bool add_one_to_cap = false;
|
||||
|
||||
if (high != NULL && se->interval0.kind == Token_Ellipsis) {
|
||||
add_one_to_len = true;
|
||||
high = ir_emit_arith(proc, Token_Add, high, v_one, t_int);
|
||||
}
|
||||
|
||||
if (max != NULL && se->interval1.kind == Token_Ellipsis) {
|
||||
GB_ASSERT(se->interval0.kind == se->interval1.kind);
|
||||
add_one_to_cap = true;
|
||||
max = ir_emit_arith(proc, Token_Add, max, v_one, t_int);
|
||||
}
|
||||
|
||||
irValue *addr = ir_build_addr(proc, se->expr).addr;
|
||||
@@ -4948,8 +4944,6 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
||||
irValue *elem = ir_emit_ptr_offset(proc, ir_slice_elem(proc, base), low);
|
||||
irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
|
||||
irValue *cap = ir_emit_arith(proc, Token_Sub, max, low, t_int);
|
||||
if (add_one_to_len) len = ir_emit_arith(proc, Token_Add, len, v_one, t_int);
|
||||
if (add_one_to_cap) cap = ir_emit_arith(proc, Token_Add, cap, v_one, t_int);
|
||||
|
||||
irValue *slice = ir_add_local_generated(proc, slice_type);
|
||||
ir_fill_slice(proc, slice, elem, len, cap);
|
||||
@@ -4968,8 +4962,6 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
||||
irValue *elem = ir_emit_ptr_offset(proc, ir_dynamic_array_elem(proc, base), low);
|
||||
irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
|
||||
irValue *cap = ir_emit_arith(proc, Token_Sub, max, low, t_int);
|
||||
if (add_one_to_len) len = ir_emit_arith(proc, Token_Add, len, v_one, t_int);
|
||||
if (add_one_to_cap) cap = ir_emit_arith(proc, Token_Add, cap, v_one, t_int);
|
||||
|
||||
irValue *slice = ir_add_local_generated(proc, slice_type);
|
||||
ir_fill_slice(proc, slice, elem, len, cap);
|
||||
@@ -4988,8 +4980,6 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
||||
irValue *elem = ir_emit_ptr_offset(proc, ir_array_elem(proc, addr), low);
|
||||
irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
|
||||
irValue *cap = ir_emit_arith(proc, Token_Sub, max, low, t_int);
|
||||
if (add_one_to_len) len = ir_emit_arith(proc, Token_Add, len, v_one, t_int);
|
||||
if (add_one_to_cap) cap = ir_emit_arith(proc, Token_Add, cap, v_one, t_int);
|
||||
|
||||
irValue *slice = ir_add_local_generated(proc, slice_type);
|
||||
ir_fill_slice(proc, slice, elem, len, cap);
|
||||
@@ -5005,7 +4995,6 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
||||
|
||||
irValue *elem = ir_emit_ptr_offset(proc, ir_string_elem(proc, base), low);
|
||||
irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
|
||||
if (add_one_to_len) len = ir_emit_arith(proc, Token_Add, len, v_one, t_int);
|
||||
|
||||
irValue *str = ir_add_local_generated(proc, t_string);
|
||||
ir_fill_string(proc, str, elem, len);
|
||||
|
||||
Reference in New Issue
Block a user