From e63fb62acfe52aecfd12b2a2f87f9a79495b2a0b Mon Sep 17 00:00:00 2001 From: Nathan Hjelm Date: Thu, 25 Apr 2013 21:09:19 -0600 Subject: [PATCH] core: release the context device list when the context is deleted. This commit fixes a memory leak in the context list patch. Devices need to be unref'd when the context is deleted. This can happen if either 1) the backend init fails, or 2) the context is destroyed by libusb_exit(). --- libusb/core.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/libusb/core.c b/libusb/core.c index d6f1971..ed8c326 100644 --- a/libusb/core.c +++ b/libusb/core.c @@ -1668,6 +1668,7 @@ void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level) */ int API_EXPORTED libusb_init(libusb_context **context) { + struct libusb_device *dev, *next; char *dbg = getenv("LIBUSB_DEBUG"); struct libusb_context *ctx; static int first_init = 1; @@ -1731,14 +1732,14 @@ int API_EXPORTED libusb_init(libusb_context **context) } usbi_mutex_static_unlock(&default_context_lock); - usbi_mutex_static_lock(&active_contexts_lock); - if (first_init) { - first_init = 0; - list_init (&active_contexts_list); - } + usbi_mutex_static_lock(&active_contexts_lock); + if (first_init) { + first_init = 0; + list_init (&active_contexts_list); + } - list_add (&ctx->list, &active_contexts_list); - usbi_mutex_static_unlock(&active_contexts_lock); + list_add (&ctx->list, &active_contexts_list); + usbi_mutex_static_unlock(&active_contexts_lock); return 0; @@ -1746,6 +1747,12 @@ int API_EXPORTED libusb_init(libusb_context **context) usbi_mutex_destroy(&ctx->open_devs_lock); usbi_mutex_destroy(&ctx->usb_devs_lock); err_free_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); free(ctx); err_unlock: usbi_mutex_static_unlock(&default_context_lock); @@ -1759,6 +1766,8 @@ int API_EXPORTED libusb_init(libusb_context **context) */ void API_EXPORTED libusb_exit(struct libusb_context *ctx) { + struct libusb_device *dev, *next; + usbi_dbg(""); USBI_GET_CONTEXT(ctx); @@ -1776,12 +1785,19 @@ void API_EXPORTED libusb_exit(struct libusb_context *ctx) usbi_mutex_static_unlock(&default_context_lock); } - usbi_mutex_static_lock(&active_contexts_lock); - list_del (&ctx->list); - usbi_mutex_static_unlock(&active_contexts_lock); + usbi_mutex_static_lock(&active_contexts_lock); + 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); + /* a little sanity check. doesn't bother with open_devs locking because * unless there is an application bug, nobody will be accessing this. */ if (!list_empty(&ctx->open_devs))