Skip to content

Commit a209843

Browse files
Fix bytesToStr (#358)
The current implementation of bytesToStr uses an unsafe reflect.StringHeader value. Change the implementation of this function to a safe and simpler version. To explain what could go wrong here is some example code: var d []byte d = someFunctionThatReturnsBytes() s := bytesToStr(d) doSomethingWith(s) When this code gets compiled bytesToStr would get inlined and the code would be like the following. I have included in comments at which point things could go wrong: var d []byte d = someFunctionThatReturnsBytes() h := (*reflect.SliceHeader)(unsafe.Pointer(&d)) shdr := reflect.StringHeader{Data: h.Data, Len: h.Len} // At this point in time d and d.Data have nothing referencing them anymore // shdr.Data is an uintptr so it will be ignored by the GC. // This means d and d.Data can be garbage collected here. // Internally strings don't use a uintptr for the data, but since this is // just a reflect.StringHeader and not a real string yet that doesn't apply // here. // This is why https://pkg.go.dev/unsafe#Pointer says: // In general, reflect.SliceHeader and reflect.StringHeader should be // used only as *reflect.SliceHeader and *reflect.StringHeader pointing // at actual slices or strings, never as plain structs. s := *(*string)(unsafe.Pointer(&shdr)) // Only at this point s.Data points to d.Data again and the backing storage // of d won't be garbage collected anymore. doSomethingWith(s) The chance of this going wrong is probably so small that nobody ever noticed it happening, but it is there.
1 parent 11c9d7f commit a209843

File tree

1 file changed

+1
-4
lines changed

1 file changed

+1
-4
lines changed

jlexer/bytestostr.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
package jlexer
99

1010
import (
11-
"reflect"
1211
"unsafe"
1312
)
1413

@@ -18,7 +17,5 @@ import (
1817
// chunk may be either blocked from being freed by GC because of a single string or the buffer.Data
1918
// may be garbage-collected even when the string exists.
2019
func bytesToStr(data []byte) string {
21-
h := (*reflect.SliceHeader)(unsafe.Pointer(&data))
22-
shdr := reflect.StringHeader{Data: h.Data, Len: h.Len}
23-
return *(*string)(unsafe.Pointer(&shdr))
20+
return *(*string)(unsafe.Pointer(&data))
2421
}

0 commit comments

Comments
 (0)