fix: misuse of reflect.SliceHeader (#19875)

Currently, unsafeBytesToString function violates the 6th rule of unsafe
pointer usage. That is, reflect.SliceHeader/String header should never
be used as plain struct. This misuse can make to silent memory
corruption, which can be difficult to track down when problem occurred.

Instead, use the more (right) idiom to convert slice of byte to string
without heap allocation.

goos: linux
goarch: amd64
cpu: Intel(R) Core(TM) i7-8665U CPU @ 1.90GHz
BenchmarkInvalid-8   	1000000000	         0.497 ns/op	       0 B/op	       0 allocs/op
BenchmarkValid-8     	1000000000	         0.239 ns/op	       0 B/op	       0 allocs/op
PASS
ok  	command-line-arguments	0.815s
pull/19939/head
Cuong Manh Le 2020-11-09 21:37:20 +07:00 committed by GitHub
parent ee390ddfd3
commit 51ff6f7b5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 2 additions and 19 deletions

9
id.go
View File

@ -3,7 +3,6 @@ package influxdb
import ( import (
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"reflect"
"strconv" "strconv"
"unsafe" "unsafe"
) )
@ -83,13 +82,7 @@ func (i *ID) Decode(b []byte) error {
} }
func unsafeBytesToString(in []byte) string { func unsafeBytesToString(in []byte) string {
src := *(*reflect.SliceHeader)(unsafe.Pointer(&in)) return *(*string)(unsafe.Pointer(&in))
dst := reflect.StringHeader{
Data: src.Data,
Len: src.Len,
}
s := *(*string)(unsafe.Pointer(&dst))
return s
} }
// DecodeFromString parses s as a hex-encoded string. // DecodeFromString parses s as a hex-encoded string.

View File

@ -1,7 +1,6 @@
package models // import "github.com/influxdata/influxdb/models" package models // import "github.com/influxdata/influxdb/models"
import ( import (
"reflect"
"strconv" "strconv"
"unsafe" "unsafe"
) )
@ -30,15 +29,6 @@ func parseBoolBytes(b []byte) (bool, error) {
} }
// unsafeBytesToString converts a []byte to a string without a heap allocation. // unsafeBytesToString converts a []byte to a string without a heap allocation.
//
// It is unsafe, and is intended to prepare input to short-lived functions
// that require strings.
func unsafeBytesToString(in []byte) string { func unsafeBytesToString(in []byte) string {
src := *(*reflect.SliceHeader)(unsafe.Pointer(&in)) return *(*string)(unsafe.Pointer(&in))
dst := reflect.StringHeader{
Data: src.Data,
Len: src.Len,
}
s := *(*string)(unsafe.Pointer(&dst))
return s
} }