Browse Source

Fix constant bounds checking for slicing

Ginger Bill 8 years ago
parent
commit
0ea815db49
5 changed files with 22 additions and 26 deletions
  1. 1 0
      core/_preload.odin
  2. 4 4
      core/strconv.odin
  3. 3 3
      core/utf16.odin
  4. 12 6
      src/check_expr.c
  5. 2 13
      src/ir.c

+ 1 - 0
core/_preload.odin

@@ -350,6 +350,7 @@ __slice_expr_error :: proc(file: string, line, column: int, low, high, max: int)
 	            file, line, column, low, high, max);
 	__debug_trap();
 }
+
 __substring_expr_error :: proc(file: string, line, column: int, low, high: int) {
 	if 0 <= low && low <= high {
 		return;

+ 4 - 4
core/strconv.odin

@@ -21,12 +21,12 @@ parse_bool :: proc(s: string) -> (result: bool, ok: bool) {
 _digit_value :: proc(r: rune) -> (int) {
 	ri := cast(int)r;
 	v: int = 16;
-	match {
-	case '0' <= r && r <= '9':
+	match r {
+	case '0'..'9':
 		v = ri - '0';
-	case 'a' <= r && r <= 'z':
+	case 'a'..'z':
 		v = ri - 'a' + 10;
-	case 'A' <= r && r <= 'Z':
+	case 'A'..'Z':
 		v = ri - 'A' + 10;
 	}
 	return v;

+ 3 - 3
core/utf16.odin

@@ -39,12 +39,12 @@ encode :: proc(d: []u16, s: []rune) {
 	n = 0;
 
 	for r in s {
-		match {
-		case 0 <= r && r < _surr1, _surr3 <= r && r < _surr_self:
+		match r {
+		case 0..<_surr1, _surr3..<_surr_self:
 			d[n] = cast(u16)r;
 			n++;
 
-		case _surr_self <= r && r <= MAX_RUNE:
+		case _surr_self..MAX_RUNE:
 			r1, r2 := encode_surrogate_pair(r);
 			d[n]    = cast(u16)r1;
 			d[n+1]  = cast(u16)r2;

+ 12 - 6
src/check_expr.c

@@ -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) {

+ 2 - 13
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);