summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Hjelm <hjelmn@google.com>2021-06-10 20:51:44 -0600
committerNathan Hjelm <hjelmn@google.com>2021-06-10 20:56:24 -0600
commita0e773812b8aa07ad57fc092a7a4f406366f5272 (patch)
tree832f6f2b1f7776fb2233b993a0b3f68be394b79e
parenta524555c987fec2c16417d2f58c8713efcbe11a9 (diff)
downloadlibusb-a0e773812b8aa07ad57fc092a7a4f406366f5272.tar.gz
core: ensure that all devices are properly cleaned up on libusb_exit
When cleaning up the context on libusb_exit the last step is to to call hotplug_exit. This function took one pass over the devices and released any devices where the reference count had reached 0. All remaining devices were assumed to have leaked references and a warning message was printed out. Unfortunately, this cleanup was too simplistic. It ignored the references created when a device was the parent of another device (which takes a reference). This reference is released when the child device is released. To ensure that we do not erroneously warn about devices with leftover references the code now loops over the device list until no more devices have a single reference. This ensures that we will eventually remove all devices with no external references. Fixes #924 Signed-off-by: Nathan Hjelm <hjelmn@google.com>
-rw-r--r--libusb/hotplug.c23
-rw-r--r--libusb/version_nano.h2
2 files changed, 15 insertions, 10 deletions
diff --git a/libusb/hotplug.c b/libusb/hotplug.c
index 387b49f..deb138d 100644
--- a/libusb/hotplug.c
+++ b/libusb/hotplug.c
@@ -166,6 +166,7 @@ void usbi_hotplug_exit(struct libusb_context *ctx)
struct usbi_hotplug_callback *hotplug_cb, *next_cb;
struct usbi_hotplug_message *msg;
struct libusb_device *dev, *next_dev;
+ int devices_released;
/* check for hotplug support */
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))
@@ -190,15 +191,19 @@ void usbi_hotplug_exit(struct libusb_context *ctx)
free(msg);
}
- /* free all discovered devices */
- for_each_device_safe(ctx, dev, next_dev) {
- /* remove the device from the usb_devs list only if there are no
- * references held, otherwise leave it on the list so that a
- * warning message will be shown */
- if (usbi_atomic_load(&dev->refcnt) == 1)
- list_del(&dev->list);
- libusb_unref_device(dev);
- }
+ /* free all discovered devices. due to parent references loop until no devices are freed. */
+ do {
+ devices_released = 0;
+ for_each_device_safe(ctx, dev, next_dev) {
+ /* remove the device from the usb_devs list only if there are no
+ * references held, otherwise leave it on the list so that a
+ * warning message will be shown */
+ if (usbi_atomic_load(&dev->refcnt) == 1)
+ list_del(&dev->list);
+ libusb_unref_device(dev);
+ ++devices_released;
+ }
+ } while (devices_released > 0);
usbi_mutex_destroy(&ctx->hotplug_cbs_lock);
}
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index 9a19b34..21591b9 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 11623
+#define LIBUSB_NANO 11624