core: Only do hotplug cleanup for hotplug capable backends
authorHans de Goede <hdegoede@redhat.com>
Wed, 26 Jun 2013 14:50:56 +0000 (16:50 +0200)
committerHans de Goede <hdegoede@redhat.com>
Wed, 26 Jun 2013 15:11:27 +0000 (17:11 +0200)
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>
libusb/core.c
libusb/version_nano.h

index 1a30290..4e01adb 100644 (file)
@@ -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. */
index 48c7a87..13ef98f 100644 (file)
@@ -1 +1 @@
-#define LIBUSB_NANO 10758
+#define LIBUSB_NANO 10759