From 0a8063ff0d64d4abd8ef39e212f34c7506d62c82 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Wed, 25 Sep 2024 21:13:09 +0200 Subject: [PATCH] Add a bunch of sanity checks --- libusb/hid.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++-- linux/hid.c | 64 +++++++++++++++++++++++++++++++++++-- mac/hid.c | 47 +++++++++++++++++++++++++++- windows/hid.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 274 insertions(+), 10 deletions(-) diff --git a/libusb/hid.c b/libusb/hid.c index a48ea9bfa..8d0d543fb 100644 --- a/libusb/hid.c +++ b/libusb/hid.c @@ -139,6 +139,9 @@ static int return_data(hid_device *dev, unsigned char *data, size_t length); static hid_device *new_hid_device(void) { hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device)); + if (!dev) + return NULL; + dev->blocking = 1; hidapi_thread_state_init(&dev->thread_state); @@ -148,6 +151,9 @@ static hid_device *new_hid_device(void) static void free_hid_device(hid_device *dev) { + if (!dev) + return; + /* Clean up the thread objects */ hidapi_thread_state_destroy(&dev->thread_state); @@ -169,6 +175,9 @@ static void register_error(hid_device *dev, const char *op) Only call with a num_bytes of 0, 1, 2, or 4. */ static uint32_t get_bytes(uint8_t *rpt, size_t len, size_t num_bytes, size_t cur) { + if (!rpt) + return 0; + /* Return if there aren't enough bytes. */ if (cur + num_bytes >= len) return 0; @@ -198,6 +207,9 @@ static uint32_t get_bytes(uint8_t *rpt, size_t len, size_t num_bytes, size_t cur static int get_usage(uint8_t *report_descriptor, size_t size, unsigned short *usage_page, unsigned short *usage) { + if (!report_descriptor || !usage_page || !usage) + return -1; + unsigned int i = 0; int size_code; int data_len, key_size; @@ -546,8 +558,10 @@ static void fill_device_info_usage(struct hid_device_info *cur_dev, libusb_devic get_usage(hid_report_descriptor, res, &page, &usage); } - cur_dev->usage_page = page; - cur_dev->usage = usage; + if (cur_dev) { + cur_dev->usage_page = page; + cur_dev->usage = usage; + } } #ifdef INVASIVE_GET_USAGE @@ -632,6 +646,9 @@ static struct hid_device_info * create_device_info_for_device(libusb_device *dev static uint16_t get_report_descriptor_size_from_interface_descriptors(const struct libusb_interface_descriptor *intf_desc) { + if (!intf_desc) + return 0; + int i = 0; int found_hid_report_descriptor = 0; uint16_t result = HID_API_MAX_REPORT_DESCRIPTOR_SIZE; @@ -685,6 +702,9 @@ static uint16_t get_report_descriptor_size_from_interface_descriptors(const stru static int is_xbox360(unsigned short vendor_id, const struct libusb_interface_descriptor *intf_desc) { + if (!intf_desc) + return 0; + static const int xb360_iface_subclass = 93; static const int xb360_iface_protocol = 1; /* Wired */ static const int xb360w_iface_protocol = 129; /* Wireless */ @@ -733,6 +753,9 @@ static int is_xbox360(unsigned short vendor_id, const struct libusb_interface_de static int is_xboxone(unsigned short vendor_id, const struct libusb_interface_descriptor *intf_desc) { + if (!intf_desc) + return 0; + static const int xb1_iface_subclass = 71; static const int xb1_iface_protocol = 208; static const int supported_vendors[] = { @@ -769,6 +792,8 @@ static int should_enumerate_interface(unsigned short vendor_id, const struct lib #if 0 printf("Checking interface 0x%x %d/%d/%d/%d\n", vendor_id, intf_desc->bInterfaceNumber, intf_desc->bInterfaceClass, intf_desc->bInterfaceSubClass, intf_desc->bInterfaceProtocol); #endif + if (!intf_desc) + return 0; if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) return 1; @@ -950,6 +975,9 @@ hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const static void LIBUSB_CALL read_callback(struct libusb_transfer *transfer) { + if (!transfer) + return; + hid_device *dev = transfer->user_data; int res; @@ -1018,6 +1046,9 @@ static void LIBUSB_CALL read_callback(struct libusb_transfer *transfer) static void *read_thread(void *param) { + if (!param) + return NULL; + int res; hid_device *dev = param; uint8_t *buf; @@ -1118,6 +1149,9 @@ static void init_xboxone(libusb_device_handle *device_handle, unsigned short idV (void)idProduct; + if (!conf_desc) + return; + for (j = 0; j < conf_desc->bNumInterfaces; j++) { const struct libusb_interface *intf = &conf_desc->interface[j]; for (k = 0; k < intf->num_altsetting; k++) { @@ -1158,6 +1192,9 @@ static void init_xboxone(libusb_device_handle *device_handle, unsigned short idV static int hidapi_initialize_device(hid_device *dev, const struct libusb_interface_descriptor *intf_desc, const struct libusb_config_descriptor *conf_desc) { + if (!conf_desc) + return 0; + int i =0; int res = 0; struct libusb_device_descriptor desc; @@ -1405,6 +1442,9 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_libusb_wrap_sys_device(intptr_t sys int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length) { + if (!dev) + return -1; + int res; int report_number; int skipped_report_id = 0; @@ -1447,6 +1487,9 @@ int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t This should be called with dev->mutex locked. */ static int return_data(hid_device *dev, unsigned char *data, size_t length) { + if (!dev || !data) + return 0; + /* Copy the data out of the linked list item (rpt) into the return buffer (data), and delete the liked list item. */ struct input_report *rpt = dev->input_reports; @@ -1461,6 +1504,9 @@ static int return_data(hid_device *dev, unsigned char *data, size_t length) static void cleanup_mutex(void *param) { + if (!param) + return; + hid_device *dev = param; hidapi_thread_mutex_unlock(&dev->thread_state); } @@ -1468,6 +1514,9 @@ static void cleanup_mutex(void *param) int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) { + if (!dev) + return -1; + #if 0 int transferred; int res = libusb_interrupt_transfer(dev->device_handle, dev->input_endpoint, data, length, &transferred, 5000); @@ -1556,6 +1605,9 @@ int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length) int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock) { + if (!dev) + return -1; + dev->blocking = !nonblock; return 0; @@ -1564,6 +1616,9 @@ int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock) int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) { + if (!dev || !data) + return -1; + int res = -1; int skipped_report_id = 0; int report_number = data[0]; @@ -1594,6 +1649,9 @@ int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) { + if (!dev || !data) + return -1; + int res = -1; int skipped_report_id = 0; int report_number = data[0]; @@ -1624,6 +1682,9 @@ int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, int HID_API_EXPORT hid_send_output_report(hid_device *dev, const unsigned char *data, size_t length) { + if (!dev || !data) + return -1; + int res = -1; int skipped_report_id = 0; int report_number = data[0]; @@ -1654,6 +1715,9 @@ int HID_API_EXPORT hid_send_output_report(hid_device *dev, const unsigned char * int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length) { + if (!dev || !data) + return -1; + int res = -1; int skipped_report_id = 0; int report_number = data[0]; @@ -1727,20 +1791,32 @@ void HID_API_EXPORT hid_close(hid_device *dev) int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) { + if (!dev) + return -1; + return hid_get_indexed_string(dev, dev->manufacturer_index, string, maxlen); } int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) { + if (!dev) + return -1; + return hid_get_indexed_string(dev, dev->product_index, string, maxlen); } int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) { + if (!dev) + return -1; + return hid_get_indexed_string(dev, dev->serial_index, string, maxlen); } HID_API_EXPORT struct hid_device_info *HID_API_CALL hid_get_device_info(hid_device *dev) { + if (!dev) + return NULL; + if (!dev->device_info) { struct libusb_device_descriptor desc; libusb_device *usb_device = libusb_get_device(dev->device_handle); @@ -1759,6 +1835,9 @@ HID_API_EXPORT struct hid_device_info *HID_API_CALL hid_get_device_info(hid_devi int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) { + if (!dev || !string) + return -1; + wchar_t *str; str = get_usb_string(dev->device_handle, string_index); @@ -1775,6 +1854,9 @@ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size) { + if (!dev) + return -1; + return hid_get_report_descriptor_libusb(dev->device_handle, dev->interface, dev->report_descriptor_size, buf, buf_size); } diff --git a/linux/hid.c b/linux/hid.c index 228fdeeca..b773a89ba 100644 --- a/linux/hid.c +++ b/linux/hid.c @@ -171,12 +171,18 @@ static void register_global_error_format(const char *format, ...) * Use register_device_error(dev, NULL) to indicate "no error". */ static void register_device_error(hid_device *dev, const char *msg) { + if (!dev) + return; + register_error_str(&dev->last_error_str, msg); } /* Similar to register_device_error, but you can pass a format string into this function. */ static void register_device_error_format(hid_device *dev, const char *format, ...) { + if (!dev) + return; + va_list args; va_start(args, format); register_error_str_vformat(&dev->last_error_str, format, args); @@ -197,6 +203,9 @@ static wchar_t *copy_udev_string(struct udev_device *dev, const char *udev_name) */ static int get_hid_item_size(const __u8 *report_descriptor, __u32 size, unsigned int pos, int *data_len, int *key_size) { + if (!report_descriptor || !data_len || !key_size) + return 0; + int key = report_descriptor[pos]; int size_code; @@ -253,6 +262,9 @@ static int get_hid_item_size(const __u8 *report_descriptor, __u32 size, unsigned */ static __u32 get_hid_report_bytes(const __u8 *rpt, size_t len, size_t num_bytes, size_t cur) { + if (!rpt) + return 0; + /* Return if there aren't enough bytes. */ if (cur + num_bytes >= len) return 0; @@ -347,6 +359,9 @@ struct hid_usage_iterator { */ static int get_next_hid_usage(const __u8 *report_descriptor, __u32 size, struct hid_usage_iterator *ctx, unsigned short *usage_page, unsigned short *usage) { + if (!report_descriptor || !ctx || !usage || !usage_page) + return -1; + int data_len, key_size; int initial = ctx->pos == 0; /* Used to handle case where no top-level application collection is defined */ @@ -370,6 +385,7 @@ static int get_next_hid_usage(const __u8 *report_descriptor, __u32 size, struct if (data_len == 4) { /* Usages 5.5 / Usage Page 6.2.2.7 */ ctx->usage_page = get_hid_report_bytes(report_descriptor, size, 2, ctx->pos + 2); ctx->usage_page_found = 1; + *usage = get_hid_report_bytes(report_descriptor, size, 2, ctx->pos); usage_found = 1; } @@ -400,8 +416,8 @@ static int get_next_hid_usage(const __u8 *report_descriptor, __u32 size, struct /* If no top-level application collection is found and usage page/usage pair is found, pair is valid https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/top-level-collections */ if (initial && usage_found && ctx->usage_page_found) { - *usage_page = ctx->usage_page; - return 0; /* success */ + *usage_page = ctx->usage_page; + return 0; /* success */ } return 1; /* finished processing */ @@ -413,6 +429,9 @@ static int get_next_hid_usage(const __u8 *report_descriptor, __u32 size, struct */ static int get_hid_report_descriptor(const char *rpt_path, struct hidraw_report_descriptor *rpt_desc) { + if (!rpt_path || !rpt_desc) + return -1; + int rpt_handle; ssize_t res; @@ -443,6 +462,10 @@ static int get_hid_report_descriptor(const char *rpt_path, struct hidraw_report_ static int get_hid_report_descriptor_from_sysfs(const char *sysfs_path, struct hidraw_report_descriptor *rpt_desc) { int res = -1; + + if (!sysfs_path) + return res; + /* Construct /device/report_descriptor */ size_t rpt_path_len = strlen(sysfs_path) + 25 + 1; char* rpt_path = (char*) calloc(1, rpt_path_len); @@ -457,6 +480,9 @@ static int get_hid_report_descriptor_from_sysfs(const char *sysfs_path, struct h /* return non-zero if successfully parsed */ static int parse_hid_vid_pid_from_uevent(const char *uevent, unsigned *bus_type, unsigned short *vendor_id, unsigned short *product_id) { + if (!uevent) + return 0; + char tmp[1024]; size_t uevent_len = strlen(uevent); if (uevent_len > sizeof(tmp) - 1) @@ -528,6 +554,10 @@ static int parse_hid_vid_pid_from_uevent_path(const char *uevent_path, unsigned static int parse_hid_vid_pid_from_sysfs(const char *sysfs_path, unsigned *bus_type, unsigned short *vendor_id, unsigned short *product_id) { int res = 0; + + if (!sysfs_path) + return res; + /* Construct /device/uevent */ size_t uevent_path_len = strlen(sysfs_path) + 14 + 1; char* uevent_path = (char*) calloc(1, uevent_path_len); @@ -541,6 +571,9 @@ static int parse_hid_vid_pid_from_sysfs(const char *sysfs_path, unsigned *bus_ty static int get_hid_report_descriptor_from_hidraw(hid_device *dev, struct hidraw_report_descriptor *rpt_desc) { + if (!dev) + return -1; + int desc_size = 0; /* Get Report Descriptor Size */ @@ -834,6 +867,9 @@ static struct hid_device_info * create_device_info_for_device(struct udev_device } static struct hid_device_info * create_device_info_for_hid_device(hid_device *dev) { + if (!dev) + return NULL; + struct udev *udev; struct udev_device *udev_dev; struct stat s; @@ -1089,6 +1125,9 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path) int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length) { + if (!dev) + return -1; + int bytes_written; if (!data || (length == 0)) { @@ -1107,6 +1146,9 @@ int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) { + if (!dev) + return -1; + /* Set device error to none */ register_device_error(dev, NULL); @@ -1164,6 +1206,9 @@ int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length) int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock) { + if (!dev) + return -1; + /* Do all non-blocking in userspace using poll(), since it looks like there's a bug in the kernel in some versions where read() will not return -1 on disconnection of the USB device */ @@ -1175,6 +1220,9 @@ int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock) int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) { + if (!dev) + return -1; + int res; register_device_error(dev, NULL); @@ -1188,6 +1236,9 @@ int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) { + if (!dev) + return -1; + int res; register_device_error(dev, NULL); @@ -1214,6 +1265,9 @@ int HID_API_EXPORT HID_API_CALL hid_send_output_report(hid_device *dev, const un int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length) { + if (!dev) + return -1; + int res; register_device_error(dev, NULL); @@ -1315,6 +1369,9 @@ int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *s HID_API_EXPORT struct hid_device_info *HID_API_CALL hid_get_device_info(hid_device *dev) { + if (!dev) + return NULL; + if (!dev->device_info) { // Lazy initialize device_info dev->device_info = create_device_info_for_hid_device(dev); @@ -1326,6 +1383,9 @@ HID_API_EXPORT struct hid_device_info *HID_API_CALL hid_get_device_info(hid_devi int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) { + if (!dev) + return -1; + (void)string_index; (void)string; (void)maxlen; diff --git a/mac/hid.c b/mac/hid.c index e2b365c4f..6e53f999a 100644 --- a/mac/hid.c +++ b/mac/hid.c @@ -276,12 +276,18 @@ static void register_global_error_format(const char *format, ...) * Use register_device_error(dev, NULL) to indicate "no error". */ static void register_device_error(hid_device *dev, const char *msg) { + if (!dev) + return; + register_error_str(&dev->last_error_str, msg); } /* Similar to register_device_error, but you can pass a format string into this function. */ static void register_device_error_format(hid_device *dev, const char *format, ...) { + if (!dev) + return; + va_list args; va_start(args, format); register_error_str_vformat(&dev->last_error_str, format, args); @@ -868,6 +874,9 @@ static void hid_report_callback(void *context, IOReturn result, void *sender, IOHIDReportType report_type, uint32_t report_id, uint8_t *report, CFIndex report_length) { + if (!context) + return; + (void) result; (void) sender; (void) report_type; @@ -921,12 +930,18 @@ static void hid_report_callback(void *context, IOReturn result, void *sender, hid_close(), and serves to stop the read_thread's run loop. */ static void perform_signal_callback(void *context) { + if (!context) + return; + hid_device *dev = (hid_device*) context; CFRunLoopStop(dev->run_loop); /*TODO: CFRunLoopGetCurrent()*/ } static void *read_thread(void *param) { + if (!param) + return NULL; + hid_device *dev = (hid_device*) param; SInt32 code; @@ -1096,6 +1111,9 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path) static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char *data, size_t length) { + if (!dev) + return -1; + const unsigned char *data_to_send = data; CFIndex length_to_send = length; IOReturn res; @@ -1138,6 +1156,9 @@ static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char static int get_report(hid_device *dev, IOHIDReportType type, unsigned char *data, size_t length) { + if (!dev || !data) + return -1; + unsigned char *report = data; CFIndex report_length = length; IOReturn res = kIOReturnSuccess; @@ -1183,6 +1204,9 @@ int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t /* Helper function, so that this isn't duplicated in hid_read(). */ static int return_data(hid_device *dev, unsigned char *data, size_t length) { + if (!dev || !data) + return -1; + /* Copy the data out of the linked list item (rpt) into the return buffer (data), and delete the liked list item. */ struct input_report *rpt = dev->input_reports; @@ -1198,6 +1222,9 @@ static int return_data(hid_device *dev, unsigned char *data, size_t length) static int cond_wait(hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex) { + if (!dev) + return -1; + while (!dev->input_reports) { int res = pthread_cond_wait(cond, mutex); if (res != 0) @@ -1219,6 +1246,9 @@ static int cond_wait(hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mut static int cond_timedwait(hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) { + if (!dev) + return -1; + while (!dev->input_reports) { int res = pthread_cond_timedwait(cond, mutex, abstime); if (res != 0) @@ -1243,6 +1273,9 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t { int bytes_read = -1; + if (!dev) + return bytes_read; + /* Lock the access to the report list. */ pthread_mutex_lock(&dev->mutex); @@ -1325,6 +1358,9 @@ int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length) int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock) { + if (!dev) + return -1; + /* All Nonblocking operation is handled by the library. */ dev->blocking = !nonblock; @@ -1465,6 +1501,9 @@ int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *s } HID_API_EXPORT struct hid_device_info *HID_API_CALL hid_get_device_info(hid_device *dev) { + if (!dev) + return NULL; + if (!dev->device_info) { dev->device_info = create_device_info(dev->device_handle); if (!dev->device_info) { @@ -1488,6 +1527,9 @@ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index int HID_API_EXPORT_CALL hid_darwin_get_location_id(hid_device *dev, uint32_t *location_id) { + if (!dev || !location_id) + return -1; + int res = get_int_property(dev->device_handle, CFSTR(kIOHIDLocationIDKey)); if (res != 0) { *location_id = (uint32_t) res; @@ -1518,11 +1560,14 @@ int HID_API_EXPORT_CALL hid_darwin_is_device_open_exclusive(hid_device *dev) int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size) { + if (!dev) + return -1; + CFTypeRef ref = IOHIDDeviceGetProperty(dev->device_handle, CFSTR(kIOHIDReportDescriptorKey)); if (ref != NULL && CFGetTypeID(ref) == CFDataGetTypeID()) { CFDataRef report_descriptor = (CFDataRef) ref; const UInt8 *descriptor_buf = CFDataGetBytePtr(report_descriptor); - CFIndex descriptor_buf_len = CFDataGetLength(report_descriptor); + const CFIndex descriptor_buf_len = CFDataGetLength(report_descriptor); size_t copy_len = (size_t) descriptor_buf_len; if (descriptor_buf == NULL || descriptor_buf_len < 0) { diff --git a/windows/hid.c b/windows/hid.c index 35c2de04e..180f85182 100644 --- a/windows/hid.c +++ b/windows/hid.c @@ -225,6 +225,9 @@ static hid_device *new_hid_device() static void free_hid_device(hid_device *dev) { + if (!dev) + return; + CloseHandle(dev->ol.hEvent); CloseHandle(dev->write_ol.hEvent); CloseHandle(dev->device_handle); @@ -304,6 +307,9 @@ static void register_winapi_error_to_buffer(wchar_t **error_buffer, const WCHAR static void register_string_error_to_buffer(wchar_t **error_buffer, const WCHAR *string_error) { + if (!error_buffer) + return; + free(*error_buffer); *error_buffer = NULL; @@ -318,11 +324,17 @@ static void register_string_error_to_buffer(wchar_t **error_buffer, const WCHAR static void register_winapi_error(hid_device *dev, const WCHAR *op) { + if (!dev) + return; + register_winapi_error_to_buffer(&dev->last_error_str, op); } static void register_string_error(hid_device *dev, const WCHAR *string_error) { + if (!dev) + return; + register_string_error_to_buffer(&dev->last_error_str, string_error); } @@ -456,6 +468,9 @@ static int hid_internal_extract_int_token_value(wchar_t* string, const wchar_t* static void hid_internal_get_usb_info(struct hid_device_info* dev, DEVINST dev_node) { + if (!dev) + return; + wchar_t *device_id = NULL, *hardware_ids = NULL; device_id = hid_internal_get_devnode_property(dev_node, &DEVPKEY_Device_InstanceId, DEVPROP_TYPE_STRING); @@ -564,6 +579,9 @@ static void hid_internal_get_usb_info(struct hid_device_info* dev, DEVINST dev_n */ static void hid_internal_get_ble_info(struct hid_device_info* dev, DEVINST dev_node) { + if (!dev) + return; + if (wcslen(dev->manufacturer_string) == 0) { /* Manufacturer Name String (UUID: 0x2A29) */ wchar_t* manufacturer_string = hid_internal_get_devnode_property(dev_node, (const DEVPROPKEY*)&PKEY_DeviceInterface_Bluetooth_Manufacturer, DEVPROP_TYPE_STRING); @@ -1043,7 +1061,10 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path) end_of_function: free(interface_path); - CloseHandle(device_handle); + + if (device_handle) { + CloseHandle(device_handle); + } if (pp_data) { HidD_FreePreparsedData(pp_data); @@ -1061,6 +1082,9 @@ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char * unsigned char *buf; + if (!dev) + return function_result; + if (!data || !length) { register_string_error(dev, L"Zero buffer/length"); return function_result; @@ -1078,8 +1102,15 @@ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char * /* The user passed the right number of bytes. Use the buffer as-is. */ buf = (unsigned char *) data; } else { - if (dev->write_buf == NULL) + if (dev->write_buf == NULL) { dev->write_buf = (unsigned char *) malloc(dev->output_report_length); + + if (dev->write_buf == NULL) { + register_winapi_error(dev, L"hid_write/malloc"); + goto end_of_function; + } + } + buf = dev->write_buf; memcpy(buf, data, length); memset(buf + length, 0, dev->output_report_length - length); @@ -1123,9 +1154,11 @@ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char * return function_result; } - int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) { + if (!dev) + return -1; + DWORD bytes_read = 0; size_t copy_len = 0; BOOL res = FALSE; @@ -1217,12 +1250,18 @@ int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, s int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock) { + if (!dev) + return -1; + dev->blocking = !nonblock; return 0; /* Success */ } int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) { + if (!dev) + return -1; + BOOL res = FALSE; unsigned char *buf; size_t length_to_send; @@ -1243,8 +1282,15 @@ int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const u buf = (unsigned char *) data; length_to_send = length; } else { - if (dev->feature_buf == NULL) + if (dev->feature_buf == NULL) { dev->feature_buf = (unsigned char *) malloc(dev->feature_report_length); + + if (dev->feature_buf == NULL) { + register_winapi_error(dev, L"hid_send_feature_report/malloc"); + return -1; + } + } + buf = dev->feature_buf; memcpy(buf, data, length); memset(buf + length, 0, dev->feature_report_length - length); @@ -1263,6 +1309,9 @@ int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const u static int hid_get_report(hid_device *dev, DWORD report_type, unsigned char *data, size_t length) { + if (!dev) + return -1; + BOOL res; DWORD bytes_returned = 0; @@ -1337,8 +1386,15 @@ int HID_API_EXPORT HID_API_CALL hid_send_output_report(hid_device* dev, const un buf = (unsigned char *) data; length_to_send = length; } else { - if (dev->write_buf == NULL) + if (dev->write_buf == NULL) { dev->write_buf = (unsigned char *) malloc(dev->output_report_length); + + if (dev->write_buf == NULL) { + register_winapi_error(dev, L"hid_send_output_report/malloc"); + return -1; + } + } + buf = dev->write_buf; memcpy(buf, data, length); memset(buf + length, 0, dev->output_report_length - length); @@ -1371,6 +1427,9 @@ void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev) int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) { + if (!dev) + return -1; + if (!string || !maxlen) { register_string_error(dev, L"Zero buffer/length"); return -1; @@ -1391,6 +1450,9 @@ int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) { + if (!dev) + return -1; + if (!string || !maxlen) { register_string_error(dev, L"Zero buffer/length"); return -1; @@ -1411,6 +1473,9 @@ int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wch int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) { + if (!dev) + return -1; + if (!string || !maxlen) { register_string_error(dev, L"Zero buffer/length"); return -1; @@ -1430,6 +1495,9 @@ int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *de } HID_API_EXPORT struct hid_device_info * HID_API_CALL hid_get_device_info(hid_device *dev) { + if (!dev) + return NULL; + if (!dev->device_info) { register_string_error(dev, L"NULL device info"); @@ -1441,6 +1509,9 @@ HID_API_EXPORT struct hid_device_info * HID_API_CALL hid_get_device_info(hid_dev int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) { + if (!dev) + return -1; + BOOL res; if (dev->device_info && dev->device_info->bus_type == HID_API_BUS_USB && maxlen > MAX_STRING_WCHARS_USB) { @@ -1461,6 +1532,9 @@ int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int int HID_API_EXPORT_CALL hid_winapi_get_container_id(hid_device *dev, GUID *container_id) { + if (!dev) + return -1; + wchar_t *interface_path = NULL, *device_id = NULL; CONFIGRET cr = CR_FAILURE; DEVINST dev_node; @@ -1513,6 +1587,9 @@ int HID_API_EXPORT_CALL hid_winapi_get_container_id(hid_device *dev, GUID *conta int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size) { + if (!dev) + return -1; + PHIDP_PREPARSED_DATA pp_data = NULL; if (!HidD_GetPreparsedData(dev->device_handle, &pp_data) || pp_data == NULL) {