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

字节切片转换与不安全的字符串更改其地址

字节切片转换与不安全的字符串更改其地址

Go
慕码人2483693 2022-09-12 20:54:19
我有这个函数将字符串转换为字节切片而不复制func StringToByteUnsafe(s string) []byte {    strh := (*reflect.StringHeader)(unsafe.Pointer(&s))    var sh reflect.SliceHeader    sh.Data = strh.Data    sh.Len = strh.Len    sh.Cap = strh.Len    return *(*[]byte)(unsafe.Pointer(&sh))}这工作正常,但是通过非常具体的设置会产生非常奇怪的行为:设置在这里:https://github.com/leviska/go-unsafe-gc/blob/main/pkg/pkg_test.go会发生什么情况:创建字节切片将其转换为临时(右值)字符串,并使用不安全再次将其转换为字节切片然后,复制此切片(通过引用)然后,用戈鲁丁内的第二个切片做点什么打印前后的指针我在我的linux mint笔记本电脑上有这个输出,带有go 1.16:go test ./pkg -v -count=1=== RUN   TestSomething0xc000046720 123 0xc000046720 1230xc000076f20 123 0xc000046721 z--- PASS: TestSomething (0.84s)PASSok      github.com/leviska/go-unsafe-gc/pkg     0.847s因此,第一个切片神奇地改变了它的地址,而第二个切片则不是如果我们删除 goroutine(并且可能稍微玩弄一下代码),我们可以获取两个指针来更改值(更改为同一个指针)。runtime.GC()如果我们将不安全的强制转换更改为所有内容,则无需更改地址即可工作。此外,如果我们从这里将其更改为不安全的强制值,https://stackoverflow.com/a/66218124/5516391 一切工作原理相同。[]byte()func StringToByteUnsafe(str string) []byte { // this works fine    var buf = *(*[]byte)(unsafe.Pointer(&str))    (*reflect.SliceHeader)(unsafe.Pointer(&buf)).Cap = len(str)    return buf}我运行它并得到相同的结果。我运行它,没有错误。GOGC=off-race如果将其作为具有 main 函数的主包运行,它似乎可以正常工作。此外,如果您删除该函数。我的猜测是编译器在这种情况下会优化内容。Convert所以,我对此有几个问题:这到底是怎么回事?看起来像一个奇怪的UB为什么运行时会神奇地更改变量的地址?为什么在无并发情况下它可以更改两个地址,而在并发情况下不能?这个不安全的强制转换与堆栈溢出答案的强制转换之间有什么区别?为什么它有效?或者这只是一个编译器错误?
查看完整描述

1 回答

?
三国纷争

TA贡献1804条经验 获得超7个赞

来自github问题的回答 https://github.com/golang/go/issues/47247

的后备存储是在堆栈上分配的,因为它不会转义。戈鲁丁堆栈可以动态移动。另一方面,b逃逸到堆中,因为它被传递给另一个戈鲁廷。通常,我们不会假设对象的地址不会更改。

这按预期工作。

我的版本不正确,因为

它使用反射。切片标题作为普通结构。你可以对它进行兽医检查,去兽医会警告你。


查看完整回答
反对 回复 2022-09-12
  • 1 回答
  • 0 关注
  • 73 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

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

帮助反馈 APP下载

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

公众号

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