question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Review finalization of LibUSB (1.x) devices and context

See original GitHub issue

libusb_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:closed
  • Created 2 years ago
  • Comments:11 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
jonasmalacofilhocommented, Feb 9, 2022

Hah, I fell for exactly that myself!

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;
  • the _Device class can’t outlive the libusb1 module;
  • and the _LibUSB singleton instance lives as long as the libusb 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!

0reactions
benzeacommented, Feb 8, 2022

Nevermind, module is a string, obviously…

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?

Read more comments on GitHub >

github_iconTop 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 >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found