ch13: fix code path

This commit is contained in:
chai2010
2016-01-20 22:50:43 +08:00
parent 8b7a8ea019
commit 617ef87432
3 changed files with 8 additions and 16 deletions

View File

@@ -18,9 +18,8 @@ fmt.Printf("%#016x\n", Float64bits(1.0)) // "0x3ff0000000000000"
許多將unsafe.Pointer指針轉爲原生數字然後再轉迴爲unsafe.Pointer類型指針的操作也是不安全的。比如下面的例子需要將變量x的地址加上b字段地址偏移量轉化爲`*int16`類型指針然後通過該指針更新x.b
<u><i>gopl.io/ch13/unsafeptr</i></u>
```Go
//gopl.io/ch13/unsafeptr
var x struct {
a bool
b int16
@@ -37,10 +36,10 @@ fmt.Println(x.b) // "42"
上面的寫法盡管很繁瑣但在這里併不是一件壞事因爲這些功能應該很謹慎地使用。不要試圖引入一個uintptr類型的臨時變量因爲它可能會破壞代碼的安全性譯註這是眞正可以體會unsafe包爲何不安全的例子。下面段代碼是錯誤的
```Go
// NOTE: subtly incorrect!
tmp := uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.b)
pb := (*int16)(unsafe.Pointer(tmp))
*pb = 42
// NOTE: subtly incorrect!
tmp := uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.b)
pb := (*int16)(unsafe.Pointer(tmp))
*pb = 42
```
産生錯誤的原因很微妙。有時候垃圾迴收器會移動一些變量以降低內存碎片等問題。這類垃圾迴收器被稱爲移動GC。當一個變量被移動所有的保存改變量舊地址的指針必須同時被更新爲變量移動後的新地址。從垃圾收集器的視角來看一個unsafe.Pointer是一個指向變量的指針因此當變量被移動是對應的指針也必須被更新但是uintptr類型的臨時變量隻是一個普通的數字所以其值不應該被改變。上面錯誤的代碼因爲引入一個非指針的臨時變量tmp導致垃圾收集器無法正確識别這個是一個指向變量x的指針。當第二個語句執行時變量x可能已經被轉移這時候臨時變量tmp也就不再是現在的`&x.b`地址。第三個向之前無效地址空間的賦值語句將徹底摧譭整個程序!
@@ -66,5 +65,3 @@ func (Value) Pointer() uintptr
func (Value) UnsafeAddr() uintptr
func (Value) InterfaceData() [2]uintptr // (index 1)
```