From 5180013aeff49421d4dde9b72abc809b82c3f176 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 4 Dec 2020 23:30:30 +0100 Subject: [PATCH] autofree: fix array re-assignment with struct fields --- vlib/v/gen/cgen.v | 23 +++++++++++--------- vlib/v/tests/valgrind/1.strings_and_arrays.v | 18 ++++++++++----- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 1a43329774..107cd7067f 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -1519,9 +1519,11 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { ast.IfExpr { return_type = right_expr.typ } else {} } - // Free the old value assigned to this string var (only if it's `str = [new value]`) + // Free the old value assigned to this string var (only if it's `str = [new value]` + // or `x.str = [new value]` ) mut af := g.pref.autofree && !g.is_builtin_mod && assign_stmt.op == .assign && assign_stmt.left_types.len == - 1 && assign_stmt.left[0] is ast.Ident + 1 && + (assign_stmt.left[0] is ast.Ident || assign_stmt.left[0] is ast.SelectorExpr) // assign_stmt.left_types[0] in [table.string_type, table.array_type] && mut sref_name := '' mut type_to_free := '' @@ -1530,18 +1532,19 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { first_left_sym := g.table.get_type_symbol(assign_stmt.left_types[0]) if first_left_type == table.string_type || first_left_sym.kind == .array { type_to_free = if first_left_type == table.string_type { 'string' } else { 'array' } - ident := assign_stmt.left[0] as ast.Ident - if ident.name != '_' { - /* - g.write('string_free(&') - g.expr(assign_stmt.left[0]) - g.writeln('); // free str on re-assignment') - */ + mut ok := true + left0 := assign_stmt.left[0] + if left0 is ast.Ident { + if left0.name == '_' { + ok = false + } + } + if ok { sref_name = '_sref$assign_stmt.pos.pos' g.write('$type_to_free $sref_name = (') // TODO we are copying the entire string here, optimize // we can't just do `.str` since we need the extra data from the string struct // doing `&string` is also not an option since the stack memory with the data will be overwritten - g.expr(assign_stmt.left[0]) + g.expr(left0) // assign_stmt.left[0]) g.writeln('); // free $type_to_free on re-assignment2') defer { if af { diff --git a/vlib/v/tests/valgrind/1.strings_and_arrays.v b/vlib/v/tests/valgrind/1.strings_and_arrays.v index e3c19993a9..dc12728028 100644 --- a/vlib/v/tests/valgrind/1.strings_and_arrays.v +++ b/vlib/v/tests/valgrind/1.strings_and_arrays.v @@ -106,10 +106,20 @@ fn reassign_str() { s = s + '!' // old s ref must be copied and freed after the assignment, since s is still used in the right expr } +struct Foo2 { +mut: + nums []int +} + fn reassign_arr() { mut x := [1, 2, 3] // x must be freed before the re-assignment x = [4, 5, 6] + mut foo := Foo2{[10, 20, 30]} + foo.nums = [40, 50, 60] // same with struct fields + foo.nums = [70, 80, 90] + // TODO remove this once structs are freed automatically + foo.nums.free() } fn match_expr() string { @@ -145,9 +155,7 @@ fn optional_str() { // test assigning an optional to an existing var mut p := 0 for { - p = opt('query:$q') or { - break - } + p = opt('query:$q') or { break } break } } @@ -161,9 +169,7 @@ fn return_error_with_freed_expr() ?string { } fn optional_return() { - return_error_with_freed_expr() or { - return - } + return_error_with_freed_expr() or { return } } fn handle_string(s string) bool {