Fixes to error handling and exit codepaths
authorPete Batard <pbatard@gmail.com>
Mon, 17 May 2010 22:16:54 +0000 (19:16 -0300)
committerDaniel Drake <dan@reactivated.net>
Mon, 17 May 2010 22:30:07 +0000 (19:30 -0300)
Various locks and things were being leaked/left open when handling
errors and during deinitialization.

[dsd: small tweaks]

libusb/core.c
libusb/io.c
libusb/os/threads_posix.h

index efae9aa..3ffeb19 100644 (file)
@@ -507,8 +507,10 @@ struct libusb_device *usbi_alloc_device(struct libusb_context *ctx,
                return NULL;
 
        r = usbi_mutex_init(&dev->lock, NULL);
-       if (r)
+       if (r) {
+               free(dev);
                return NULL;
+       }
 
        dev->ctx = ctx;
        dev->refcnt = 1;
@@ -869,8 +871,10 @@ API_EXPORTED int libusb_open(libusb_device *dev, libusb_device_handle **handle)
                return LIBUSB_ERROR_NO_MEM;
 
        r = usbi_mutex_init(&_handle->lock, NULL);
-       if (r)
+       if (r) {
+               free(_handle);
                return LIBUSB_ERROR_OTHER;
+       }
 
        _handle->dev = libusb_ref_device(dev);
        _handle->claimed_interfaces = 0;
@@ -879,6 +883,7 @@ API_EXPORTED int libusb_open(libusb_device *dev, libusb_device_handle **handle)
        r = usbi_backend->open(_handle);
        if (r < 0) {
                libusb_unref_device(dev);
+               usbi_mutex_destroy(&_handle->lock);
                free(_handle);
                return r;
        }
@@ -990,6 +995,7 @@ static void do_close(struct libusb_context *ctx,
 
        usbi_backend->close(dev_handle);
        libusb_unref_device(dev_handle->dev);
+       usbi_mutex_destroy(&dev_handle->lock);
        free(dev_handle);
 }
 
@@ -1501,6 +1507,8 @@ API_EXPORTED int libusb_init(libusb_context **context)
        return 0;
 
 err:
+       usbi_mutex_destroy(&ctx->open_devs_lock);
+       usbi_mutex_destroy(&ctx->usb_devs_lock);
        free(ctx);
        return r;
 }
@@ -1531,6 +1539,8 @@ API_EXPORTED void libusb_exit(struct libusb_context *ctx)
        }
        usbi_mutex_static_unlock(&default_context_lock);
 
+       usbi_mutex_destroy(&ctx->open_devs_lock);
+       usbi_mutex_destroy(&ctx->usb_devs_lock);
        free(ctx);
 }
 
index f627bcf..8505f1e 100644 (file)
@@ -1015,12 +1015,14 @@ int usbi_io_init(struct libusb_context *ctx)
 
        /* FIXME should use an eventfd on kernels that support it */
        r = pipe(ctx->ctrl_pipe);
-       if (r < 0)
-               return LIBUSB_ERROR_OTHER;
+       if (r < 0) {
+               r = LIBUSB_ERROR_OTHER;
+               goto err;
+       }
 
        r = usbi_add_pollfd(ctx, ctx->ctrl_pipe[0], POLLIN);
        if (r < 0)
-               return r;
+               goto err_close_pipe;
 
 #ifdef USBI_TIMERFD_AVAILABLE
        ctx->timerfd = timerfd_create(usbi_backend->get_timerfd_clockid(),
@@ -1030,7 +1032,7 @@ int usbi_io_init(struct libusb_context *ctx)
                r = usbi_add_pollfd(ctx, ctx->timerfd, POLLIN);
                if (r < 0) {
                        close(ctx->timerfd);
-                       return r;
+                       goto err_close_pipe;
                }
        } else {
                usbi_dbg("timerfd not available (code %d error %d)", ctx->timerfd, errno);
@@ -1039,6 +1041,18 @@ int usbi_io_init(struct libusb_context *ctx)
 #endif
 
        return 0;
+
+err_close_pipe:
+       close(ctx->ctrl_pipe[0]);
+       close(ctx->ctrl_pipe[1]);
+err:
+       usbi_mutex_destroy(&ctx->flying_transfers_lock);
+       usbi_mutex_destroy(&ctx->pollfds_lock);
+       usbi_mutex_destroy(&ctx->pollfd_modify_lock);
+       usbi_mutex_destroy(&ctx->events_lock);
+       usbi_mutex_destroy(&ctx->event_waiters_lock);
+       usbi_cond_destroy(&ctx->event_waiters_cond);
+       return r;
 }
 
 void usbi_io_exit(struct libusb_context *ctx)
@@ -1052,6 +1066,12 @@ void usbi_io_exit(struct libusb_context *ctx)
                close(ctx->timerfd);
        }
 #endif
+       usbi_mutex_destroy(&ctx->flying_transfers_lock);
+       usbi_mutex_destroy(&ctx->pollfds_lock);
+       usbi_mutex_destroy(&ctx->pollfd_modify_lock);
+       usbi_mutex_destroy(&ctx->events_lock);
+       usbi_mutex_destroy(&ctx->event_waiters_lock);
+       usbi_cond_destroy(&ctx->event_waiters_cond);
 }
 
 static int calculate_timeout(struct usbi_transfer *transfer)
@@ -1787,8 +1807,10 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
 
        /* TODO: malloc when number of fd's changes, not on every poll */
        fds = malloc(sizeof(*fds) * nfds);
-       if (!fds)
+       if (!fds) {
+               usbi_mutex_unlock(&ctx->pollfds_lock);
                return LIBUSB_ERROR_NO_MEM;
+       }
 
        list_for_each_entry(ipollfd, &ctx->pollfds, list) {
                struct libusb_pollfd *pollfd = &ipollfd->pollfd;
index 6efef66..728c101 100644 (file)
@@ -40,5 +40,6 @@
 #define usbi_cond_wait                 pthread_cond_wait
 #define usbi_cond_timedwait            pthread_cond_timedwait
 #define usbi_cond_broadcast            pthread_cond_broadcast
+#define usbi_cond_destroy              pthread_cond_destroy
 
 #endif /* __LIBUSB_THREADS_POSIX_H__ */