The warning means, in short, that you are taking the address of a loop variable.
This happens because in for
statements the iteration variable(s) is reused. At each iteration, the value of the next element in the range expression is assigned to the iteration variable; v
doesn't change, only its value changes. Hence, the expression &v
is referring to the same location in memory.
The following code prints the same memory address four times:
for _, n := range []int{1, 2, 3, 4} {
fmt.Printf("%p\n", &n)
}
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. Static analysis tools will detect this and emit the warning you see.
Common ways to prevent the issue are:
- 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)
}
In case you dereference sequentially within the loop and you know for sure that nothing is leaking the pointer, you might get away with ignoring this check. However the job of the linter is precisely to report code patterns that could cause issues, so it's a good idea to fix it anyway.