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 { | ||||
| 						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) | ||||
| 					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