Hello gophers,
I have a question which relates mostly to the ideology of unsafe usage.
In `
github.com/gobwas/ws` WebSocket library I used an optimization for
reading WebSocket frame headers into stack based slices (to reduce the
number of heap allocations):
func ReadHeader(r io.Reader) (Header, error) {
var (
b [16]byte
bts []byte
)
h := (*reflect.SliceHeader)(unsafe.Pointer(&bts))
*h = reflect.SliceHeader{
Data: uintptr(unsafe.Pointer(&b)),
Len: len(b),
Cap: len(b),
}
_, err = io.ReadFull(r, bts)
// process bytes and return result.
}
This works fine on Linux for a long time and under the high load, but on
Windows it sometimes crashes or has an unexpected behaviour.
Crashes are happened with the message like:
> fatal error: found bad pointer in Go heap (incorrect use of unsafe or cgo?)
I may assume that the bad pointer errors are relate to the
internal/poll/fd_windows.go operation buffer implementation, which
stores pointer to the first byte of given destination buffer – and since
the buffer is stack based GC throws such error.
I may assume that the unexpected behaviour happens after goroutine stack
moving/copying but can not reproduce it yet during tests.
But nevertheless, my question is: is it legal to use unsafe in that way
in general? Should I split the implementation of ReadHeader() to support
windows separately without stack based slices?
References:
https://github.com/golang/go/blob/d97bd5d07ac4e7b342053b335428ff9c97212f9f/src/internal/poll/fd_windows.go#L526
https://github.com/gobwas/ws/blob/89d0ae05650f2cc04354d7fef282df0db5acff80/read.go#L18
https://github.com/gobwas/ws/issues/73
--
Regards,
Sergey.