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

checker: check unsafe array assign (fix #9651) (#15515)

This commit is contained in:
yuyi 2022-08-25 13:52:13 +08:00 committed by GitHub
parent 86496aa191
commit c662431cfd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 84 additions and 48 deletions

View File

@ -321,7 +321,7 @@ fn take_screenshots(opt Options, app AppConfig) ![]string {
os.setenv('$k', rv, true)
}
mut flags := app.capture.flags.join(' ')
flags := app.capture.flags.join(' ')
result := opt.verbose_execute('${os.quoted_path(v_exe)} $flags -d gg_record run ${os.quoted_path(app.abs_path)}')
if result.exit_code != 0 {
return error('Failed taking screenshot of `$app.abs_path`:\n$result.output')
@ -336,7 +336,7 @@ fn take_screenshots(opt Options, app AppConfig) ![]string {
existing_screenshots := get_app_screenshots(out_path, app)!
mut flags := app.capture.flags
flags := app.capture.flags
mut p_app := os.new_process(app.abs_path)
p_app.set_args(flags)

View File

@ -86,7 +86,7 @@ fn main() {
if module_names.len == 0 && os.exists('./v.mod') {
println('Detected v.mod file inside the project directory. Using it...')
manifest := vmod.from_file('./v.mod') or { panic(err) }
module_names = manifest.dependencies
module_names = manifest.dependencies.clone()
}
mut source := Source.vpm
if '--once' in options {

View File

@ -154,7 +154,7 @@ fn (r &Repl) current_source_code(should_add_temp_lines bool, not_add_print bool)
if !not_add_print {
lines = r.vstartup_lines.filter(!it.starts_with('print'))
} else {
lines = r.vstartup_lines
lines = r.vstartup_lines.clone()
}
all_lines << lines
}

View File

@ -83,7 +83,7 @@ pub fn (mut list LinkedList<T>) pop() ?T {
return error('Linked list is empty')
}
mut node := list.head
mut to_return := node.data
mut to_return := unsafe { node.data }
if unsafe { node.next == 0 } {
// first node case
// set to null
@ -92,7 +92,7 @@ pub fn (mut list LinkedList<T>) pop() ?T {
for unsafe { node.next.next != 0 } {
node = node.next
}
to_return = node.next.data
to_return = unsafe { node.next.data }
// set to null
node.next = unsafe { nil }
}

View File

@ -55,8 +55,8 @@ fn newton_divide_array_by_array(operand_a []u32, operand_b []u32, mut quotient [
q.inc()
r -= b
}
quotient = q.digits
remainder = r.digits
quotient = q.digits.clone()
remainder = r.digits.clone()
shrink_tail_zeros(mut remainder)
}
@ -241,7 +241,7 @@ fn toom3_multiply_digit_array(operand_a []u32, operand_b []u32, mut storage []u3
result := (((pinf.lshift(s) + t2).lshift(s) + t1).lshift(s) + tm1).lshift(s) + p0
storage = result.digits
storage = result.digits.clone()
}
[inline]

View File

@ -66,7 +66,7 @@ pub fn (db Connection) @select(config orm.SelectConfig, data orm.QueryData, wher
stmt.bind_res(fields, dataptr, lens, num_fields)
mut row := 0
mut types := config.types
mut types := config.types.clone()
mut field_types := []FieldType{}
if config.is_count {
types = [orm.type_idx['u64']]

View File

@ -54,13 +54,13 @@ fn (mut btree BTree) add_children(tag Tag) int {
btree.all_tags << tag
if btree.all_tags.len > 1 {
for btree.childrens.len <= btree.node_pointer {
mut temp_array := btree.childrens
mut temp_array := btree.childrens.clone()
temp_array << []int{}
btree.childrens = temp_array
}
btree.childrens[btree.node_pointer] << btree.all_tags.len - 1
for btree.parents.len < btree.all_tags.len {
mut temp_array := btree.parents
mut temp_array := btree.parents.clone()
temp_array << 0
btree.parents = temp_array
}

View File

@ -62,7 +62,7 @@ fn (raw_ver RawVersion) coerce() ?Version {
}
fn (raw_ver RawVersion) complete() RawVersion {
mut raw_ints := raw_ver.raw_ints
mut raw_ints := raw_ver.raw_ints.clone()
for raw_ints.len < 3 {
raw_ints << '0'
}

View File

@ -399,7 +399,7 @@ pub fn (t &Table) get_embeds(sym &TypeSymbol, options GetEmbedsOptions) [][]Type
if unalias_sym.info is Struct {
for embed in unalias_sym.info.embeds {
embed_sym := t.sym(embed)
mut preceding := options.preceding
mut preceding := options.preceding.clone()
preceding << embed
embeds << t.get_embeds(embed_sym, preceding: preceding)
}
@ -1932,7 +1932,7 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr
}
}
}
mut all_methods := ts.methods
mut all_methods := unsafe { ts.methods }
for imethod in imethods {
for mut method in all_methods {
if imethod.name == method.name {
@ -2097,7 +2097,7 @@ pub fn (mut t Table) generic_insts_to_concrete() {
}
sym.register_method(method)
}
mut all_methods := parent.methods
mut all_methods := unsafe { parent.methods }
for imethod in imethods {
for mut method in all_methods {
if imethod.name == method.name {

View File

@ -338,13 +338,29 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
}
left_sym := c.table.sym(left_type_unwrapped)
right_sym := c.table.sym(right_type_unwrapped)
if left_sym.kind == .array && !c.inside_unsafe && node.op in [.assign, .decl_assign]
&& right_sym.kind == .array && left is ast.Ident && !left.is_blank_ident()
&& right is ast.Ident {
old_assign_error_condition := left_sym.kind == .array && !c.inside_unsafe
&& node.op in [.assign, .decl_assign] && right_sym.kind == .array && left is ast.Ident
&& !left.is_blank_ident() && right is ast.Ident
if old_assign_error_condition {
// Do not allow `a = b`, only `a = b.clone()`
c.error('use `array2 $node.op.str() array1.clone()` instead of `array2 $node.op.str() array1` (or use `unsafe`)',
node.pos)
}
// Do not allow `a = val.array_field`, only `a = val.array_field.clone()`
// TODO: turn this warning into an error after 2022/09/24
// TODO: and remove the less strict check from above.
if left_sym.kind == .array && !c.inside_unsafe && right_sym.kind == .array
&& left is ast.Ident && !left.is_blank_ident() && right in [ast.Ident, ast.SelectorExpr]
&& ((node.op == .decl_assign && (left as ast.Ident).is_mut)
|| node.op == .assign) {
// no point to show the notice, if the old error was already shown:
if !old_assign_error_condition {
mut_str := if node.op == .decl_assign { 'mut ' } else { '' }
c.note('use `${mut_str}array2 $node.op.str() array1.clone()` instead of `${mut_str}array2 $node.op.str() array1` (or use `unsafe`)',
node.pos)
}
}
if left_sym.kind == .array && right_sym.kind == .array {
// `mut arr := [u8(1),2,3]`
// `arr = [byte(4),5,6]`

View File

@ -756,8 +756,8 @@ pub fn (mut c Checker) infer_fn_generic_types(func ast.Fn, mut node ast.CallExpr
mut concrete_types := []ast.Type{}
match arg_sym.info {
ast.Struct, ast.Interface, ast.SumType {
generic_types = arg_sym.info.generic_types
concrete_types = arg_sym.info.concrete_types
generic_types = arg_sym.info.generic_types.clone()
concrete_types = arg_sym.info.concrete_types.clone()
}
else {}
}

View File

@ -542,7 +542,7 @@ pub fn (mut c Checker) expand_iface_embeds(idecl &ast.InterfaceDecl, level int,
mut ares := []ast.InterfaceEmbedding{}
for ie in iface_embeds {
if iface_decl := c.table.interfaces[ie.typ] {
mut list := iface_decl.embeds
mut list := iface_decl.embeds.clone()
if !iface_decl.are_embeds_expanded {
list = c.expand_iface_embeds(idecl, level + 1, iface_decl.embeds)
c.table.interfaces[ie.typ].embeds = list

View File

@ -30,7 +30,7 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
exp_is_result := expected_type.has_flag(.result)
mut expected_types := [expected_type]
if expected_type_sym.info is ast.MultiReturn {
expected_types = expected_type_sym.info.types
expected_types = expected_type_sym.info.types.clone()
if c.table.cur_concrete_types.len > 0 {
expected_types = expected_types.map(c.unwrap_generic(it))
}

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/array_assign_err.vv:8:8: notice: use `mut array2 := array1.clone()` instead of `mut array2 := array1` (or use `unsafe`)
6 | fn main() {
7 | a := Dumb{[1, 2, 3]}
8 | mut b := a.v // I expect a compiler error
| ~~
9 | for _ in 0 .. 100 {
10 | b << [4, 5, 6]

View File

@ -0,0 +1,13 @@
struct Dumb {
mut:
v []int
}
fn main() {
a := Dumb{[1, 2, 3]}
mut b := a.v // I expect a compiler error
for _ in 0 .. 100 {
b << [4, 5, 6]
}
println(a) // prints [4,5,6] in this case, but I've also seen crashes
}

View File

@ -10,10 +10,10 @@ vlib/v/checker/tests/array_or_map_assign_err.vv:5:5: error: use `array2 = array1
4 | mut a3 := []int{}
5 | a3 = a1
| ^
6 |
6 |
7 | m1 := {'one': 1}
vlib/v/checker/tests/array_or_map_assign_err.vv:8:8: error: cannot copy map: call `move` or `clone` method (or use a reference)
6 |
6 |
7 | m1 := {'one': 1}
8 | m2 := m1
| ~~
@ -24,10 +24,10 @@ vlib/v/checker/tests/array_or_map_assign_err.vv:10:7: error: cannot copy map: ca
9 | mut m3 := map[string]int{}
10 | m3 = m1
| ~~
11 |
11 |
12 | _ = a2
vlib/v/checker/tests/array_or_map_assign_err.vv:25:8: error: cannot copy map: call `move` or `clone` method (or use a reference)
23 |
23 |
24 | fn foo(mut m map[string]int) {
25 | m2 := m
| ^

View File

@ -1160,12 +1160,12 @@ pub fn (mut f Fmt) interface_decl(node ast.InterfaceDecl) {
immut_fields := if node.mut_pos < 0 { node.fields } else { node.fields[..node.mut_pos] }
mut_fields := if node.mut_pos < 0 { []ast.StructField{} } else { node.fields[node.mut_pos..] }
mut immut_methods := node.methods
mut immut_methods := node.methods.clone()
mut mut_methods := []ast.FnDecl{}
for i, method in node.methods {
if method.params[0].is_mut {
immut_methods = node.methods[..i]
mut_methods = node.methods[i..]
immut_methods = node.methods[..i].clone()
mut_methods = node.methods[i..].clone()
break
}
}

View File

@ -1030,7 +1030,7 @@ fn (mut g Gen) register_result(t ast.Type) string {
fn (mut g Gen) write_optionals() {
mut done := []string{}
rlock g.done_optionals {
done = g.done_optionals
done = g.done_optionals.clone()
}
for base, styp in g.optionals {
if base in done {
@ -5814,7 +5814,7 @@ static inline __shared__$interface_name ${shared_fn_name}(__shared__$cctype* x)
}
}
}
mut methods := st_sym.methods
mut methods := st_sym.methods.clone()
method_names := methods.map(it.name)
match st_sym.info {
ast.Struct, ast.Interface, ast.SumType {

View File

@ -1077,12 +1077,12 @@ pub fn (mut f Gen) interface_decl(node ast.InterfaceDecl) {
immut_fields := if node.mut_pos < 0 { node.fields } else { node.fields[..node.mut_pos] }
mut_fields := if node.mut_pos < 0 { []ast.StructField{} } else { node.fields[node.mut_pos..] }
mut immut_methods := node.methods
mut immut_methods := node.methods.clone()
mut mut_methods := []ast.FnDecl{}
for i, method in node.methods {
if method.params[0].is_mut {
immut_methods = node.methods[..i]
mut_methods = node.methods[i..]
immut_methods = node.methods[..i].clone()
mut_methods = node.methods[i..].clone()
break
}
}

View File

@ -675,7 +675,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) {
g.push_pub_var(name)
}
}
mut args := it.params
args := it.params
g.fn_args(args, it.is_variadic)
g.writeln(') {')
@ -808,7 +808,7 @@ fn (mut g JsGen) gen_anon_fn(mut fun ast.AnonFn) {
g.write('return function (')
mut args := it.params
args := it.params
g.fn_args(args, it.is_variadic)
g.writeln(') {')

View File

@ -6,7 +6,7 @@ module parser
import v.ast
fn (mut p Parser) assign_stmt() ast.Stmt {
mut defer_vars := p.defer_vars
mut defer_vars := p.defer_vars.clone()
p.defer_vars = []ast.Ident{}
exprs, comments := p.expr_list()

View File

@ -728,7 +728,7 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
tmp := p.label_names
p.label_names = []
stmts = p.parse_block_no_scope(false)
label_names = p.label_names
label_names = p.label_names.clone()
p.label_names = tmp
}
p.cur_fn_name = keep_fn_name

View File

@ -327,9 +327,9 @@ pub fn (mut p Parser) parse() &ast.File {
}
p.scope.end_pos = p.tok.pos
mut errors := p.errors
mut warnings := p.warnings
mut notices := p.notices
mut errors := p.errors.clone()
mut warnings := p.warnings.clone()
mut notices := p.notices.clone()
if p.pref.check_only {
errors << p.scanner.errors
@ -2001,7 +2001,7 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt {
tok := p.tok
mut pos := tok.pos()
mut defer_vars := p.defer_vars
mut defer_vars := p.defer_vars.clone()
p.defer_vars = []ast.Ident{}
left, left_comments := p.expr_list()
@ -3374,7 +3374,7 @@ fn (mut p Parser) const_decl() ast.ConstDecl {
p.top_level_statement_start()
mut attrs := []ast.Attr{}
if p.attrs.len > 0 {
attrs = p.attrs
attrs = p.attrs.clone()
p.attrs = []
}
mut is_markused := false
@ -3491,7 +3491,7 @@ fn (mut p Parser) return_stmt() ast.Return {
fn (mut p Parser) global_decl() ast.GlobalDecl {
mut attrs := []ast.Attr{}
if p.attrs.len > 0 {
attrs = p.attrs
attrs = p.attrs.clone()
p.attrs = []
}

View File

@ -64,7 +64,7 @@ struct Efg {
fn test_shared_auto_init_array() {
e := Efg{}
shared a := e.a
shared a := unsafe { e.a }
lock a {
a << 23.0625
a << -133.25
@ -81,11 +81,11 @@ fn test_shared_array_in_struct() {
a: [1.25, 2.75, 7, 13.0625]
i: 12
}
shared t := x.a
shared t := unsafe { x.a }
lock t {
t[2] = -1.125
}
shared tt := x.a
shared tt := unsafe { x.a }
v := rlock tt {
tt[3]
}