On Thu, 24 Dec 2015 13:26:51 +0800
Hoping White <
baiha...@gmail.com> wrote:
> Hi, Ian
>
> I interchange data between go and cpp using the following pattern
>
>
> func getByteSlicePointer(data []byte) unsafe.Pointer {
> if data == nil {
> return unsafe.Pointer(nil)
> }
> header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
> return unsafe.Pointer(header.Data)
> }
>
> func setByteSlicePointer(data *[]byte, buffer unsafe.Pointer, size
> uint32) { header := (*reflect.SliceHeader)(unsafe.Pointer(data))
> header.Len = int(size)
> header.Cap = int(size)
> header.Data = uintptr(buffer)
> }
>
>
> func getStringPointer(s *string) unsafe.Pointer {
> if s == nil {
> return unsafe.Pointer(nil)
> }
> header := (*reflect.StringHeader)(unsafe.Pointer(s))
> return unsafe.Pointer(header.Data)
> }
Don't use `reflect.*Header` -- the Go authors actually regret exposing
this implementation detail. Use cgo-provided facilities and a
type-conversion trick to convert C byte-arrays to Go's byte slices.
Please read [1] for more info.
On a side note, your examples miss context. Are you positive that once
you passed the data from your C side to Go it stays alive (that is, not
free()d or realloc()ed during its entire lifetime)? The same goes for
Go: once you applied your getByteSlicePointer() to a Go value of type
[]byte and passed the resuting raw pointer to the C side, are you sure
your Go variable does not go out of scope and loses a last reference to
it (and gets garbage collected)? Note that a pointer passed to a C
side it not counted as a reference to a variable: it only is until the
call into C code is in proress; once it's over, the C side must not use
this pointer anymore because the GC on the Go side might have moved the
memory pointed to by that pointer or reclaimed it.
If you need a buffer truly shared by C and Go sides, you either should
obtain it through C.malloc() (and then guarantee the C side won't call
realloc() on that memory) or use a custom allocator on the Go side
(say, allocate a memory pool by using syscall.Mmap with MAP_ANONYMOUS
and then allocate your buffers there; pointers to these buffers may be
freely shared between C and Go sides).
> By the way, I have tried -msan with no luck. It seems my go version
> does not support msan. Can you be more specific about this?
In order for -msan to work, you must be on linux/amd64 and use clang (a
C compiler from the LLVM suite), not gcc, to build your cgo code.
Supposedly you need to export the CC (or CXX if your C side is C++ in
fact) environment variable set to "clang". You might also need to
massage the compiler flags a bit (I dunno). Consider reading [2] and
study the output of `go env` to get a better idea.
[3] is what Go uses when building with -msan and clang.
1.
https://github.com/golang/go/wiki/cgo
2.
https://golang.org/cmd/cgo/
3.
http://clang.llvm.org/docs/MemorySanitizer.html