为了账号安全,请及时绑定邮箱和手机立即绑定

for循环中的隐式内存别名

for循环中的隐式内存别名

Go
呼如林 2022-06-13 10:58:22
我正在使用 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)                                            ^“for循环中的隐式内存别名”到底是什么意思?我在 golangci-lint 文档中找不到任何错误描述。我不明白这个错误。
查看完整描述

2 回答

?
德玛西亚99

TA贡献1770条经验 获得超3个赞

简而言之,警告意味着您正在获取循环变量的地址。


发生这种情况是因为在for语句中重复使用了迭代变量。在每次迭代中,将范围表达式中下一个元素的值赋给迭代变量;v不会改变,只会改变它的值。因此,该表达式&v指的是内存中的同一位置。


以下代码四次打印相同的内存地址:


for _, n := range []int{1, 2, 3, 4} {

    fmt.Printf("%p\n", &n)

}

当您存储迭代变量的地址时,或者当您在循环内的闭包中使用它时,当您取消引用指针时,它的值可能已经改变。静态分析工具会检测到这一点并发出您看到的警告。


防止该问题的常见方法是:


索引范围切片/数组/映射。这将获取第 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 的工作正是报告可能导致问题的代码模式,因此无论如何修复它都是一个好主意。


查看完整回答
反对 回复 2022-06-13
?
江户川乱折腾

TA贡献1851条经验 获得超5个赞

索引将解决问题:


for i := range versions {

    res := createWorkerFor(&versions[i])

    ...


}


查看完整回答
反对 回复 2022-06-13
  • 2 回答
  • 0 关注
  • 607 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号