Detect buffer overflow when getting DirectInput device state This fixes bug https://github.com/libsdl-org/SDL/issues/4528
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
diff --git a/src/joystick/windows/SDL_dinputjoystick.c b/src/joystick/windows/SDL_dinputjoystick.c
index 8699f31..4854df3 100644
--- a/src/joystick/windows/SDL_dinputjoystick.c
+++ b/src/joystick/windows/SDL_dinputjoystick.c
@@ -34,7 +34,7 @@
#define DIDFT_OPTIONAL 0x80000000
#endif
-#define INPUT_QSIZE 32 /* Buffer up to 32 input messages */
+#define INPUT_QSIZE 128 /* Buffer up to 128 input messages */
#define JOY_AXIS_THRESHOLD (((SDL_JOYSTICK_AXIS_MAX)-(SDL_JOYSTICK_AXIS_MIN))/100) /* 1% motion */
#define CONVERT_MAGNITUDE(x) (((x)*10000) / 0x7FFF)
@@ -947,60 +947,6 @@ TranslatePOV(DWORD value)
return HAT_VALS[value];
}
-static void
-UpdateDINPUTJoystickState_Buffered(SDL_Joystick * joystick)
-{
- int i;
- HRESULT result;
- DWORD numevents;
- DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
-
- numevents = INPUT_QSIZE;
- result =
- IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
- sizeof(DIDEVICEOBJECTDATA), evtbuf,
- &numevents, 0);
- if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
- IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
- result =
- IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
- sizeof(DIDEVICEOBJECTDATA),
- evtbuf, &numevents, 0);
- }
-
- /* Handle the events or punt */
- if (FAILED(result)) {
- return;
- }
-
- for (i = 0; i < (int)numevents; ++i) {
- int j;
-
- for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
- const input_t *in = &joystick->hwdata->Inputs[j];
-
- if (evtbuf[i].dwOfs != in->ofs)
- continue;
-
- switch (in->type) {
- case AXIS:
- SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)evtbuf[i].dwData);
- break;
- case BUTTON:
- SDL_PrivateJoystickButton(joystick, in->num,
- (Uint8)(evtbuf[i].dwData ? SDL_PRESSED : SDL_RELEASED));
- break;
- case HAT:
- {
- Uint8 pos = TranslatePOV(evtbuf[i].dwData);
- SDL_PrivateJoystickHat(joystick, in->num, pos);
- }
- break;
- }
- }
- }
-}
-
/* Function to update the state of a joystick - called as a device poll.
* This function shouldn't update the joystick structure directly,
* but instead should call SDL_PrivateJoystick*() to deliver events
@@ -1075,6 +1021,67 @@ UpdateDINPUTJoystickState_Polled(SDL_Joystick * joystick)
}
}
+static void
+UpdateDINPUTJoystickState_Buffered(SDL_Joystick * joystick)
+{
+ int i;
+ HRESULT result;
+ DWORD numevents;
+ DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
+
+ numevents = INPUT_QSIZE;
+ result =
+ IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
+ sizeof(DIDEVICEOBJECTDATA), evtbuf,
+ &numevents, 0);
+ if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
+ IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
+ result =
+ IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
+ sizeof(DIDEVICEOBJECTDATA),
+ evtbuf, &numevents, 0);
+ }
+
+ /* Handle the events or punt */
+ if (FAILED(result)) {
+ return;
+ }
+
+ for (i = 0; i < (int)numevents; ++i) {
+ int j;
+
+ for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
+ const input_t *in = &joystick->hwdata->Inputs[j];
+
+ if (evtbuf[i].dwOfs != in->ofs)
+ continue;
+
+ switch (in->type) {
+ case AXIS:
+ SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)evtbuf[i].dwData);
+ break;
+ case BUTTON:
+ SDL_PrivateJoystickButton(joystick, in->num,
+ (Uint8)(evtbuf[i].dwData ? SDL_PRESSED : SDL_RELEASED));
+ break;
+ case HAT:
+ {
+ Uint8 pos = TranslatePOV(evtbuf[i].dwData);
+ SDL_PrivateJoystickHat(joystick, in->num, pos);
+ }
+ break;
+ }
+ }
+ }
+
+ if (result == DI_BUFFEROVERFLOW) {
+ /* Our buffer wasn't big enough to hold all the queued events,
+ * so poll the device to make sure we have the complete state.
+ */
+ UpdateDINPUTJoystickState_Polled(joystick);
+ }
+}
+
void
SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick)
{