From 57ad943b92a797ca4782342867dcba5be0e14ead Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Sat, 28 Nov 2020 15:21:53 +0100 Subject: [PATCH] autofree: free arrays on re-assignment --- vlib/v/gen/cgen.v | 37 ++++++++++++-------- vlib/v/tests/valgrind/1.strings_and_arrays.v | 7 ++++ 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 3f419c5ac5..3657273ac3 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -1538,25 +1538,32 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { } // Free the old value assigned to this string var (only if it's `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_types[0] == table.string_type && assign_stmt.left[0] is ast.Ident + 1 && assign_stmt.left[0] is ast.Ident + // assign_stmt.left_types[0] in [table.string_type, table.array_type] && mut sref_name := '' + mut type_to_free := '' if af { - ident := assign_stmt.left[0] as ast.Ident - if ident.name != '_' { - /* - g.write('string_free(&') + first_left_type := assign_stmt.left_types[0] + 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') - */ - sref_name = '_sref$assign_stmt.pos.pos' - g.write('string $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.writeln('); // free str on re-assignment2') - defer { - if af { - g.writeln('string_free(&$sref_name);') + */ + 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.writeln('); // free $type_to_free on re-assignment2') + defer { + if af { + g.writeln('${type_to_free}_free(&$sref_name);') + } } } } else { diff --git a/vlib/v/tests/valgrind/1.strings_and_arrays.v b/vlib/v/tests/valgrind/1.strings_and_arrays.v index b1a93321f1..f91305f748 100644 --- a/vlib/v/tests/valgrind/1.strings_and_arrays.v +++ b/vlib/v/tests/valgrind/1.strings_and_arrays.v @@ -106,6 +106,12 @@ 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 } +fn reassign_arr() { + mut x := [1, 2, 3] + // x must be freed before the re-assignment + x = [4, 5, 6] +} + fn match_expr() string { x := 2 res := match x { @@ -266,6 +272,7 @@ fn main() { println('start') simple() reassign_str() + reassign_arr() str_tmp_expr() str_tmp_expr_advanced() str_tmp_expr_advanced_var_decl()