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 {
|
||||
if left_type.is_ptr() || left_type.is_pointer() {
|
||||
if left_type.is_any_kind_of_pointer() {
|
||||
if right_type.is_int() {
|
||||
return left_type
|
||||
} else {
|
||||
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() {
|
||||
return right_type
|
||||
} else {
|
||||
|
|
|
@ -1241,12 +1241,20 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||
left_pos := node.left.position()
|
||||
right_pos := node.right.position()
|
||||
left_right_pos := left_pos.extend(right_pos)
|
||||
if (left_type.is_ptr() || left_sym.is_pointer()) && 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_pos)
|
||||
}
|
||||
if left_type == ast.voidptr_type {
|
||||
c.error('`$node.op` cannot be used with `voidptr`', left_pos)
|
||||
if left_type.is_any_kind_of_pointer()
|
||||
&& node.op in [.plus, .minus, .mul, .div, .mod, .xor, .amp, .pipe] {
|
||||
if (right_type.is_any_kind_of_pointer() && node.op != .minus)
|
||||
|| (!right_type.is_any_kind_of_pointer() && node.op !in [.plus, .minus]) {
|
||||
left_name := c.table.type_to_str(left_type)
|
||||
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
|
||||
|
@ -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)
|
||||
}
|
||||
} 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 {
|
||||
left_name := c.table.type_to_str(left_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)
|
||||
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
|
||||
5 | 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() {
|
||||
10 | v := 4
|
||||
11 | mut q := &v - 1
|
||||
| ^
|
||||
| ~~~~~~
|
||||
12 | q = q + 3
|
||||
13 | _ := q
|
||||
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
|
||||
11 | mut q := &v - 1
|
||||
12 | q = q + 3
|
||||
| ^
|
||||
| ~~~~~
|
||||
13 | _ := q
|
||||
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