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 {}
}
// 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 &&
assign_stmt.left_types[0] == table.string_type && assign_stmt.left[0] is ast.Ident {
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
mut sref_name := ''
if af {
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);')
}
}
} else {
af = false
}
}
// Autofree tmp arg vars

View File

@ -741,7 +741,7 @@ fn (mut g Gen) autofree_call_postgen(node_pos int) {
return
}
g.doing_autofree_tmp = true
g.write('/* postgen */')
// g.write('/* postgen */')
scope := g.file.scope.innermost(node_pos)
for _, obj in scope.objects {
match mut obj {
@ -770,7 +770,7 @@ fn (mut g Gen) autofree_call_postgen(node_pos int) {
else {}
}
}
g.write('/* postgen end */')
// g.write('/* postgen end */')
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() {
nums := [1, 2, 3] // local array must be freed
println(nums)
@ -64,8 +65,12 @@ fn str_inter() {
fn str_replace() {
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)
//
mut s2 := 'aa' + 'bb'
s2 = s2.replace('a', 'c')
println(s2)
/*
r := s.replace('hello', 'hi')
cloned := s.replace('hello', 'hi').clone()
@ -85,8 +90,12 @@ fn str_replace2() {
}
fn reassign_str() {
mut x := 'a'
x = 'b' // nothing has to be freed here
//
mut s := 'a' + 'b'
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 {
@ -212,12 +221,12 @@ fn free_inside_opt_block() {
fn main() {
println('start')
simple()
reassign_str()
str_tmp_expr()
str_tmp_expr_advanced()
str_tmp_expr_advanced_var_decl()
str_inter()
match_expr()
reassign_str()
optional_str()
// optional_return()
str_replace()