gpt4 book ai didi

go - 在 Go 中什么时候仅通过 `uintptr` 引用对象是安全的?

转载 作者:IT王子 更新时间:2023-10-29 01:12:52 30 4
gpt4 key购买 nike

Go 编程语言在第 13.2 节中说这是代码是安全的并且 x 将始终对垃圾收集器可见:

pb := (*int16)(unsafe.Pointer(
uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.b)))
*pb = 42

并且这段代码是不安全的,因为 x 暂时对垃圾收集器,它可以移动它,使 pb 成为悬空指针:

tmp := uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.b)
pb := (*int16)(unsafe.Pointer(tmp))
*pb = 42

但我看不出这两个例子之间的区别。

在描述为安全的情况下,在 uintptr 被调用之后,唯一的对 x 的引用是 uintptr 值,不是吗?有一个指针它在同一行,但它是 uintptr 的一个参数,它已经运行,所以没有任何东西引用参数,所以 Pointer 不是事件的,uintptr 是对该对象的唯一引用。

我看不出如何将 uintptr 存储在局部变量中而不是作为表达式中间值使它更安全。不是局部变量就像 tmp 无论如何在编译阶段被删除,成为匿名数据流边缘,以便生成的代码在语义上应该是等价的?或者 Go 有垃圾收集何时可以运行的一些规则?例如只有安全点语句之间?但是第一个例子中的代码有方法调用,所以我会假设它们总是安全点吗?

最佳答案

找到我在评论中暗示的引用here

A uintptr is an integer, not a reference. Converting a Pointer to a uintptr creates an integer value with no pointer semantics. Even if a uintptr holds the address of some object, the garbage collector will not update that uintptr's value if the object moves, nor will that uintptr keep the object from being reclaimed.

这意味着这个表达式:

pb := (*int16)(unsafe.Pointer(
uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.b)))
*pb = 42

是安全的,因为你正在创建一个 uintptr,它被视为一个整数,而不是一个引用,但它会被立即分配(除非其他地方存在竞争条件, 的对象x 引用不能被 GC 处理)直到 赋值之后)。 uintptr(再次:整数类型)也立即转换为指针,将其转换为引用,以便 GC 管理 pb。这意味着:

  • uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.b)):一切安全,因为 x 显然是对对象的现有引用<
  • pb 被分配了一个整数,该整数(通过转换)标记为对 int16 对象的引用

但是,当你这样写的时候:

tmp := uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.b)
pb := (*int16)(unsafe.Pointer(tmp))

有可能在分配tmp(记住整数,而不是引用)之间,移动内存中的实际对象。正如文档中所说:tmp 更新。因此,当您分配 pb 时,您可能会得到一个无效指针。
将本例中的 tmp 视为第一种情况下的 x。它不是对对象的引用,而是你写的

tmp := 123456 // a random integer
pb := (*int16) (unsafe.Pointer(tmp)) // not safe, obviously

例如:

var pb *int16
tmp := uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.b)
go func() {
time.Sleep(1 * time.Second)
pb = (*int16)(unsafe.Pointer(tmp))
}()
// original value of x could be GC'ed here, before the goroutine starts, or the time.Sleep call returns
x = TypeOfX{
b: 123,
}

关于go - 在 Go 中什么时候仅通过 `uintptr` 引用对象是安全的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42067478/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com