parser,gen: fix `arr << map[key] using map_get_and_set_1, leading to double free
							parent
							
								
									982e35909d
								
							
						
					
					
						commit
						843de10442
					
				| 
						 | 
				
			
			@ -1092,7 +1092,9 @@ fn test_push_arr_string_free() {
 | 
			
		|||
	mut lines := ['hi']
 | 
			
		||||
	s := 'a' + 'b'
 | 
			
		||||
	lines << s
 | 
			
		||||
	s.free() // make sure the data in the array is valid after freeing the string
 | 
			
		||||
	// make sure the data in the array is valid after freeing the string
 | 
			
		||||
	unsafe { s.free() }
 | 
			
		||||
	//
 | 
			
		||||
	println(lines)
 | 
			
		||||
	assert lines.len == 2
 | 
			
		||||
	assert lines[0] == 'hi'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -110,12 +110,12 @@ pub:
 | 
			
		|||
pub struct SelectorExpr {
 | 
			
		||||
pub:
 | 
			
		||||
	pos        token.Position
 | 
			
		||||
	expr       Expr // expr.field_name
 | 
			
		||||
	field_name string
 | 
			
		||||
	is_mut     bool // is used for the case `if mut ident.selector is MyType {`, it indicates if the root ident is mutable
 | 
			
		||||
	mut_pos    token.Position
 | 
			
		||||
	next_token token.Kind
 | 
			
		||||
pub mut:
 | 
			
		||||
	expr            Expr       // expr.field_name
 | 
			
		||||
	expr_type       table.Type // type of `Foo` in `Foo.bar`
 | 
			
		||||
	typ             table.Type // type of the entire thing (`Foo.bar`)
 | 
			
		||||
	name_type       table.Type // T in `T.name` or typeof in `typeof(expr).name`
 | 
			
		||||
| 
						 | 
				
			
			@ -609,12 +609,15 @@ pub mut:
 | 
			
		|||
pub struct IndexExpr {
 | 
			
		||||
pub:
 | 
			
		||||
	pos     token.Position
 | 
			
		||||
	left    Expr
 | 
			
		||||
	index   Expr // [0], RangeExpr [start..end] or map[key]
 | 
			
		||||
	or_expr OrExpr
 | 
			
		||||
pub mut:
 | 
			
		||||
	left      Expr
 | 
			
		||||
	left_type table.Type // array, map, fixed array
 | 
			
		||||
	is_setter bool
 | 
			
		||||
	is_map    bool
 | 
			
		||||
	is_array  bool
 | 
			
		||||
	is_farray bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct IfExpr {
 | 
			
		||||
| 
						 | 
				
			
			@ -1543,3 +1546,13 @@ pub fn (expr Expr) is_mut_ident() bool {
 | 
			
		|||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// helper for dealing with `m[k1][k2][k3][k3] = value`
 | 
			
		||||
pub fn (mut lx IndexExpr) recursive_mapset_is_setter(val bool) {
 | 
			
		||||
	lx.is_setter = val
 | 
			
		||||
	if mut lx.left is IndexExpr {
 | 
			
		||||
		if lx.left.is_map {
 | 
			
		||||
			lx.left.recursive_mapset_is_setter(val)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2695,6 +2695,12 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
 | 
			
		|||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				if mut left is ast.IndexExpr {
 | 
			
		||||
					// eprintln('>>> left.is_setter: ${left.is_setter:10} | left.is_map: ${left.is_map:10} | left.is_array: ${left.is_array:10}')
 | 
			
		||||
					if left.is_map && left.is_setter {
 | 
			
		||||
						left.recursive_mapset_is_setter(true)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				if is_decl {
 | 
			
		||||
					c.error('non-name `$left` on left side of `:=`', left.position())
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			@ -5223,6 +5229,18 @@ pub fn (mut c Checker) index_expr(mut node ast.IndexExpr) table.Type {
 | 
			
		|||
	mut typ := c.expr(node.left)
 | 
			
		||||
	node.left_type = typ
 | 
			
		||||
	typ_sym := c.table.get_final_type_symbol(typ)
 | 
			
		||||
	match typ_sym.kind {
 | 
			
		||||
		.map {
 | 
			
		||||
			node.is_map = true
 | 
			
		||||
		}
 | 
			
		||||
		.array {
 | 
			
		||||
			node.is_array = true
 | 
			
		||||
		}
 | 
			
		||||
		.array_fixed {
 | 
			
		||||
			node.is_farray = true
 | 
			
		||||
		}
 | 
			
		||||
		else {}
 | 
			
		||||
	}
 | 
			
		||||
	if typ_sym.kind !in [.array, .array_fixed, .string, .map] && !typ.is_ptr()
 | 
			
		||||
		&& typ !in [table.byteptr_type, table.charptr_type] && !typ.has_flag(.variadic) {
 | 
			
		||||
		c.error('type `$typ_sym.name` does not support indexing', node.pos)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4373,7 +4373,11 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
 | 
			
		|||
						g.is_array_set = true
 | 
			
		||||
						g.write('map_set_1(')
 | 
			
		||||
					} else {
 | 
			
		||||
						g.write('(*(($elem_type_str*)map_get_and_set_1(')
 | 
			
		||||
						if node.is_setter {
 | 
			
		||||
							g.write('(*(($elem_type_str*)map_get_and_set_1(')
 | 
			
		||||
						} else {
 | 
			
		||||
							g.write('(*(($elem_type_str*)map_get_1(')
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					if !left_is_ptr || node.left_type.has_flag(.shared_f) {
 | 
			
		||||
						g.write('&')
 | 
			
		||||
| 
						 | 
				
			
			@ -4409,7 +4413,11 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
 | 
			
		|||
					|| g.inside_map_index
 | 
			
		||||
					|| (g.is_assign_lhs && !g.is_array_set && get_and_set_types) {
 | 
			
		||||
					zero := g.type_default(info.value_type)
 | 
			
		||||
					g.write('(*($elem_type_str*)map_get_and_set_1(')
 | 
			
		||||
					if node.is_setter {
 | 
			
		||||
						g.write('(*($elem_type_str*)map_get_and_set_1(')
 | 
			
		||||
					} else {
 | 
			
		||||
						g.write('(*($elem_type_str*)map_get_1(')
 | 
			
		||||
					}
 | 
			
		||||
					if !left_is_ptr {
 | 
			
		||||
						g.write('&')
 | 
			
		||||
					}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -348,6 +348,9 @@ pub fn (mut p Parser) expr_with_left(left ast.Expr, precedence int, is_stmt_iden
 | 
			
		|||
			p.next()
 | 
			
		||||
			right := p.expr(precedence - 1)
 | 
			
		||||
			pos.update_last_line(p.prev_tok.line_nr)
 | 
			
		||||
			if mut node is ast.IndexExpr {
 | 
			
		||||
				node.recursive_mapset_is_setter(true)
 | 
			
		||||
			}
 | 
			
		||||
			node = ast.InfixExpr{
 | 
			
		||||
				left: node
 | 
			
		||||
				right: right
 | 
			
		||||
| 
						 | 
				
			
			@ -381,6 +384,9 @@ pub fn (mut p Parser) expr_with_left(left ast.Expr, precedence int, is_stmt_iden
 | 
			
		|||
				p.error_with_pos('$p.tok must be on the same line as the previous token',
 | 
			
		||||
					p.tok.position())
 | 
			
		||||
			}
 | 
			
		||||
			if mut node is ast.IndexExpr {
 | 
			
		||||
				node.recursive_mapset_is_setter(true)
 | 
			
		||||
			}
 | 
			
		||||
			node = ast.PostfixExpr{
 | 
			
		||||
				op: p.tok.kind
 | 
			
		||||
				expr: node
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,14 +1,4 @@
 | 
			
		|||
struct Foo {
 | 
			
		||||
mut:
 | 
			
		||||
	name string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_nested_maps() {
 | 
			
		||||
	if true {
 | 
			
		||||
	}
 | 
			
		||||
	//
 | 
			
		||||
	else {
 | 
			
		||||
	}
 | 
			
		||||
fn test_map_of_map() {
 | 
			
		||||
	mut x := map[string]map[string]int{}
 | 
			
		||||
	x['a'] = map[string]int{}
 | 
			
		||||
	assert x['a']['b'] == 0
 | 
			
		||||
| 
						 | 
				
			
			@ -16,6 +6,9 @@ fn test_nested_maps() {
 | 
			
		|||
	assert x['a']['b'] == 5
 | 
			
		||||
	x['a']['b'] = 7
 | 
			
		||||
	assert x['a']['b'] == 7
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_map_of_map_of_map() {
 | 
			
		||||
	mut y := map[string]map[string]map[string]int{}
 | 
			
		||||
	y['a'] = map[string]map[string]int{}
 | 
			
		||||
	y['a']['b'] = map[string]int{}
 | 
			
		||||
| 
						 | 
				
			
			@ -24,9 +17,18 @@ fn test_nested_maps() {
 | 
			
		|||
	assert y['a']['b']['c'] == 5
 | 
			
		||||
	y['a']['b']['c'] = 7
 | 
			
		||||
	assert y['a']['b']['c'] == 7
 | 
			
		||||
	mut foos := map[string]map[string]Foo{}
 | 
			
		||||
	foos['a']['b'] = Foo{'bar'}
 | 
			
		||||
	assert foos['a']['b'].name == 'bar'
 | 
			
		||||
	foos['a']['b'].name = 'baz'
 | 
			
		||||
	assert foos['a']['b'].name == 'baz'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Foo {
 | 
			
		||||
mut:
 | 
			
		||||
	name string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_map_of_map_to_struct() {
 | 
			
		||||
	mut foos := map[string]map[string]Foo{}
 | 
			
		||||
	foos['zza']['zzb'] = Foo{'bar'}
 | 
			
		||||
	assert foos['zza']['zzb'].name == 'bar'
 | 
			
		||||
	//
 | 
			
		||||
	foos['zza']['zzb'].name = 'baz'
 | 
			
		||||
	assert foos['zza']['zzb'].name == 'baz'
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue