]> Sergey Matveev's repositories - go-opus.git/commitdiff
Move callbacks struct to C allocator, to be safe
authorHraban Luyat <hraban@0brg.net>
Mon, 22 Aug 2016 14:11:13 +0000 (15:11 +0100)
committerHraban Luyat <hraban@0brg.net>
Mon, 22 Aug 2016 14:11:13 +0000 (15:11 +0100)
I'm not sure if the Go pointer proposal has already been implemented,
but under the proposed restrictions allocating the callback struct in Go
and passing that pointer to a C function which keeps it after returning
is not allowed.

This patch allocates the struct in C and passes the pointer from Go to
C, which is fine.

callbacks.c [new file with mode: 0644]
stream.go

diff --git a/callbacks.c b/callbacks.c
new file mode 100644 (file)
index 0000000..9148557
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright © 2015, 2016 Hraban Luyat <hraban@0brg.net>
+//
+// License for use of this code is detailed in the LICENSE file
+
+// Allocate callback struct in C to ensure it's not managed by the Go GC. This
+// plays nice with the CGo rules and avoids any confusion.
+
+#include <opusfile.h>
+
+// Defined in Go. Uses the same signature as Go, no need for proxy function.
+int go_readcallback(void *p, unsigned char *buf, int nbytes);
+
+// Allocated once, never moved. Pointer to this is safe for passing around
+// between Go and C.
+struct OpusFileCallbacks callbacks = {
+    .read = go_readcallback,
+};
index b087c33d33083faf7c6c1e40ea5ef57b4c804b3d..bc1b8a6ddc99f0a21b5904e978d9687b38eb576a 100644 (file)
--- a/stream.go
+++ b/stream.go
@@ -15,8 +15,7 @@ import (
 #include <opusfile.h>
 #include <string.h>
 
-// Uses the same signature as Go, no need for proxy
-int go_readcallback(void *p, unsigned char *buf, int nbytes);
+extern struct OpusFileCallbacks callbacks;
 
 */
 import "C"
@@ -61,13 +60,6 @@ func go_readcallback(p unsafe.Pointer, cbuf *C.uchar, cmaxbytes C.int) C.int {
        return C.int(n)
 }
 
-var callbacks = C.struct_OpusFileCallbacks{
-       read:  C.op_read_func(C.go_readcallback),
-       seek:  nil,
-       tell:  nil,
-       close: nil,
-}
-
 func NewStream(read io.Reader) (*Stream, error) {
        var s Stream
        err := s.Init(read)
@@ -104,7 +96,7 @@ func (s *Stream) Init(read io.Reader) error {
        oggfile := C.op_open_callbacks(
                // "C code may not keep a copy of a Go pointer after the call returns."
                unsafe.Pointer(s.id),
-               &callbacks,
+               &C.callbacks,
                nil,
                0,
                &errno)