V
Vincent Pelletier
Hi.
(please keep me in CC for replies, I'm not subscribed)
I wrote a ctypes-(wait, read on)-based binding[1] for libusb1, in which I'm
triggering a segfault from an application[2] I wrote.
I've been through several segfault caused by ctypes mis-usage, this one seems
different enough. I think there is something else (maybe ultimately caused by
some ctypes effect, but I don't see the relation yet).
The Python line causing the segfault:
https://github.com/vpelletier/python-libusb1/blob/master/usb1.py#L192
C stack at segfault (with -dbg package installed):
http://pastebin.com/rVUPsSrU
#0
(gdb) print *op
$1 = {ob_refcnt = -4247522206314328575, ob_type = 0xcf0dc50ec50dc50e}
(gdb) up
#1
(gdb) print *obj
$2 = {ob_refcnt = 6, ob_type = 0x9c5f70}
(gdb) print obj
$3 = <USBTransfer at remote 0xb3a950>
The program using python-libusb1 which triggers the segfault:
https://github.com/vpelletier/ITI1480A-linux/blob/master/iti1480a/capture.py
The event loop is at the bottom: allocate USB transfers, submit them, loop on
libusb1 event handling until there is no more submitted transfer, libusb uses
callback which resubmits transfer, ...
ctypes possible segfault causes checklist:
- callback is cast into a ctype CFUNCTYPE type instance
See:
https://github.com/vpelletier/python-libusb1/blob/master/libusb1.py#L587
https://github.com/vpelletier/python-libusb1/blob/master/usb1.py#L133
- a strong ref to it is kept on USBTransfer instance so it is not GC'ed
See:
https://github.com/vpelletier/python-libusb1/blob/master/usb1.py#L808
- application is single-threaded (libusb1 doesn't create any C thread either)
so even if there were missing GIL acquisitions, it shouldn't be a problem
Also, a strong ref to USBTransfer is kept on USBDeviceHandle instance. When
an USBDeviceHandle is GC'ed, it cancels any pending transfer, waits for
completion (=libusb1 callback is executed) and then allow them to be GC'ed.
- we are not accessing unallocated memory in this traceback (although it could
be that memory got overwritten somehow)
I couldn't trigger the bug while under valgrind (which reported some
"Conditional jump or move depends on uninitialized value(s)" & "Use of
uninitialized value of size 8" in PyObject_Free, but reading the code I guess
they are harmless and unrelated).
Any idea of ways to debug this problem further ?
Regards,
(please keep me in CC for replies, I'm not subscribed)
I wrote a ctypes-(wait, read on)-based binding[1] for libusb1, in which I'm
triggering a segfault from an application[2] I wrote.
I've been through several segfault caused by ctypes mis-usage, this one seems
different enough. I think there is something else (maybe ultimately caused by
some ctypes effect, but I don't see the relation yet).
The Python line causing the segfault:
https://github.com/vpelletier/python-libusb1/blob/master/usb1.py#L192
C stack at segfault (with -dbg package installed):
http://pastebin.com/rVUPsSrU
#0
(gdb) print *op
$1 = {ob_refcnt = -4247522206314328575, ob_type = 0xcf0dc50ec50dc50e}
(gdb) up
#1
(gdb) print *obj
$2 = {ob_refcnt = 6, ob_type = 0x9c5f70}
(gdb) print obj
$3 = <USBTransfer at remote 0xb3a950>
The program using python-libusb1 which triggers the segfault:
https://github.com/vpelletier/ITI1480A-linux/blob/master/iti1480a/capture.py
The event loop is at the bottom: allocate USB transfers, submit them, loop on
libusb1 event handling until there is no more submitted transfer, libusb uses
callback which resubmits transfer, ...
ctypes possible segfault causes checklist:
- callback is cast into a ctype CFUNCTYPE type instance
See:
https://github.com/vpelletier/python-libusb1/blob/master/libusb1.py#L587
https://github.com/vpelletier/python-libusb1/blob/master/usb1.py#L133
- a strong ref to it is kept on USBTransfer instance so it is not GC'ed
See:
https://github.com/vpelletier/python-libusb1/blob/master/usb1.py#L808
- application is single-threaded (libusb1 doesn't create any C thread either)
so even if there were missing GIL acquisitions, it shouldn't be a problem
Also, a strong ref to USBTransfer is kept on USBDeviceHandle instance. When
an USBDeviceHandle is GC'ed, it cancels any pending transfer, waits for
completion (=libusb1 callback is executed) and then allow them to be GC'ed.
- we are not accessing unallocated memory in this traceback (although it could
be that memory got overwritten somehow)
I couldn't trigger the bug while under valgrind (which reported some
"Conditional jump or move depends on uninitialized value(s)" & "Use of
uninitialized value of size 8" in PyObject_Free, but reading the code I guess
they are harmless and unrelated).
Any idea of ways to debug this problem further ?
Regards,