Skip to content
This repository has been archived by the owner on Aug 31, 2020. It is now read-only.

Fix a segfault caused by invalid Go pointer #53

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion usb/endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func TestEndpoint(t *testing.T) {
fakeT := lib.waitForSubmitted()
fakeT.length = tc.ret
fakeT.status = tc.status
close(fakeT.done)
fakeT.done <- struct{}{}
}()
opv := op.Func.Interface().(func(*endpoint, []byte) (int, error))
got, err := opv(ep, tc.buf)
Expand Down
7 changes: 3 additions & 4 deletions usb/fakelibusb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,19 +256,18 @@ func (f *fakeLibusb) setAlt(d *libusbDevHandle, intf, alt uint8) error {
return nil
}

func (f *fakeLibusb) alloc(_ *libusbDevHandle, _ uint8, _ TransferType, _ time.Duration, _ int, buf []byte) (*libusbTransfer, error) {
func (f *fakeLibusb) alloc(_ *libusbDevHandle, _ uint8, _ TransferType, _ time.Duration, _ int, buf []byte, done chan struct{}) (*libusbTransfer, error) {
f.mu.Lock()
defer f.mu.Unlock()
t := new(libusbTransfer)
f.ts[t] = &fakeTransfer{buf: buf}
f.ts[t] = &fakeTransfer{buf: buf, done: done}
return t, nil
}
func (f *fakeLibusb) cancel(t *libusbTransfer) error { return errors.New("not implemented") }
func (f *fakeLibusb) submit(t *libusbTransfer, done chan struct{}) error {
func (f *fakeLibusb) submit(t *libusbTransfer) error {
f.mu.Lock()
ft := f.ts[t]
f.mu.Unlock()
ft.done = done
f.submitted <- ft
return nil
}
Expand Down
34 changes: 24 additions & 10 deletions usb/libusb.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"fmt"
"log"
"reflect"
"sync"
"time"
"unsafe"
)
Expand Down Expand Up @@ -69,9 +70,9 @@ type libusbIntf interface {
setAlt(*libusbDevHandle, uint8, uint8) error

// transfer
alloc(*libusbDevHandle, uint8, TransferType, time.Duration, int, []byte) (*libusbTransfer, error)
alloc(*libusbDevHandle, uint8, TransferType, time.Duration, int, []byte, chan struct{}) (*libusbTransfer, error)
cancel(*libusbTransfer) error
submit(*libusbTransfer, chan struct{}) error
submit(*libusbTransfer) error
data(*libusbTransfer) (int, TransferStatus)
free(*libusbTransfer)
setIsoPacketLengths(*libusbTransfer, uint32)
Expand Down Expand Up @@ -312,7 +313,7 @@ func (libusbImpl) setAlt(d *libusbDevHandle, iface, setup uint8) error {
return fromUSBError(C.libusb_set_interface_alt_setting((*C.libusb_device_handle)(d), C.int(iface), C.int(setup)))
}

func (libusbImpl) alloc(d *libusbDevHandle, addr uint8, tt TransferType, timeout time.Duration, isoPackets int, buf []byte) (*libusbTransfer, error) {
func (libusbImpl) alloc(d *libusbDevHandle, addr uint8, tt TransferType, timeout time.Duration, isoPackets int, buf []byte, done chan struct{}) (*libusbTransfer, error) {
xfer := C.libusb_alloc_transfer(C.int(isoPackets))
if xfer == nil {
return nil, fmt.Errorf("libusb_alloc_transfer(%d) failed", isoPackets)
Expand All @@ -324,15 +325,18 @@ func (libusbImpl) alloc(d *libusbDevHandle, addr uint8, tt TransferType, timeout
xfer.num_iso_packets = C.int(isoPackets)
xfer.buffer = (*C.uchar)((unsafe.Pointer)(&buf[0]))
xfer.length = C.int(len(buf))
return (*libusbTransfer)(xfer), nil
ret := (*libusbTransfer)(xfer)
xferDoneMap.Lock()
xferDoneMap.m[ret] = done
xferDoneMap.Unlock()
return ret, nil
}

func (libusbImpl) cancel(t *libusbTransfer) error {
return fromUSBError(C.libusb_cancel_transfer((*C.struct_libusb_transfer)(t)))
}

func (libusbImpl) submit(t *libusbTransfer, done chan struct{}) error {
t.user_data = (unsafe.Pointer)(&done)
func (libusbImpl) submit(t *libusbTransfer) error {
return fromUSBError(C.submit((*C.struct_libusb_transfer)(t)))
}

Expand All @@ -356,10 +360,20 @@ func (libusbImpl) setIsoPacketLengths(t *libusbTransfer, length uint32) {
// libusb is an injection point for tests
var libusb libusbIntf = libusbImpl{}

//export xfer_callback
func xfer_callback(cptr unsafe.Pointer) {
ch := *(*chan struct{})(cptr)
close(ch)
// xferDoneMap keeps a map of done callback channels for all allocated transfers.
var xferDoneMap = struct {
m map[*libusbTransfer]chan struct{}
sync.RWMutex
}{
m: make(map[*libusbTransfer]chan struct{}),
}

//export xferCallback
func xferCallback(xfer *C.struct_libusb_transfer) {
xferDoneMap.RLock()
ch := xferDoneMap.m[(*libusbTransfer)(xfer)]
xferDoneMap.RUnlock()
ch <- struct{}{}
}

// for benchmarking
Expand Down
8 changes: 2 additions & 6 deletions usb/transfer.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,10 @@
#include <string.h>

void print_xfer(struct libusb_transfer *xfer);
void xfer_callback(void *);

void callback(struct libusb_transfer *xfer) {
xfer_callback(xfer->user_data);
}
void xferCallback(struct libusb_transfer *xfer);

int submit(struct libusb_transfer *xfer) {
xfer->callback = (libusb_transfer_cb_fn)(&callback);
xfer->callback = (libusb_transfer_cb_fn)(&xferCallback);
xfer->status = -1;
return libusb_submit_transfer(xfer);
}
Expand Down
7 changes: 4 additions & 3 deletions usb/transfer.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ func (t *usbTransfer) submit() error {
if t.submitted {
return errors.New("transfer was already submitted and is not finished yet.")
}
t.done = make(chan struct{})
if err := libusb.submit(t.xfer, t.done); err != nil {
if err := libusb.submit(t.xfer); err != nil {
return err
}
t.submitted = true
Expand Down Expand Up @@ -125,7 +124,8 @@ func newUSBTransfer(dev *libusbDevHandle, ei EndpointInfo, buf []byte, timeout t
debug.Printf("New isochronous transfer - buffer length %d, using %d packets of %d bytes each", len(buf), isoPackets, isoPktSize)
}

xfer, err := libusb.alloc(dev, ei.Address, tt, timeout, isoPackets, buf)
done := make(chan struct{}, 1)
xfer, err := libusb.alloc(dev, ei.Address, tt, timeout, isoPackets, buf, done)
if err != nil {
return nil, err
}
Expand All @@ -137,6 +137,7 @@ func newUSBTransfer(dev *libusbDevHandle, ei EndpointInfo, buf []byte, timeout t
t := &usbTransfer{
xfer: xfer,
buf: buf,
done: done,
}
runtime.SetFinalizer(t, func(t *usbTransfer) {
t.cancel()
Expand Down
6 changes: 3 additions & 3 deletions usb/transfer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,18 +96,18 @@ func TestTransferProtocol(t *testing.T) {
ft.length = 5
ft.status = LIBUSB_TRANSFER_COMPLETED
copy(ft.buf, []byte{1, 2, 3, 4, 5})
close(ft.done)
ft.done <- struct{}{}

ft = f.waitForSubmitted()
ft.length = 99
ft.status = LIBUSB_TRANSFER_COMPLETED
copy(ft.buf, []byte{12, 12, 12, 12, 12})
close(ft.done)
ft.done <- struct{}{}

ft = f.waitForSubmitted()
ft.length = 123
ft.status = LIBUSB_TRANSFER_CANCELLED
close(ft.done)
ft.done <- struct{}{}
}()

xfers[0].submit()
Expand Down