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'] | 	mut lines := ['hi'] | ||||||
| 	s := 'a' + 'b' | 	s := 'a' + 'b' | ||||||
| 	lines << s | 	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) | 	println(lines) | ||||||
| 	assert lines.len == 2 | 	assert lines.len == 2 | ||||||
| 	assert lines[0] == 'hi' | 	assert lines[0] == 'hi' | ||||||
|  |  | ||||||
|  | @ -110,12 +110,12 @@ pub: | ||||||
| pub struct SelectorExpr { | pub struct SelectorExpr { | ||||||
| pub: | pub: | ||||||
| 	pos        token.Position | 	pos        token.Position | ||||||
| 	expr       Expr // expr.field_name
 |  | ||||||
| 	field_name string | 	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
 | 	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 | 	mut_pos    token.Position | ||||||
| 	next_token token.Kind | 	next_token token.Kind | ||||||
| pub mut: | pub mut: | ||||||
|  | 	expr            Expr       // expr.field_name
 | ||||||
| 	expr_type       table.Type // type of `Foo` in `Foo.bar`
 | 	expr_type       table.Type // type of `Foo` in `Foo.bar`
 | ||||||
| 	typ             table.Type // type of the entire thing (`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`
 | 	name_type       table.Type // T in `T.name` or typeof in `typeof(expr).name`
 | ||||||
|  | @ -609,12 +609,15 @@ pub mut: | ||||||
| pub struct IndexExpr { | pub struct IndexExpr { | ||||||
| pub: | pub: | ||||||
| 	pos     token.Position | 	pos     token.Position | ||||||
| 	left    Expr |  | ||||||
| 	index   Expr // [0], RangeExpr [start..end] or map[key]
 | 	index   Expr // [0], RangeExpr [start..end] or map[key]
 | ||||||
| 	or_expr OrExpr | 	or_expr OrExpr | ||||||
| pub mut: | pub mut: | ||||||
|  | 	left      Expr | ||||||
| 	left_type table.Type // array, map, fixed array
 | 	left_type table.Type // array, map, fixed array
 | ||||||
| 	is_setter bool | 	is_setter bool | ||||||
|  | 	is_map    bool | ||||||
|  | 	is_array  bool | ||||||
|  | 	is_farray bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct IfExpr { | pub struct IfExpr { | ||||||
|  | @ -1543,3 +1546,13 @@ pub fn (expr Expr) is_mut_ident() bool { | ||||||
| 	} | 	} | ||||||
| 	return false | 	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 { | 			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 { | 				if is_decl { | ||||||
| 					c.error('non-name `$left` on left side of `:=`', left.position()) | 					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) | 	mut typ := c.expr(node.left) | ||||||
| 	node.left_type = typ | 	node.left_type = typ | ||||||
| 	typ_sym := c.table.get_final_type_symbol(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() | 	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) { | 		&& typ !in [table.byteptr_type, table.charptr_type] && !typ.has_flag(.variadic) { | ||||||
| 		c.error('type `$typ_sym.name` does not support indexing', node.pos) | 		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.is_array_set = true | ||||||
| 						g.write('map_set_1(') | 						g.write('map_set_1(') | ||||||
| 					} else { | 					} else { | ||||||
|  | 						if node.is_setter { | ||||||
| 							g.write('(*(($elem_type_str*)map_get_and_set_1(') | 							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) { | 					if !left_is_ptr || node.left_type.has_flag(.shared_f) { | ||||||
| 						g.write('&') | 						g.write('&') | ||||||
|  | @ -4409,7 +4413,11 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { | ||||||
| 					|| g.inside_map_index | 					|| g.inside_map_index | ||||||
| 					|| (g.is_assign_lhs && !g.is_array_set && get_and_set_types) { | 					|| (g.is_assign_lhs && !g.is_array_set && get_and_set_types) { | ||||||
| 					zero := g.type_default(info.value_type) | 					zero := g.type_default(info.value_type) | ||||||
|  | 					if node.is_setter { | ||||||
| 						g.write('(*($elem_type_str*)map_get_and_set_1(') | 						g.write('(*($elem_type_str*)map_get_and_set_1(') | ||||||
|  | 					} else { | ||||||
|  | 						g.write('(*($elem_type_str*)map_get_1(') | ||||||
|  | 					} | ||||||
| 					if !left_is_ptr { | 					if !left_is_ptr { | ||||||
| 						g.write('&') | 						g.write('&') | ||||||
| 					} | 					} | ||||||
|  |  | ||||||
|  | @ -348,6 +348,9 @@ pub fn (mut p Parser) expr_with_left(left ast.Expr, precedence int, is_stmt_iden | ||||||
| 			p.next() | 			p.next() | ||||||
| 			right := p.expr(precedence - 1) | 			right := p.expr(precedence - 1) | ||||||
| 			pos.update_last_line(p.prev_tok.line_nr) | 			pos.update_last_line(p.prev_tok.line_nr) | ||||||
|  | 			if mut node is ast.IndexExpr { | ||||||
|  | 				node.recursive_mapset_is_setter(true) | ||||||
|  | 			} | ||||||
| 			node = ast.InfixExpr{ | 			node = ast.InfixExpr{ | ||||||
| 				left: node | 				left: node | ||||||
| 				right: right | 				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.error_with_pos('$p.tok must be on the same line as the previous token', | ||||||
| 					p.tok.position()) | 					p.tok.position()) | ||||||
| 			} | 			} | ||||||
|  | 			if mut node is ast.IndexExpr { | ||||||
|  | 				node.recursive_mapset_is_setter(true) | ||||||
|  | 			} | ||||||
| 			node = ast.PostfixExpr{ | 			node = ast.PostfixExpr{ | ||||||
| 				op: p.tok.kind | 				op: p.tok.kind | ||||||
| 				expr: node | 				expr: node | ||||||
|  |  | ||||||
|  | @ -1,14 +1,4 @@ | ||||||
| struct Foo { | fn test_map_of_map() { | ||||||
| mut: |  | ||||||
| 	name string |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn test_nested_maps() { |  | ||||||
| 	if true { |  | ||||||
| 	} |  | ||||||
| 	//
 |  | ||||||
| 	else { |  | ||||||
| 	} |  | ||||||
| 	mut x := map[string]map[string]int{} | 	mut x := map[string]map[string]int{} | ||||||
| 	x['a'] = map[string]int{} | 	x['a'] = map[string]int{} | ||||||
| 	assert x['a']['b'] == 0 | 	assert x['a']['b'] == 0 | ||||||
|  | @ -16,6 +6,9 @@ fn test_nested_maps() { | ||||||
| 	assert x['a']['b'] == 5 | 	assert x['a']['b'] == 5 | ||||||
| 	x['a']['b'] = 7 | 	x['a']['b'] = 7 | ||||||
| 	assert 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{} | 	mut y := map[string]map[string]map[string]int{} | ||||||
| 	y['a'] = map[string]map[string]int{} | 	y['a'] = map[string]map[string]int{} | ||||||
| 	y['a']['b'] = map[string]int{} | 	y['a']['b'] = map[string]int{} | ||||||
|  | @ -24,9 +17,18 @@ fn test_nested_maps() { | ||||||
| 	assert y['a']['b']['c'] == 5 | 	assert y['a']['b']['c'] == 5 | ||||||
| 	y['a']['b']['c'] = 7 | 	y['a']['b']['c'] = 7 | ||||||
| 	assert 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' | struct Foo { | ||||||
| 	foos['a']['b'].name = 'baz' | mut: | ||||||
| 	assert foos['a']['b'].name == 'baz' | 	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