UnsafeStrToBytes is currently not safe for -d=checkptr=2, since when it cast from smaller struct (string) to bigger struct ([]byte). That causes checkptr complains as the casting straddle multiple heap objects. To fix this, we have to get the string header first, then use its fields to construct the slice. New implementation performs the same speed with the old (wrong) one. name old time/op new time/op delta UnsafeStrToBytes-8 25.7ns ± 1% 25.7ns ± 3% ~ (p=0.931 n=10+17) name old alloc/op new alloc/op delta UnsafeStrToBytes-8 7.00B ± 0% 7.00B ± 0% ~ (all equal) name old allocs/op new allocs/op delta UnsafeStrToBytes-8 0.00 0.00 ~ (all equal) While at it, also simplify UnsafeBytesToStr implementation, since when we can pass the slice directly to unsafe.Pointer, instead of getting the slice header first.
55 lines
1.2 KiB
Go
55 lines
1.2 KiB
Go
package conv
|
|
|
|
import (
|
|
"runtime"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
func TestStringSuite(t *testing.T) {
|
|
suite.Run(t, new(StringSuite))
|
|
}
|
|
|
|
type StringSuite struct{ suite.Suite }
|
|
|
|
func unsafeConvertStr() []byte {
|
|
return UnsafeStrToBytes("abc")
|
|
}
|
|
|
|
func (s *StringSuite) TestUnsafeStrToBytes() {
|
|
// we convert in other function to trigger GC. We want to check that
|
|
// the underlying array in []bytes is accessible after GC will finish swapping.
|
|
for i := 0; i < 5; i++ {
|
|
b := unsafeConvertStr()
|
|
runtime.GC()
|
|
<-time.NewTimer(2 * time.Millisecond).C
|
|
b2 := append(b, 'd')
|
|
s.Equal("abc", string(b))
|
|
s.Equal("abcd", string(b2))
|
|
}
|
|
}
|
|
|
|
func unsafeConvertBytes() string {
|
|
return UnsafeBytesToStr([]byte("abc"))
|
|
}
|
|
|
|
func (s *StringSuite) TestUnsafeBytesToStr() {
|
|
// we convert in other function to trigger GC. We want to check that
|
|
// the underlying array in []bytes is accessible after GC will finish swapping.
|
|
for i := 0; i < 5; i++ {
|
|
str := unsafeConvertBytes()
|
|
runtime.GC()
|
|
<-time.NewTimer(2 * time.Millisecond).C
|
|
s.Equal("abc", str)
|
|
}
|
|
}
|
|
|
|
func BenchmarkUnsafeStrToBytes(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
UnsafeStrToBytes(strconv.Itoa(i))
|
|
}
|
|
}
|