Husni Munaya

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:         }