From 21807f94a218d0456ca909ce4ffc0537b0b3c363 Mon Sep 17 00:00:00 2001 From: yuyi Date: Tue, 17 Jan 2023 12:47:16 +0800 Subject: [PATCH] checker: check unsafe map index operation (#17000) --- vlib/v/checker/assign.v | 6 ++++-- vlib/v/checker/checker.v | 4 ++-- vlib/v/checker/tests/map_index_reference_value.out | 14 ++++++++++++++ vlib/v/checker/tests/map_index_reference_value.vv | 9 +++++++++ 4 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 vlib/v/checker/tests/map_index_reference_value.out create mode 100644 vlib/v/checker/tests/map_index_reference_value.vv diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index 784232bdd9..8a0d4b60bf 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -109,9 +109,11 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { if left in [ast.Ident, ast.SelectorExpr] { 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) - c.inside_left_assign = false + c.is_index_assign = false c.expected_type = c.unwrap_generic(left_type) } if node.right_types.len < node.left.len { // first type or multi return types added above diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 29b2aa303c..27e06627c6 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -111,7 +111,7 @@ mut: inside_println_arg bool inside_decl_rhs bool 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 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) } - 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 { elem_type := c.table.value_type(typ) if elem_type.is_real_pointer() { diff --git a/vlib/v/checker/tests/map_index_reference_value.out b/vlib/v/checker/tests/map_index_reference_value.out new file mode 100644 index 0000000000..cdd1cb355d --- /dev/null +++ b/vlib/v/checker/tests/map_index_reference_value.out @@ -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 | } diff --git a/vlib/v/checker/tests/map_index_reference_value.vv b/vlib/v/checker/tests/map_index_reference_value.vv new file mode 100644 index 0000000000..949b045661 --- /dev/null +++ b/vlib/v/checker/tests/map_index_reference_value.vv @@ -0,0 +1,9 @@ +struct Foo { + bar string +} + +fn main() { + mut m := map[string]&Foo{} + m['bar'].bar = 'bar' + // m['bar'] << 'baz' // etc +}