diff options
author | Hans de Goede <hdegoede@redhat.com> | 2013-06-26 16:50:56 +0200 |
---|---|---|
committer | Hans de Goede <hdegoede@redhat.com> | 2013-06-26 17:11:27 +0200 |
commit | 163e2083e290eb878f4e38b17daf5998a7a29c47 (patch) | |
tree | c3c7adb4255aa780e7e80771061ce9311f240d6b | |
parent | c1bf7fbab0ed2b5606ff0d50cde2896d0ac2f4ff (diff) | |
download | libusb-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.c | 18 | ||||
-rw-r--r-- | libusb/version_nano.h | 2 |
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 |