autofree: fix string reassignment

pull/6737/head
Alexander Medvednikov 2020-11-07 04:00:45 +01:00
parent 62cae1ba00
commit 0e8c7ca2e3
3 changed files with 32 additions and 6 deletions

View File

@ -1412,13 +1412,30 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
else {} 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]`)
if g.pref.autofree && assign_stmt.op == .assign && assign_stmt.left_types.len == 1 && mut af := g.pref.autofree && 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 { assign_stmt.left_types[0] == table.string_type && assign_stmt.left[0] is ast.Ident
mut sref_name := ''
if af {
ident := assign_stmt.left[0] as ast.Ident ident := assign_stmt.left[0] as ast.Ident
if ident.name != '_' { if ident.name != '_' {
/*
g.write('string_free(&') g.write('string_free(&')
g.expr(assign_stmt.left[0]) g.expr(assign_stmt.left[0])
g.writeln('); // free str on re-assignment') 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);')
}
}
} else {
af = false
} }
} }
// Autofree tmp arg vars // Autofree tmp arg vars

View File

@ -741,7 +741,7 @@ fn (mut g Gen) autofree_call_postgen(node_pos int) {
return return
} }
g.doing_autofree_tmp = true g.doing_autofree_tmp = true
g.write('/* postgen */') // g.write('/* postgen */')
scope := g.file.scope.innermost(node_pos) scope := g.file.scope.innermost(node_pos)
for _, obj in scope.objects { for _, obj in scope.objects {
match mut obj { match mut obj {
@ -770,7 +770,7 @@ fn (mut g Gen) autofree_call_postgen(node_pos int) {
else {} else {}
} }
} }
g.write('/* postgen end */') // g.write('/* postgen end */')
g.doing_autofree_tmp = false g.doing_autofree_tmp = false
} }

View File

@ -1,3 +1,4 @@
// This program is built and run via Valgrind to ensure there are no leaks with -autofree
fn simple() { fn simple() {
nums := [1, 2, 3] // local array must be freed nums := [1, 2, 3] // local array must be freed
println(nums) println(nums)
@ -64,8 +65,12 @@ fn str_inter() {
fn str_replace() { fn str_replace() {
mut s := 'hello world' mut s := 'hello world'
s = s.replace('hello', 'hi') s = s.replace('hello', 'hi') // s can't be freed as usual before the assignment, since it's used in the right expr
println(s) println(s)
//
mut s2 := 'aa' + 'bb'
s2 = s2.replace('a', 'c')
println(s2)
/* /*
r := s.replace('hello', 'hi') r := s.replace('hello', 'hi')
cloned := s.replace('hello', 'hi').clone() cloned := s.replace('hello', 'hi').clone()
@ -85,8 +90,12 @@ fn str_replace2() {
} }
fn reassign_str() { fn reassign_str() {
mut x := 'a'
x = 'b' // nothing has to be freed here
//
mut s := 'a' + 'b' mut s := 'a' + 'b'
s = 'x' + 'y' // 'a' + 'b' must be freed before the re-assignment s = 'x' + 'y' // 'a' + 'b' must be freed before the re-assignment
s = s + '!' // old s ref must be copied and freed after the assignment, since s is still used in the right expr
} }
fn match_expr() string { fn match_expr() string {
@ -212,12 +221,12 @@ fn free_inside_opt_block() {
fn main() { fn main() {
println('start') println('start')
simple() simple()
reassign_str()
str_tmp_expr() str_tmp_expr()
str_tmp_expr_advanced() str_tmp_expr_advanced()
str_tmp_expr_advanced_var_decl() str_tmp_expr_advanced_var_decl()
str_inter() str_inter()
match_expr() match_expr()
reassign_str()
optional_str() optional_str()
// optional_return() // optional_return()
str_replace() str_replace()