Review finalization of LibUSB (1.x) devices and context
See original GitHub issuelibusb_unref_device()
is not supposed to be called after the context (for that device) has been destroyed with libsub_exit()
.
However, with
# file: repro.py
import usb
devices = list(usb.core.find(find_all=True))
print(f"Found {len(devices)} USB devices")
del(devices)
and current PyUSB HEAD:
$ LIBUSB_DEBUG=4 vmaster/bin/python repro.py
[timestamp] [threadID] facility level [function call] <message>
--------------------------------------------------------------------------------
[ 0.000008] [0000554e] libusb: debug [libusb_init] libusb v1.0.25.11692
[ 0.000015] [0000554e] libusb: debug [usbi_add_event_source] add fd 3 events 1
[ 0.000017] [0000554e] libusb: debug [usbi_io_init] using timer for timeouts
[ 0.000018] [0000554e] libusb: debug [usbi_add_event_source] add fd 4 events 1
[ 0.000021] [0000554e] libusb: debug [get_kernel_version] reported kernel version is 5.16.5-arch1-1
[ 0.000028] [0000554e] libusb: debug [op_init] found usbfs at /dev/bus/usb
[ 0.000029] [0000554e] libusb: debug [op_init] max iso packet length is (likely) 98304 bytes
[ 0.000032] [0000554e] libusb: debug [op_init] sysfs is available
[ 0.000229] [00005551] libusb: debug [linux_udev_event_thread_main] udev event thread entering
[ 0.002767] [0000554e] libusb: debug [linux_get_device_address] getting address for device: usb1 detached: 0
[ 0.002771] [0000554e] libusb: debug [linux_get_device_address] scan usb1
[ 0.002782] [0000554e] libusb: debug [linux_get_device_address] bus=1 dev=1
[ 0.002783] [0000554e] libusb: debug [linux_enumerate_device] busnum 1 devaddr 1 session_id 257
[ 0.002785] [0000554e] libusb: debug [linux_enumerate_device] allocating new device for 1/1 (session 257)
[... corresponding calls to 12 other devices ...]
[ 0.003536] [0000554e] libusb: debug [linux_get_device_address] getting address for device: usb4 detached: 0
[ 0.003537] [0000554e] libusb: debug [linux_get_device_address] scan usb4
[ 0.003547] [0000554e] libusb: debug [linux_get_device_address] bus=4 dev=1
[ 0.003549] [0000554e] libusb: debug [linux_enumerate_device] busnum 4 devaddr 1 session_id 1025
[ 0.003550] [0000554e] libusb: debug [linux_enumerate_device] allocating new device for 4/1 (session 1025)
[ 0.003624] [0000554e] libusb: debug [libusb_get_device_list]
[ 0.003649] [0000554e] libusb: debug [libusb_get_device_descriptor]
[... 12 other calls to libusb_get_device_descriptor ...]
[ 0.003939] [0000554e] libusb: debug [libusb_get_device_descriptor]
Found 14 USB devices
[ 0.004073] [0000554e] libusb: debug [libusb_exit]
[ 0.004104] [00005551] libusb: debug [linux_udev_event_thread_main] udev event thread exiting
[ 0.004127] [0000554e] libusb: debug [libusb_unref_device] destroy device 4.1
[... 12 other calls to libusb_unref_device ...]
[ 0.004144] [0000554e] libusb: debug [libusb_unref_device] destroy device 1.1
[ 0.004146] [0000554e] libusb: debug [usbi_remove_event_source] remove fd 4
[ 0.004149] [0000554e] libusb: debug [usbi_remove_event_source] remove fd 3
Related: libusb/libusb#1058
Issue Analytics
- State:
- Created 2 years ago
- Comments:11 (5 by maintainers)
Top Results From Across the Web
Device Leak Issue under Windows #77 - GitHub
When using python-libusb1 under Windows, there are libusb warning messages ... and finally, context gets finalized, which emits the warning.
Read more >Diff - platform/external/libusb - android Git repositories
Previously NULL would be passed for the default context, + but since the first context created is the default context, and most apps...
Read more >Contexts - libusb
The deinitialization and freeing of the default context will only happen when the last user calls libusb_exit(). In other words, the default context...
Read more >Fail to set usb configuration or reset device for ... - Issue Tracker
When trying to set configuration for ftdi-based usb device i'm getting error -32 (EPIPE). The same error for different Android OS (4.0.x, 4.1)...
Read more >libusb-devel Mailing List for libusb - SourceForge
A cross-platform library that gives apps easy access to USB devices ... options for the "default context", then creating the context with libusb_init()....
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Good to know I’m not the only one : )
I think what allows the code to work currently (under both CPython and PyPy, as I’ve just confirmed) is:
_Device
instances can’t outlive the_Device
class;_Device
class can’t outlive thelibusb1
module;_LibUSB
singleton instance lives as long as thelibusb
module.I also think that if
_Device._finalize_object
gets to run (finalizers aren’t guaranteed to run, especially in some cases when the interpreter is exiting), then that counts to the_Device
class still being there, and thus the_LibUSB
instance as well.So I’m going to close this as it seems everything is working properly, both practically and in theory.
Thanks for all the help!
Hah, I fell for exactly that myself!
I fear I am a bit out of knowledge about python garbage collection and object destruction at this point 😕
My naive approach would be to create a chain like
Device -> _ResourceManager -> _Device -> _LibUSB
, and then hopefully python cannot release the objects in the wrong order. So, maybe it is enough to attach a reference to_LibUSB
to the_Device
instance?