This is unsafe because the event is auto-reset, therefore the call to
WaitForSingleObject() resets the event which GetOverlappedResult() will
try to wait on.
Even though the overlapped operation is guaranteed to be completed at
the point we call GetOverlappedResult(), it will still wait on the event
handle for a short time to trigger the reset for auto-reset events. This
amounts to roughly a 100 ms sleep each time GetOverlappedResult() is called
for a completed I/O with a non-signalled event.
In the context of HIDAPI, this extra sleep means that callers that loop
on hid_read_timeout() with timeout=0 will loop forever, since the 100 ms
sleep each iteration ensures ReadFile() will always have new data.
- hidapi already called CancelIo on hid_close but that only cancels pending IO for the current thread. Controller read/writes originate from multiple
threads (serialized, but on a different thread nonetheless) but device destruction was always done on the main device thread which left any
pending overlapped reads still running after hidapi's internal read buffer is deallocated leading to intermittent free list corruption.
Mathieu Eyraud
SDL dynamically loads libusb but does not check the return value of 'SDL_LoadFunction'.
Also libusb is loaded and initialized several time because 'SDL_hidapi_wasinit' is never set to true.
I made a patch if you want to test:
- check that 'hid_init' is called once and only once,
- check return value of 'hid_init',
- check return value of 'SDL_LoadFunction',
- check return value of 'SDL_malloc',
- add some debug logging.
This fixes bad report parsing for various newer Xbox controllers, and this driver is now preferred over XInput, since it handles more than 4 controllers.
There are a number of poorly behaved HID devices that time out on attempts to
read various strings. Rather than end up on an endless treadmill of blacklisting
broken devices, reduce our risk by only querying devices that are gamepads.
SDL_hidapijoystick.c already checks these same usages, so we shouldn't
exclude any working HID devices (caveat below).
This also makes HidP_GetPreparsedData() and HidP_GetCaps() failure skip
the device entirely, but that seems desired. If a device can't even return basic
top-level collection data properly, we want nothing to do with that broken device.
If we do find devices that work with HIDAPI joystick and fail these calls, we can
add an exception via VID+PID matching.
It appears that with some (presumably) flaky drivers or hardware that the WriteFile in hid_write never completes leading to GetOverlappedResult to block forever waiting for it.
The function we currently use, IOHIDDeviceRegisterRemovalCallback(), often
fails on Catalina with a "__CFRunLoopModeFindSourceForMachPort returned NULL"
error message. Once a removal callback is missed, we will eventually crash when
the joystick is closed attempting to use the invalid IOHIDDeviceRef.
https://forums.developer.apple.com/thread/124444