Skip to content

Instantly share code, notes, and snippets.

@brendanbates89
Created October 24, 2017 13:00
Show Gist options
  • Save brendanbates89/2a9d748607bf02cc819a1a11f4c8917c to your computer and use it in GitHub Desktop.
Save brendanbates89/2a9d748607bf02cc819a1a11f4c8917c to your computer and use it in GitHub Desktop.
From 0036429f2f7fd1dff7a9b80d52e58f2f791e6b2b Mon Sep 17 00:00:00 2001
From: Brendan Bates <-------------->
Date: Mon, 8 May 2017 15:19:30 -0400
Subject: [PATCH] DTECTIT-41 - Fix issue stemming from the improper cleanup of uncancelled file descriptors in Win32.
---
libusb/io.c | 38 ++++++++++++++++++++++++++++++++++++--
libusb/os/windows_nt_common.c | 10 +++++++---
msvc/libusb_dll_2015.vcxproj | 4 ++--
3 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/libusb/io.c b/libusb/io.c
index bf2b5fa..f01c8d5 100644
--- a/libusb/io.c
+++ b/libusb/io.c
@@ -1978,7 +1978,7 @@ int API_EXPORTED libusb_wait_for_event(libusb_context *ctx, struct timeval *tv)
return (r == ETIMEDOUT);
}
-static void handle_timeout(struct usbi_transfer *itransfer)
+static int handle_timeout(struct usbi_transfer *itransfer)
{
struct libusb_transfer *transfer =
USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
@@ -1991,6 +1991,8 @@ static void handle_timeout(struct usbi_transfer *itransfer)
else
usbi_warn(TRANSFER_CTX(transfer),
"async cancel failed %d errno=%d", r, errno);
+
+ return r;
}
static int handle_timeouts_locked(struct libusb_context *ctx)
@@ -2010,6 +2012,9 @@ static int handle_timeouts_locked(struct libusb_context *ctx)
TIMESPEC_TO_TIMEVAL(&systime, &systime_ts);
+ int remove_size = 0;
+ struct usbi_transfer **remove_list = 0;
+
/* iterate through flying transfers list, finding all transfers that
* have expired timeouts */
list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
@@ -2030,8 +2035,37 @@ static int handle_timeouts_locked(struct libusb_context *ctx)
return 0;
/* otherwise, we've got an expired timeout to handle */
- handle_timeout(transfer);
+ int result = handle_timeout(transfer);
+
+ // Edge Case
+ //
+ // If the transfer returned "no device", add this transfer to list of transfers that
+ // are unable to be cancelled.
+ if (result == LIBUSB_ERROR_NO_DEVICE) {
+ // Increment size of the remove list.
+ remove_size++;
+
+ // Reallocate memory.
+ if (!remove_list) {
+ remove_list = malloc(sizeof(struct usbi_transfer *));
+ } else {
+ remove_list = realloc(remove_list, sizeof(struct usbi_transfer *) * remove_size);
+ }
+
+ // Add to the list.
+ remove_list[remove_size - 1] = transfer;
+ }
}
+
+ // Iterate through transfers unable to be cancelled and complete them with an error.
+ if (remove_size) {
+ for (int i = 0; i < remove_size; ++i) {
+ usbi_handle_transfer_completion(remove_list[i], LIBUSB_TRANSFER_STALL);
+ }
+
+ free(remove_list);
+ }
+
return 0;
}
diff --git a/libusb/os/windows_nt_common.c b/libusb/os/windows_nt_common.c
index 68eb4a7..da9a8e6 100644
--- a/libusb/os/windows_nt_common.c
+++ b/libusb/os/windows_nt_common.c
@@ -577,9 +577,13 @@ int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_N
// newly allocated wfd that took the place of the one from the transfer.
windows_handle_callback(transfer, io_result, io_size);
} else {
- usbi_err(ctx, "could not find a matching transfer for fd %d", fds[i]);
- r = LIBUSB_ERROR_NOT_FOUND;
- break;
+ // Remove the offending FD.
+ usbi_remove_pollfd(ctx, fds[i].fd);
+
+ // Free the memory used by the FD.
+ struct winfd removing_fd;
+ removing_fd.fd = fds[i].fd;
+ usbi_free_fd(&removing_fd);
}
}
usbi_mutex_unlock(&ctx->open_devs_lock);
--
libgit2 0.26.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment