aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAyke van Laethem <aykevanlaethem@gmail.com>2017-10-02 20:27:54 +0200
committerAyke van Laethem <aykevanlaethem@gmail.com>2017-10-02 20:29:19 +0200
commitc00c43c28b3f2e269931aa7a9e6f7e622ac838da (patch)
treedc3279c3040cfc47712ace9988d6a68887a42906
parenta1518c8e91c6923c4c48677fc543447b465dd16a (diff)
downloadgolibrsync-c00c43c28b3f2e269931aa7a9e6f7e622ac838da.tar.gz
golibrsync-c00c43c28b3f2e269931aa7a9e6f7e622ac838da.tar.bz2
golibrsync-c00c43c28b3f2e269931aa7a9e6f7e622ac838da.zip
Do not store Go pointers in C structs
-rw-r--r--librsync/librsync.go26
-rw-r--r--librsync/librsync_callback.go18
2 files changed, 31 insertions, 13 deletions
diff --git a/librsync/librsync.go b/librsync/librsync.go
index 1ffc7ec..3bebd6f 100644
--- a/librsync/librsync.go
+++ b/librsync/librsync.go
@@ -74,9 +74,10 @@ type Job struct {
running bool
err error
- inbuf []byte
+ inbuf unsafe.Pointer
in io.Reader
+ outbufOrig unsafe.Pointer
outbufTotal []byte
outbuf []byte
}
@@ -85,8 +86,9 @@ func newJob(input io.Reader) (job *Job, err error) {
job = new(Job)
job.in = input
- job.inbuf = make([]byte, inbufSize)
- job.outbufTotal = make([]byte, outbufSize)
+ job.inbuf = C.malloc(inbufSize)
+ job.outbufOrig = C.malloc(outbufSize)
+ job.outbufTotal = (*[outbufSize]byte)(job.outbufOrig)[:]
job.rsbufs = C.new_rs_buffers()
if job.rsbufs == nil {
@@ -158,6 +160,9 @@ func (job *Job) Close() error {
job.job = nil
}
+ C.free(job.inbuf)
+ C.free(job.outbufOrig)
+
return nil
}
@@ -227,7 +232,9 @@ func (job *Job) Read(p []byte) (readN int, outerr error) {
// Fill input buffer
if (job.rsbufs.avail_in == 0) && (job.rsbufs.eof_in == 0) {
- n, err := job.in.Read(job.inbuf[0:inbufSize])
+ // Turn job.inbuf (C buffer) into a Go slice
+ // https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices
+ n, err := job.in.Read((*[inbufSize]byte)(job.inbuf)[:])
switch err {
case nil:
@@ -240,7 +247,7 @@ func (job *Job) Read(p []byte) (readN int, outerr error) {
return
}
- job.rsbufs.next_in = (*C.char)(unsafe.Pointer(&(job.inbuf[0])))
+ job.rsbufs.next_in = (*C.char)(job.inbuf)
job.rsbufs.avail_in = C.size_t(n)
}
@@ -325,7 +332,7 @@ func NewDeltaGen(sig Signature, newfile io.Reader) (job *Job, err error) {
type Patcher struct {
*Job
basis io.ReaderAt
- buf []byte
+ buf unsafe.Pointer
}
var patchCallback = C.patchCallback // So we can use the `&` operator in NewPatcher
@@ -347,7 +354,7 @@ func NewPatcher(delta io.Reader, basis io.ReaderAt) (job *Patcher, err error) {
id := uintptr(unsafe.Pointer(_job.rsbufs)) // this is a unique, unchanging number (C doesn't change pointers under the hood)
storePatcher(job, id)
- job.job = C.rs_patch_begin((*C.rs_copy_cb)(patchCallback), unsafe.Pointer(id))
+ job.job = C.rs_patch_begin((*C.rs_copy_cb)(patchCallback), unsafe.Pointer(_job.rsbufs))
if job.job == nil {
dropPatcher(id)
job.Close()
@@ -361,5 +368,10 @@ func NewPatcher(delta io.Reader, basis io.ReaderAt) (job *Patcher, err error) {
// able to free.
func (patch *Patcher) Close() error {
dropPatcher(uintptr(unsafe.Pointer(patch.Job.rsbufs)))
+
+ if patch.buf != nil {
+ C.free(patch.buf)
+ }
+
return patch.Job.Close()
}
diff --git a/librsync/librsync_callback.go b/librsync/librsync_callback.go
index ace9779..66b16c7 100644
--- a/librsync/librsync_callback.go
+++ b/librsync/librsync_callback.go
@@ -3,6 +3,7 @@ package librsync
/*
#include <stdio.h>
#include <librsync.h>
+#include <stdlib.h>
*/
import "C"
@@ -12,20 +13,25 @@ import (
)
//export patchCallbackGo
-func patchCallbackGo(_patcher uintptr, pos C.rs_long_t, len *C.size_t, _buf *unsafe.Pointer) C.rs_result {
+func patchCallbackGo(_patcher uintptr, pos C.rs_long_t, buflen *C.size_t, buf *unsafe.Pointer) C.rs_result {
patcher := getPatcher(_patcher)
- patcher.buf = make([]byte, int(*len))
- n, err := patcher.basis.ReadAt(patcher.buf, int64(pos))
- if n < int(*len) {
+ if patcher.buf != nil {
+ C.free(patcher.buf)
+ }
+ patcher.buf = C.malloc(*buflen)
+ // https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices
+ s := (*[1 << 30]byte)(patcher.buf)[:*buflen:*buflen]
+ n, err := patcher.basis.ReadAt(s, int64(pos))
+ if n < int(*buflen) {
if err != io.EOF {
panic(jobInternalPanic{err})
} else {
return C.RS_INPUT_ENDED
}
}
- *len = C.size_t(n)
- *_buf = unsafe.Pointer(&(patcher.buf[0]))
+ *buflen = C.size_t(n)
+ *buf = patcher.buf
return C.RS_DONE
}