checker: disallow invalid pointer arithmetic (#10888)
parent
4f22ae4a30
commit
12884e9eb7
|
@ -195,13 +195,13 @@ fn (mut c Checker) check_shift(left_type ast.Type, right_type ast.Type, left_pos
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) promote(left_type ast.Type, right_type ast.Type) ast.Type {
|
pub fn (mut c Checker) promote(left_type ast.Type, right_type ast.Type) ast.Type {
|
||||||
if left_type.is_ptr() || left_type.is_pointer() {
|
if left_type.is_any_kind_of_pointer() {
|
||||||
if right_type.is_int() {
|
if right_type.is_int() {
|
||||||
return left_type
|
return left_type
|
||||||
} else {
|
} else {
|
||||||
return ast.void_type
|
return ast.void_type
|
||||||
}
|
}
|
||||||
} else if right_type.is_ptr() || right_type.is_pointer() {
|
} else if right_type.is_any_kind_of_pointer() {
|
||||||
if left_type.is_int() {
|
if left_type.is_int() {
|
||||||
return right_type
|
return right_type
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1241,12 +1241,20 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
||||||
left_pos := node.left.position()
|
left_pos := node.left.position()
|
||||||
right_pos := node.right.position()
|
right_pos := node.right.position()
|
||||||
left_right_pos := left_pos.extend(right_pos)
|
left_right_pos := left_pos.extend(right_pos)
|
||||||
if (left_type.is_ptr() || left_sym.is_pointer()) && node.op in [.plus, .minus] {
|
if left_type.is_any_kind_of_pointer()
|
||||||
if !c.inside_unsafe && !node.left.is_auto_deref_var() && !node.right.is_auto_deref_var() {
|
&& node.op in [.plus, .minus, .mul, .div, .mod, .xor, .amp, .pipe] {
|
||||||
c.warn('pointer arithmetic is only allowed in `unsafe` blocks', left_pos)
|
if (right_type.is_any_kind_of_pointer() && node.op != .minus)
|
||||||
}
|
|| (!right_type.is_any_kind_of_pointer() && node.op !in [.plus, .minus]) {
|
||||||
if left_type == ast.voidptr_type {
|
left_name := c.table.type_to_str(left_type)
|
||||||
c.error('`$node.op` cannot be used with `voidptr`', left_pos)
|
right_name := c.table.type_to_str(right_type)
|
||||||
|
c.error('invalid operator `$node.op` to `$left_name` and `$right_name`', left_right_pos)
|
||||||
|
} else if node.op in [.plus, .minus] {
|
||||||
|
if !c.inside_unsafe && !node.left.is_auto_deref_var() && !node.right.is_auto_deref_var() {
|
||||||
|
c.warn('pointer arithmetic is only allowed in `unsafe` blocks', left_right_pos)
|
||||||
|
}
|
||||||
|
if left_type == ast.voidptr_type {
|
||||||
|
c.error('`$node.op` cannot be used with `voidptr`', left_pos)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut return_type := left_type
|
mut return_type := left_type
|
||||||
|
@ -1408,7 +1416,15 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
||||||
c.error('mismatched types `$left_name` and `$right_name`', left_right_pos)
|
c.error('mismatched types `$left_name` and `$right_name`', left_right_pos)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
promoted_type := c.promote(c.table.unalias_num_type(left_type), c.table.unalias_num_type(right_type))
|
unaliased_left_type := c.table.unalias_num_type(left_type)
|
||||||
|
unalias_right_type := c.table.unalias_num_type(right_type)
|
||||||
|
mut promoted_type := c.promote(unaliased_left_type, unalias_right_type)
|
||||||
|
// substract pointers is allowed in unsafe block
|
||||||
|
is_allowed_pointer_arithmetic := left_type.is_any_kind_of_pointer()
|
||||||
|
&& right_type.is_any_kind_of_pointer() && node.op == .minus
|
||||||
|
if is_allowed_pointer_arithmetic {
|
||||||
|
promoted_type = ast.int_type
|
||||||
|
}
|
||||||
if promoted_type.idx() == ast.void_type_idx {
|
if promoted_type.idx() == ast.void_type_idx {
|
||||||
left_name := c.table.type_to_str(left_type)
|
left_name := c.table.type_to_str(left_type)
|
||||||
right_name := c.table.type_to_str(right_type)
|
right_name := c.table.type_to_str(right_type)
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
vlib/v/checker/tests/disallow_pointer_arithmetic_err.vv:4:7: error: invalid operator `+` to `&int` and `&int`
|
||||||
|
2 | x := 5
|
||||||
|
3 | p := &x
|
||||||
|
4 | _ := p + p //should be error
|
||||||
|
| ~~~~~
|
||||||
|
5 | _ := p * p //should be error
|
||||||
|
6 | _ := p * 2 //should be error
|
||||||
|
vlib/v/checker/tests/disallow_pointer_arithmetic_err.vv:5:7: error: invalid operator `*` to `&int` and `&int`
|
||||||
|
3 | p := &x
|
||||||
|
4 | _ := p + p //should be error
|
||||||
|
5 | _ := p * p //should be error
|
||||||
|
| ~~~~~
|
||||||
|
6 | _ := p * 2 //should be error
|
||||||
|
7 | _ := p + 5 //OK but only in unsafe block, r is *int
|
||||||
|
vlib/v/checker/tests/disallow_pointer_arithmetic_err.vv:6:7: error: invalid operator `*` to `&int` and `int literal`
|
||||||
|
4 | _ := p + p //should be error
|
||||||
|
5 | _ := p * p //should be error
|
||||||
|
6 | _ := p * 2 //should be error
|
||||||
|
| ~~~~~
|
||||||
|
7 | _ := p + 5 //OK but only in unsafe block, r is *int
|
||||||
|
8 | _ := p - p //OK even in safe code, but n should be isize
|
||||||
|
vlib/v/checker/tests/disallow_pointer_arithmetic_err.vv:7:7: error: pointer arithmetic is only allowed in `unsafe` blocks
|
||||||
|
5 | _ := p * p //should be error
|
||||||
|
6 | _ := p * 2 //should be error
|
||||||
|
7 | _ := p + 5 //OK but only in unsafe block, r is *int
|
||||||
|
| ~~~~~
|
||||||
|
8 | _ := p - p //OK even in safe code, but n should be isize
|
||||||
|
9 | }
|
||||||
|
vlib/v/checker/tests/disallow_pointer_arithmetic_err.vv:8:7: error: pointer arithmetic is only allowed in `unsafe` blocks
|
||||||
|
6 | _ := p * 2 //should be error
|
||||||
|
7 | _ := p + 5 //OK but only in unsafe block, r is *int
|
||||||
|
8 | _ := p - p //OK even in safe code, but n should be isize
|
||||||
|
| ~~~~~
|
||||||
|
9 | }
|
|
@ -0,0 +1,9 @@
|
||||||
|
fn main() {
|
||||||
|
x := 5
|
||||||
|
p := &x
|
||||||
|
_ := p + p //should be error
|
||||||
|
_ := p * p //should be error
|
||||||
|
_ := p * 2 //should be error
|
||||||
|
_ := p + 5 //OK but only in unsafe block, r is *int
|
||||||
|
_ := p - p //OK even in safe code, but n should be isize
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ vlib/v/checker/tests/mismatched_ptr_op_ptr.vv:5:17: error: mismatched types `&st
|
||||||
| ~~~
|
| ~~~
|
||||||
6 | println(b+b)
|
6 | println(b+b)
|
||||||
7 | }
|
7 | }
|
||||||
vlib/v/checker/tests/mismatched_ptr_op_ptr.vv:6:17: error: mismatched types `&string` and `&string`
|
vlib/v/checker/tests/mismatched_ptr_op_ptr.vv:6:17: error: invalid operator `+` to `&string` and `&string`
|
||||||
4 | b := &a
|
4 | b := &a
|
||||||
5 | println(b+*b)
|
5 | println(b+*b)
|
||||||
6 | println(b+b)
|
6 | println(b+b)
|
||||||
|
|
|
@ -16,13 +16,13 @@ vlib/v/checker/tests/unsafe_pointer_arithmetic_should_be_checked.vv:11:14: error
|
||||||
9 | fn test_ptr_infix() {
|
9 | fn test_ptr_infix() {
|
||||||
10 | v := 4
|
10 | v := 4
|
||||||
11 | mut q := &v - 1
|
11 | mut q := &v - 1
|
||||||
| ^
|
| ~~~~~~
|
||||||
12 | q = q + 3
|
12 | q = q + 3
|
||||||
13 | _ := q
|
13 | _ := q
|
||||||
vlib/v/checker/tests/unsafe_pointer_arithmetic_should_be_checked.vv:12:9: error: pointer arithmetic is only allowed in `unsafe` blocks
|
vlib/v/checker/tests/unsafe_pointer_arithmetic_should_be_checked.vv:12:9: error: pointer arithmetic is only allowed in `unsafe` blocks
|
||||||
10 | v := 4
|
10 | v := 4
|
||||||
11 | mut q := &v - 1
|
11 | mut q := &v - 1
|
||||||
12 | q = q + 3
|
12 | q = q + 3
|
||||||
| ^
|
| ~~~~~
|
||||||
13 | _ := q
|
13 | _ := q
|
||||||
14 | _ := v
|
14 | _ := v
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
fn test_strings() {
|
||||||
|
s := 'hi'
|
||||||
|
mut p := unsafe { s.str + 1 }
|
||||||
|
n := unsafe { p - s.str }
|
||||||
|
assert typeof(n).name == 'int'
|
||||||
|
}
|
Loading…
Reference in New Issue