From 4e62bc0b8130467b6a7b24b73911d7d2b33a9a01 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 18 Mar 2021 05:41:50 +0300 Subject: [PATCH] autofree: fix free before return --- vlib/v/gen/c/cgen.v | 27 ++++++++++---------- vlib/v/tests/valgrind/1.strings_and_arrays.v | 7 ++++- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 600d9c946d..1bf7bb5e24 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1768,7 +1768,7 @@ fn (mut g Gen) gen_asm_stmt(stmt ast.AsmStmt) { } else { g.write(' ') } - // swap destionation and operands for att syntax + // swap destionation and operands for att syntax if template.args.len != 0 { template.args.prepend(template.args[template.args.len - 1]) template.args.delete(template.args.len - 1) @@ -4539,7 +4539,7 @@ fn (mut g Gen) return_statement(node ast.Return) { styp := g.typ(g.fn_decl.return_type) g.writeln('return ($styp){0};') } else { - if g.is_autofree && !g.is_builtin_mod { + if g.is_autofree { g.writeln('// free before return (no values returned)') g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true) } @@ -4680,13 +4680,24 @@ fn (mut g Gen) return_statement(node ast.Return) { g.writeln('return $opt_tmp;') return } + // autofree before `return` + // set free_parent_scopes to true, since all variables defined in parent + // scopes need to be freed before the return + if g.is_autofree { + expr := node.exprs[0] + if expr is ast.Ident { + g.returned_var_name = expr.name + } + g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true) + } // free := g.is_autofree && !g.is_builtin_mod // node.exprs[0] is ast.CallExpr + // Create a temporary variable for the return expression free := !g.is_builtin_mod // node.exprs[0] is ast.CallExpr mut tmp := '' if free { // `return foo(a, b, c)` // `tmp := foo(a, b, c); free(a); free(b); free(c); return tmp;` - // Save return value in a temp var so that it all args (a,b,c) can be freed + // Save return value in a temp var so that all args (a,b,c) can be freed // Don't use a tmp var if a variable is simply returned: `return x` if node.exprs[0] !is ast.Ident { tmp = g.new_tmp_var() @@ -4712,18 +4723,8 @@ fn (mut g Gen) return_statement(node ast.Return) { g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type) } if free { - expr := node.exprs[0] - if expr is ast.Ident { - g.returned_var_name = expr.name - } g.writeln(';') has_semicolon = true - // autofree before `return` - // set free_parent_scopes to true, since all variables defined in parent - // scopes need to be freed before the return - if g.pref.autofree { - g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true) - } if tmp != '' { g.write('return $tmp') has_semicolon = false diff --git a/vlib/v/tests/valgrind/1.strings_and_arrays.v b/vlib/v/tests/valgrind/1.strings_and_arrays.v index 1676b3134b..0609361199 100644 --- a/vlib/v/tests/valgrind/1.strings_and_arrays.v +++ b/vlib/v/tests/valgrind/1.strings_and_arrays.v @@ -318,6 +318,11 @@ fn get_user() User { return user } +fn get_user2() User { + users := [User{'Peter', 25}, User{'Alice', 21}] + return users[0] // has to be cloned, since `users` are going to be freed at the end of the function +} + fn string_array_get() { s := ['a', 'b', 'c'] x := s[0] @@ -361,7 +366,7 @@ fn main() { free_before_break() // free_map() // loop_map() - // free_array_except_returned_element() + free_array_except_returned_element() println('end') }