1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker: check unsafe map index operation (#17000)

This commit is contained in:
yuyi 2023-01-17 12:47:16 +08:00 committed by GitHub
parent 6bf6a40e0c
commit 21807f94a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 29 additions and 4 deletions

View File

@ -109,9 +109,11 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
if left in [ast.Ident, ast.SelectorExpr] { if left in [ast.Ident, ast.SelectorExpr] {
c.prevent_sum_type_unwrapping_once = true c.prevent_sum_type_unwrapping_once = true
} }
c.inside_left_assign = true if left is ast.IndexExpr {
c.is_index_assign = true
}
left_type = c.expr(left) left_type = c.expr(left)
c.inside_left_assign = false c.is_index_assign = false
c.expected_type = c.unwrap_generic(left_type) c.expected_type = c.unwrap_generic(left_type)
} }
if node.right_types.len < node.left.len { // first type or multi return types added above if node.right_types.len < node.left.len { // first type or multi return types added above

View File

@ -111,7 +111,7 @@ mut:
inside_println_arg bool inside_println_arg bool
inside_decl_rhs bool inside_decl_rhs bool
inside_if_guard bool // true inside the guard condition of `if x := opt() {}` inside_if_guard bool // true inside the guard condition of `if x := opt() {}`
inside_left_assign bool is_index_assign bool
comptime_call_pos int // needed for correctly checking use before decl for templates comptime_call_pos int // needed for correctly checking use before decl for templates
goto_labels map[string]ast.GotoLabel // to check for unused goto labels goto_labels map[string]ast.GotoLabel // to check for unused goto labels
} }
@ -3816,7 +3816,7 @@ fn (mut c Checker) index_expr(mut node ast.IndexExpr) ast.Type {
node.pos) node.pos)
} }
if !c.inside_unsafe && !c.is_builtin_mod && !c.inside_if_guard && !c.inside_left_assign if !c.inside_unsafe && !c.is_builtin_mod && !c.inside_if_guard && !c.is_index_assign
&& typ_sym.kind == .map && node.or_expr.stmts.len == 0 { && typ_sym.kind == .map && node.or_expr.stmts.len == 0 {
elem_type := c.table.value_type(typ) elem_type := c.table.value_type(typ)
if elem_type.is_real_pointer() { if elem_type.is_real_pointer() {

View File

@ -0,0 +1,14 @@
vlib/v/checker/tests/map_index_reference_value.vv:7:3: notice: accessing a pointer map value requires an `or{}` block outside `unsafe`
5 | fn main() {
6 | mut m := map[string]&Foo{}
7 | m['bar'].bar = 'bar'
| ~~~~~~~
8 | // m['bar'] << 'baz' // etc
9 | }
vlib/v/checker/tests/map_index_reference_value.vv:7:11: error: field `bar` of struct `&Foo` is immutable
5 | fn main() {
6 | mut m := map[string]&Foo{}
7 | m['bar'].bar = 'bar'
| ~~~
8 | // m['bar'] << 'baz' // etc
9 | }

View File

@ -0,0 +1,9 @@
struct Foo {
bar string
}
fn main() {
mut m := map[string]&Foo{}
m['bar'].bar = 'bar'
// m['bar'] << 'baz' // etc
}