Beware of Implicit Memory Aliasing in Go For Loop
December 19, 2020
A for loop in Go will only use one iterator variable whose value gets updated in each loop operation. Since it’s just a single variable, its address is constant and doesn’t change. If not used carefully, it might lead to unintended behaviour.
Consider the following example.
package main
import "fmt"
func main() {
var output []*int
nums := []int{1, 2, 3}
for _, num := range nums {
output = append(output, &num)
}
fmt.Println("Value: ", *output[0], *output[1], *output[2])
fmt.Println("Address: ", output[0], output[1], output[2])
}
It will produce the following output:
Value: 3 3 3
Address: 0xc00010c000 0xc00010c000 0xc00010c000
To avoid such problem, we can access the item in the iterable directly instead of using the iterator variable.
package main
import "fmt"
func main() {
var output []*int
nums := []int{1, 2, 3}
for i := range nums {
output = append(output, &nums[i])
}
fmt.Println("Value: ", *output[0], *output[1], *output[2])
fmt.Println("Address: ", output[0], output[1], output[2])
}
Output:
Value: 1 2 3
Address: 0xc00013a000 0xc00013a008 0xc00013a010
Gosec can detect this problem automatically for you. If you scan the code in the first example with gosec, you’ll get the following output:
[/home/user/project/implicit-memory-aliasing/main.go:10] - G601 (CWE-118): Implicit memory aliasing in for loop. (Confidence: MEDIUM, Severity: MEDIUM)
9: for _, num := range nums {
> 10: output = append(output, &num)
11: }