使用unsafe.Pointer时,切片边界超出范围

时间:2017-01-11 12:33:47

标签: go

当我使用类似b [1:2]的语法修剪字节数组时,我遇到了一个奇怪的恐慌,这种语法从[] byte转换为string然后再转换回[] byte。

我的go版本是go1.7.3 darwin / amd64。以下是详细代码。

package main

import (
            "reflect"
            "unsafe"
            "fmt"

)

func BytesToString(b []byte) string {
    bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
    sh := reflect.StringHeader{bh.Data, bh.Len}
    return *(*string)(unsafe.Pointer(&sh))
}

func StringToBytes(s string) []byte {
    sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
    bh := reflect.SliceHeader{sh.Data, sh.Len, 0}
    return *(*[]byte)(unsafe.Pointer(&bh))
}

func main() {
b := []byte{'b', 'y', 't', 'e'}

// No1  here you can trim []byte using b[1:2]
_ = b[1:2]
fmt.Println("No1")

// convert []byte to string
s := BytesToString(b)

// convert string to []byte
b = StringToBytes(s)

// create new []byte variant using content of b
bb := make([]byte, len(b))
for i := 0; i < len(b); i++ {
    bb[i] = b[i]
}

// No2 here you also can trim []byte using bb[1:2]
_ = bb[1:2]
fmt.Println("No2")

// No3 here you can not trim []byte. I don't know why. why?
_ = b[1:2]
fmt.Println("No3")

}

运行此代码,并收到如下错误:

 No1
 No2
 panic: runtime error: slice bounds out of range

 goroutine 1 [running]:
 panic(0x8f060, 0xc42000a100)
 /usr/local/Cellar/go/1.7.3/libexec/src/runtime/panic.go:500 +0x1a1
 main.main()
 /tmp/unsafe.go:45 +0x274
 exit status 2

我很好奇是什么导致了这种恐慌?

1 个答案:

答案 0 :(得分:2)

StringToBytes创建的切片的capacity为零。

for循环不会因为index expressions检查len(b)而感到恐慌。

表达式b[1:2]恐慌,因为slice expressions检查cap(b)

一种解决方法是将容量设置为字符串的长度:

func StringToBytes(s string) []byte {
    sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
    bh := reflect.SliceHeader{sh.Data, sh.Len, sh.Len}
    return *(*[]byte)(unsafe.Pointer(&bh))
}