summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2013-06-26 16:50:56 +0200
committerHans de Goede <hdegoede@redhat.com>2013-06-26 17:11:27 +0200
commit163e2083e290eb878f4e38b17daf5998a7a29c47 (patch)
treec3c7adb4255aa780e7e80771061ce9311f240d6b
parentc1bf7fbab0ed2b5606ff0d50cde2896d0ac2f4ff (diff)
downloadlibusb-163e2083e290eb878f4e38b17daf5998a7a29c47.tar.gz
core: Only do hotplug cleanup for hotplug capable backends
Xiaofan encountered a crash while testing on openbsd. The main problem here is libusb_exit doing hotplug cleanup on a non hotplug capable backend. If the usb_devs list is non empty (*) at libusb_exit time with a non hotplug capable backend, then the hotplug cleanup code will unref the devices in the list. Assuming this is the last unref, then libusb_unref_device will call usbi_disconnect_device, which will try to take the usb_devs_lock, which is already hold by libusb_exit. Note that if this deadlock was not there, that we then also would have a double list_del issue. *) This should never happen, if it does either libusb or the app has a memleak, or the app still holds a reference to the device. The latter is an application bug, since device->ctx will be invalid after libusb_exit, so the application should not hold references after calling libusb_exit. In this case we have a memleak the libusb openbsd code causing the usb_devs list to be non empty. This will be fixed in another commit. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r--libusb/core.c18
-rw-r--r--libusb/version_nano.h2
2 files changed, 11 insertions, 9 deletions
diff --git a/libusb/core.c b/libusb/core.c
index 1a30290..4e01adb 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -1912,14 +1912,16 @@ void API_EXPORTED libusb_exit(struct libusb_context *ctx)
list_del (&ctx->list);
usbi_mutex_static_unlock(&active_contexts_lock);
- usbi_hotplug_deregister_all(ctx);
-
- usbi_mutex_lock(&ctx->usb_devs_lock);
- list_for_each_entry_safe(dev, next, &ctx->usb_devs, list, struct libusb_device) {
- list_del(&dev->list);
- libusb_unref_device(dev);
- }
- usbi_mutex_unlock(&ctx->usb_devs_lock);
+ if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
+ usbi_hotplug_deregister_all(ctx);
+ usbi_mutex_lock(&ctx->usb_devs_lock);
+ list_for_each_entry_safe(dev, next, &ctx->usb_devs, list, struct libusb_device) {
+ list_del(&dev->list);
+ libusb_unref_device(dev);
+ }
+ usbi_mutex_unlock(&ctx->usb_devs_lock);
+ } else if (!list_empty(&ctx->usb_devs))
+ usbi_warn(ctx, "some libusb_devices were leaked");
/* a little sanity check. doesn't bother with open_devs locking because
* unless there is an application bug, nobody will be accessing this. */
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index 48c7a87..13ef98f 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 10758
+#define LIBUSB_NANO 10759