for循环中的隐式内存别名
Implicit memory aliasing in for loop
我正在使用 golangci-lint,但在以下代码中遇到错误:
versions []ObjectDescription
... (populate versions) ...
for i, v := range versions {
res := createWorkerFor(&v)
...
}
错误是:
G601: Implicit memory aliasing in for loop. (gosec)
res := createWorkerFor(&v)
^
"implicit memory aliasing in for loop" 到底是什么意思?我在 golangci-lint 文档中找不到任何错误描述。我不明白这个错误。
索引将解决问题:
for i := range versions {
res := createWorkerFor(&versions[i])
...
}
简而言之,警告意味着您正在获取循环变量的地址。
发生这种情况是因为在 for
statements 中重复使用了迭代变量。在每次迭代中,范围表达式中下一个元素的值被分配给迭代变量; v
没有改变,只有它的值改变了。因此,表达式 &v
指的是内存中的相同位置。
以下代码四次打印相同的内存地址:
for _, n := range []int{1, 2, 3, 4} {
fmt.Printf("%p\n", &n)
}
当您存储迭代变量的地址时,或者当您在循环内的闭包中使用它时,在您取消引用指针时,它的值可能已经改变。静态分析工具将检测到这一点并发出您看到的警告。
防止此问题的常见方法是:
- 索引范围 slice/array/map。这取第 i 个位置的实际元素的地址,而不是迭代变量
for i := range versions {
res := createWorkerFor(&versions[i])
}
- 在循环内重新分配迭代变量
for _, v := range versions {
v := v
res := createWorkerFor(&v) // this is now the address of the inner v
}
- 使用闭包,将迭代变量作为参数传递给闭包
for _, v := range versions {
go func(arg ObjectDescription) {
x := &arg // safe
}(v)
}
如果您在循环中按顺序取消引用并且您确定没有任何内容泄漏指针,您可能会忽略此检查。然而,linter 的工作恰恰是报告 可能 导致问题的代码模式,因此无论如何修复它是个好主意。
我正在使用 golangci-lint,但在以下代码中遇到错误:
versions []ObjectDescription
... (populate versions) ...
for i, v := range versions {
res := createWorkerFor(&v)
...
}
错误是:
G601: Implicit memory aliasing in for loop. (gosec)
res := createWorkerFor(&v)
^
"implicit memory aliasing in for loop" 到底是什么意思?我在 golangci-lint 文档中找不到任何错误描述。我不明白这个错误。
索引将解决问题:
for i := range versions {
res := createWorkerFor(&versions[i])
...
}
简而言之,警告意味着您正在获取循环变量的地址。
发生这种情况是因为在 for
statements 中重复使用了迭代变量。在每次迭代中,范围表达式中下一个元素的值被分配给迭代变量; v
没有改变,只有它的值改变了。因此,表达式 &v
指的是内存中的相同位置。
以下代码四次打印相同的内存地址:
for _, n := range []int{1, 2, 3, 4} {
fmt.Printf("%p\n", &n)
}
当您存储迭代变量的地址时,或者当您在循环内的闭包中使用它时,在您取消引用指针时,它的值可能已经改变。静态分析工具将检测到这一点并发出您看到的警告。
防止此问题的常见方法是:
- 索引范围 slice/array/map。这取第 i 个位置的实际元素的地址,而不是迭代变量
for i := range versions {
res := createWorkerFor(&versions[i])
}
- 在循环内重新分配迭代变量
for _, v := range versions {
v := v
res := createWorkerFor(&v) // this is now the address of the inner v
}
- 使用闭包,将迭代变量作为参数传递给闭包
for _, v := range versions {
go func(arg ObjectDescription) {
x := &arg // safe
}(v)
}
如果您在循环中按顺序取消引用并且您确定没有任何内容泄漏指针,您可能会忽略此检查。然而,linter 的工作恰恰是报告 可能 导致问题的代码模式,因此无论如何修复它是个好主意。