Skip to content

Instantly share code, notes, and snippets.

@Integralist
Last active November 17, 2023 12:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Integralist/7c6c9418ca6b328d6a721ccf34df050a to your computer and use it in GitHub Desktop.
Save Integralist/7c6c9418ca6b328d6a721ccf34df050a to your computer and use it in GitHub Desktop.
[Go range bug] #go #golang #range

Problem

Consider the following example:

package main

import "fmt"

func main() {
	for _, n := range []int{1, 2, 3, 4} {
		fmt.Printf("%#v | %d\n", &n, n) // NOTE: The memory address is the same! Meaning the value could change and print 4 each time.
	}
}

Static analysis tools (like gosec) will sometimes report:

G601: Implicit memory aliasing in for loop. (gosec)

This happens because in for statements the iteration variable is reused.

This means for each iteration, the value of the next element in the range expression is assigned to the iteration variable.

So v doesn't change, only its value changes. Hence, the expression &v is referring to the same location in memory.

When you store the address of the iteration variable, or when you use it in a closure inside the loop, by the time you dereference the pointer, its value might have changed.

Solutions

NOTE: Go might fix this in go1.22 (not guaranteed at time of writing).

Index the ranged slice/array/map. This takes the address of the actual element at i-th position, instead of the iteration variable:

for i := range versions {
    res := createWorkerFor(&versions[i])
}

Reassign the iteration variable inside the loop:

for _, v := range versions {
    v := v
    res := createWorkerFor(&v) // this is now the address of the inner v
}

With closures, pass the iteration variable as argument to the closure:

for _, v := range versions { 
    go func(arg ObjectDescription) {
        x := &arg // safe
    }(v)
}

Reference

This gist was produced after reading the answer given here: https://stackoverflow.com/a/68247837/14849316

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment