From dbbf96702b782b02b8779d1c27601ea049f3a7f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kr=C3=BCger?= <45282134+UweKrueger@users.noreply.github.com> Date: Fri, 12 Mar 2021 16:08:39 +0100 Subject: [PATCH] checker: require `shared a` to be `rlocked` to read `a[i]` or `a.e` (#9266) --- vlib/v/checker/check_types.v | 31 +++++++++++++------ vlib/v/checker/checker.v | 20 +++--------- vlib/v/checker/tests/lock_already_locked.out | 6 ++++ vlib/v/checker/tests/lock_already_rlocked.out | 6 ++++ vlib/v/checker/tests/lock_needed.out | 22 ++++++++++++- vlib/v/checker/tests/lock_needed.vv | 19 ++++++++++++ 6 files changed, 78 insertions(+), 26 deletions(-) diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 13e2857bd..4939d1819 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -348,14 +348,27 @@ pub fn (c &Checker) get_default_fmt(ftyp table.Type, typ table.Type) byte { } } -pub fn (mut c Checker) fail_if_not_rlocked(expr ast.Expr, what string) { - if expr is ast.Ident { - if expr.name !in c.rlocked_names && expr.name !in c.locked_names { - action := if what == 'argument' { 'passed' } else { 'used' } - c.error('$expr.name is `shared` and must be `rlock`ed or `lock`ed to be $action as non-mut $what', - expr.pos) +pub fn (mut c Checker) fail_if_unreadable(expr ast.Expr, typ table.Type, what string) { + match expr { + ast.Ident { + if typ.has_flag(.shared_f) { + if expr.name !in c.rlocked_names && expr.name !in c.locked_names { + action := if what == 'argument' { 'passed' } else { 'used' } + c.error('$expr.name is `shared` and must be `rlock`ed or `lock`ed to be $action as non-mut $what', + expr.pos) + } + } + return } - } else { + ast.SelectorExpr { + c.fail_if_unreadable(expr.expr, expr.expr_type, what) + } + ast.IndexExpr { + c.fail_if_unreadable(expr.left, expr.left_type, what) + } + else {} + } + if typ.has_flag(.shared_f) { c.error('you have to create a handle and `rlock` it to use a `shared` element as non-mut $what', expr.position()) } @@ -366,9 +379,7 @@ pub fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) table.T c.inside_println_arg = true for i, expr in node.exprs { ftyp := c.expr(expr) - if ftyp.has_flag(.shared_f) { - c.fail_if_not_rlocked(expr, 'interpolation object') - } + c.fail_if_unreadable(expr, ftyp, 'interpolation object') node.expr_types << ftyp typ := c.table.unalias_num_type(ftyp) mut fmt := node.fmts[i] diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 4c98854b0..fd4bdd94d 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1421,9 +1421,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type { pos) } } else { - if left_type.has_flag(.shared_f) { - c.fail_if_not_rlocked(call_expr.left, 'receiver') - } + c.fail_if_unreadable(call_expr.left, left_type, 'receiver') } if (!left_type_sym.is_builtin() && method.mod != 'builtin') && method.language == .v && method.no_body { @@ -1517,9 +1515,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type { c.error('`$call_expr.name` parameter `$param.name` is `$tok`, you need to provide `$tok` e.g. `$tok arg${ i + 1}`', arg.expr.position()) } else { - if got_arg_typ.has_flag(.shared_f) { - c.fail_if_not_rlocked(arg.expr, 'argument') - } + c.fail_if_unreadable(arg.expr, got_arg_typ, 'argument') } } } @@ -1584,9 +1580,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type { if call_expr.args.len > 0 { c.error('.str() method calls should have no arguments', call_expr.pos) } - if left_type.has_flag(.shared_f) { - c.fail_if_not_rlocked(call_expr.left, 'receiver') - } + c.fail_if_unreadable(call_expr.left, left_type, 'receiver') return table.string_type } // call struct field fn type @@ -1903,9 +1897,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type { if call_expr.args[0].typ.is_void() { c.error('`$fn_name` can not print void expressions', call_expr.pos) } - if call_expr.args[0].typ.has_flag(.shared_f) { - c.fail_if_not_rlocked(call_expr.args[0].expr, 'argument to print') - } + c.fail_if_unreadable(call_expr.args[0].expr, call_expr.args[0].typ, 'argument to print') c.inside_println_arg = false /* // TODO: optimize `struct T{} fn (t &T) str() string {return 'abc'} mut a := []&T{} a << &T{} println(a[0])` @@ -1983,9 +1975,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type { c.error('`$call_expr.name` parameter `$arg.name` is `$tok`, you need to provide `$tok` e.g. `$tok arg${ i + 1}`', call_arg.expr.position()) } else { - if typ.has_flag(.shared_f) { - c.fail_if_not_rlocked(call_arg.expr, 'argument') - } + c.fail_if_unreadable(call_arg.expr, typ, 'argument') } } // Handle expected interface diff --git a/vlib/v/checker/tests/lock_already_locked.out b/vlib/v/checker/tests/lock_already_locked.out index 7e421a1bc..5d01cdb40 100644 --- a/vlib/v/checker/tests/lock_already_locked.out +++ b/vlib/v/checker/tests/lock_already_locked.out @@ -5,3 +5,9 @@ vlib/v/checker/tests/lock_already_locked.vv:11:3: error: nested `lock`/`rlock` n | ~~~~~ 12 | a.x++ 13 | } +vlib/v/checker/tests/lock_already_locked.vv:15:10: error: a is `shared` and must be `rlock`ed or `lock`ed to be used as non-mut argument to print + 13 | } + 14 | } + 15 | println(a.x) + | ^ + 16 | } diff --git a/vlib/v/checker/tests/lock_already_rlocked.out b/vlib/v/checker/tests/lock_already_rlocked.out index 411907d91..8a61e7734 100644 --- a/vlib/v/checker/tests/lock_already_rlocked.out +++ b/vlib/v/checker/tests/lock_already_rlocked.out @@ -5,3 +5,9 @@ vlib/v/checker/tests/lock_already_rlocked.vv:11:3: error: nested `lock`/`rlock` | ~~~~ 12 | a.x++ 13 | } +vlib/v/checker/tests/lock_already_rlocked.vv:15:10: error: a is `shared` and must be `rlock`ed or `lock`ed to be used as non-mut argument to print + 13 | } + 14 | } + 15 | println(a.x) + | ^ + 16 | } diff --git a/vlib/v/checker/tests/lock_needed.out b/vlib/v/checker/tests/lock_needed.out index e6422a6b6..87b207e43 100644 --- a/vlib/v/checker/tests/lock_needed.out +++ b/vlib/v/checker/tests/lock_needed.out @@ -1,7 +1,27 @@ -vlib/v/checker/tests/lock_needed.vv:10:2: error: `abc` is `shared` and needs explicit lock for `v.ast.SelectorExpr` +vlib/v/checker/tests/lock_needed.vv:10:2: error: `abc` is `shared` and needs explicit lock for `v.ast.SelectorExpr` 8 | x: 5 9 | } 10 | abc.x++ | ~~~ 11 | println(abc.x) 12 | } +vlib/v/checker/tests/lock_needed.vv:11:10: error: abc is `shared` and must be `rlock`ed or `lock`ed to be used as non-mut argument to print + 9 | } + 10 | abc.x++ + 11 | println(abc.x) + | ~~~ + 12 | } + 13 | +vlib/v/checker/tests/lock_needed.vv:25:12: error: you have to create a handle and `rlock` it to use a `shared` element as non-mut argument to print + 23 | } + 24 | } + 25 | println(a.st.x) + | ~~ + 26 | } + 27 | +vlib/v/checker/tests/lock_needed.vv:30:10: error: a is `shared` and must be `rlock`ed or `lock`ed to be used as non-mut argument to print + 28 | fn g() { + 29 | shared a := []f64{len: 10, init: 7.5} + 30 | println(a[3]) + | ^ + 31 | } diff --git a/vlib/v/checker/tests/lock_needed.vv b/vlib/v/checker/tests/lock_needed.vv index 805e79072..001aa7fa5 100644 --- a/vlib/v/checker/tests/lock_needed.vv +++ b/vlib/v/checker/tests/lock_needed.vv @@ -10,3 +10,22 @@ fn main() { abc.x++ println(abc.x) } + +struct Abc { +mut: + st shared St +} + +fn f() { + mut a := Abc{ + st: St{ + x: 9 + } + } + println(a.st.x) +} + +fn g() { + shared a := []f64{len: 10, init: 7.5} + println(a[3]) +} -- 2.39.5