From d1b0370166f9318ad31a44edc6a45aec0defe597 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sat, 19 Oct 2024 01:19:00 -0300 Subject: [PATCH] checker: check for external variable access on qsort/sorted callback (fix #12386) (#22557) --- vlib/v/checker/fn.v | 1 + vlib/v/checker/infix.v | 37 +++++++++++++++++++ vlib/v/checker/tests/array_sort_err.out | 6 +++ .../tests/qsort_external_variable_err.out | 7 ++++ .../tests/qsort_external_variable_err.vv | 9 +++++ 5 files changed, 60 insertions(+) create mode 100644 vlib/v/checker/tests/qsort_external_variable_err.out create mode 100644 vlib/v/checker/tests/qsort_external_variable_err.vv diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index d01cc4bc0..6753cf892 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -3296,6 +3296,7 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as if mut node.args[0].expr is ast.LambdaExpr { c.support_lambda_expr_in_sort(elem_typ.ref(), ast.bool_type, mut node.args[0].expr) } else if node.args[0].expr is ast.InfixExpr { + c.check_sort_external_variable_access(node.args[0].expr) if node.args[0].expr.op !in [.gt, .lt] { c.error('`.${method_name}()` can only use `<` or `>` comparison', node.pos) diff --git a/vlib/v/checker/infix.v b/vlib/v/checker/infix.v index f16d568c0..fa38ce6ad 100644 --- a/vlib/v/checker/infix.v +++ b/vlib/v/checker/infix.v @@ -1071,3 +1071,40 @@ fn (mut c Checker) autocast_in_if_conds(mut right ast.Expr, from_expr ast.Expr, else {} } } + +fn (mut c Checker) check_sort_external_variable_access(node ast.Expr) bool { + match node { + ast.InfixExpr { + if !c.check_sort_external_variable_access(node.left) { + return false + } + if !c.check_sort_external_variable_access(node.right) { + return false + } + } + ast.Ident { + if node.name !in ['a', 'b'] { + c.error('can not access external variable `${node.name}`', node.pos) + return false + } + } + ast.CallExpr { + return c.check_sort_external_variable_access(node.left) + } + ast.SelectorExpr { + return c.check_sort_external_variable_access(node.expr) + } + ast.IndexExpr { + if !c.check_sort_external_variable_access(node.left) { + return false + } + if !c.check_sort_external_variable_access(node.index) { + return false + } + } + else { + return true + } + } + return true +} diff --git a/vlib/v/checker/tests/array_sort_err.out b/vlib/v/checker/tests/array_sort_err.out index c123be831..835ce7a40 100644 --- a/vlib/v/checker/tests/array_sort_err.out +++ b/vlib/v/checker/tests/array_sort_err.out @@ -19,6 +19,12 @@ vlib/v/checker/tests/array_sort_err.vv:5:6: error: `.sort()` cannot use same arg | ~~~~~~~~~~~ 6 | arr.sort(c > d) 7 | } +vlib/v/checker/tests/array_sort_err.vv:6:11: error: can not access external variable `c` + 4 | arr.sort(a == b) + 5 | arr.sort(a > a) + 6 | arr.sort(c > d) + | ^ + 7 | } vlib/v/checker/tests/array_sort_err.vv:6:6: error: `.sort()` can only use `a` or `b` as argument, e.g. `arr.sort(a < b)` 4 | arr.sort(a == b) 5 | arr.sort(a > a) diff --git a/vlib/v/checker/tests/qsort_external_variable_err.out b/vlib/v/checker/tests/qsort_external_variable_err.out new file mode 100644 index 000000000..66495d124 --- /dev/null +++ b/vlib/v/checker/tests/qsort_external_variable_err.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/qsort_external_variable_err.vv:7:24: error: can not access external variable `i` + 5 | unsafe { array.sort(a[0] > b[0]) } + 6 | println(array) + 7 | unsafe { array.sort(a[i] < b[i]) } + | ^ + 8 | println(array) + 9 | } diff --git a/vlib/v/checker/tests/qsort_external_variable_err.vv b/vlib/v/checker/tests/qsort_external_variable_err.vv new file mode 100644 index 000000000..1e2b38331 --- /dev/null +++ b/vlib/v/checker/tests/qsort_external_variable_err.vv @@ -0,0 +1,9 @@ +fn main() { + array := [[1, 5], [4, 2]] + println(array) + i := 0 + unsafe { array.sort(a[0] > b[0]) } + println(array) + unsafe { array.sort(a[i] < b[i]) } + println(array) +} -- 2.39.5