[PATCH v3] dinput: Cap the buffer size to 20.

Alistair Leslie-Hughes leslie_alistair at hotmail.com
Sun Jan 12 16:33:24 CST 2020


When a program calls SetProperty with DIPROP_BUFFERSIZE, dinput records
this value for GetProperty but only uses it when the device can support
that number of buffers otherwise a max value.

In the case of game "Far Cry 5", it passes through (DWORD)-1 which
cause HeapAlloc to fail ((DWORD)-1 * sizeof(DIDEVICEOBJECTDATA)).

Since there is no real way of working out the max value, I've capped it at 20.

MSDN reference.
https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee417908(v=vs.85)

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45732

Signed-off-by: Alistair Leslie-Hughes <leslie_alistair at hotmail.com>
---
 dlls/dinput/device.c         | 12 ++++++++----
 dlls/dinput/device_private.h |  3 ++-
 dlls/dinput/tests/device.c   | 25 +++++++++++++++++++++++++
 3 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c
index 28329d03b5..d02910c1b1 100644
--- a/dlls/dinput/device.c
+++ b/dlls/dinput/device.c
@@ -1307,7 +1307,7 @@ HRESULT WINAPI IDirectInputDevice2WImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface,
 
             if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
 
-            pd->dwData = This->queue_len;
+            pd->dwData = This->buffersize;
             TRACE("buffersize = %d\n", pd->dwData);
             break;
         }
@@ -1396,12 +1396,16 @@ HRESULT WINAPI IDirectInputDevice2WImpl_SetProperty(
             TRACE("buffersize = %d\n", pd->dwData);
 
             EnterCriticalSection(&This->crit);
+
+            This->buffersize  = pd->dwData;
+
+            This->queue_len = min(This->buffersize, 20);
+
             HeapFree(GetProcessHeap(), 0, This->data_queue);
 
-            This->data_queue = !pd->dwData ? NULL : HeapAlloc(GetProcessHeap(), 0,
-                                pd->dwData * sizeof(DIDEVICEOBJECTDATA));
+            This->data_queue = !This->queue_len ? NULL : HeapAlloc(GetProcessHeap(), 0,
+                                This->queue_len * sizeof(DIDEVICEOBJECTDATA));
             This->queue_head = This->queue_tail = This->overflow = 0;
-            This->queue_len  = pd->dwData;
 
             LeaveCriticalSection(&This->crit);
             break;
diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h
index 27e9c26286..23d9e2eebc 100644
--- a/dlls/dinput/device_private.h
+++ b/dlls/dinput/device_private.h
@@ -71,10 +71,11 @@ struct IDirectInputDeviceImpl
     DI_EVENT_PROC               event_proc;  /* function to receive mouse & keyboard events */
 
     LPDIDEVICEOBJECTDATA        data_queue;  /* buffer for 'GetDeviceData'.                 */
-    int                         queue_len;   /* size of the queue - set in 'SetProperty'    */
+    int                         queue_len;   /* valid size of the queue                     */
     int                         queue_head;  /* position to write new event into queue      */
     int                         queue_tail;  /* next event to read from queue               */
     BOOL                        overflow;    /* return DI_BUFFEROVERFLOW in 'GetDeviceData' */
+    DWORD                       buffersize;  /* size of the queue - set in 'SetProperty'    */
 
     DataFormat                  data_format; /* user data format and wine to user format converter */
 
diff --git a/dlls/dinput/tests/device.c b/dlls/dinput/tests/device.c
index a2a5a65686..dcf8a37334 100644
--- a/dlls/dinput/tests/device.c
+++ b/dlls/dinput/tests/device.c
@@ -25,6 +25,8 @@
 #include "windef.h"
 #include "dinput.h"
 
+#include <limits.h>
+
 static const DIOBJECTDATAFORMAT obj_data_format[] = {
   { &GUID_YAxis, 16, DIDFT_OPTIONAL|DIDFT_AXIS  |DIDFT_MAKEINSTANCE(1), 0},
   { &GUID_Button,15, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(3), 0},
@@ -106,8 +108,22 @@ static void test_object_info(IDirectInputDeviceA *device, HWND hwnd)
     dp.diph.dwHeaderSize = sizeof(DIPROPHEADER);
     dp.diph.dwHow = DIPH_DEVICE;
     dp.diph.dwObj = 0;
+    dp.dwData = UINT_MAX;
+
+    hr = IDirectInputDevice_GetProperty(device, DIPROP_BUFFERSIZE, &dp.diph);
+    ok(hr == DI_OK, "Failed: %08x\n", hr);
+    ok(dp.dwData == 0, "got %d\n", dp.dwData);
+
+    dp.dwData = UINT_MAX;
+    hr = IDirectInputDevice_SetProperty(device, DIPROP_BUFFERSIZE, (LPCDIPROPHEADER)&dp.diph);
+    ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr);
+
     dp.dwData = 0;
+    hr = IDirectInputDevice_GetProperty(device, DIPROP_BUFFERSIZE, &dp.diph);
+    ok(hr == DI_OK, "Failed: %08x\n", hr);
+    ok(dp.dwData == UINT_MAX, "got %d\n", dp.dwData);
 
+    dp.dwData = 0;
     hr = IDirectInputDevice_SetProperty(device, DIPROP_BUFFERSIZE, (LPCDIPROPHEADER)&dp.diph);
     ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr);
     cnt = 5;
@@ -166,6 +182,15 @@ static void test_object_info(IDirectInputDeviceA *device, HWND hwnd)
         hr = IDirectInputDevice_Unacquire(device);
         ok(hr == DI_OK, "Unacquire() failed: %08x\n", hr);
     }
+
+    /* Reset buffer size */
+    dp.diph.dwSize = sizeof(DIPROPDWORD);
+    dp.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+    dp.diph.dwHow = DIPH_DEVICE;
+    dp.diph.dwObj = 0;
+    dp.dwData = 0;
+    hr = IDirectInputDevice_SetProperty(device, DIPROP_BUFFERSIZE, (LPCDIPROPHEADER)&dp.diph);
+    ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr);
 }
 
 struct enum_data
-- 
2.17.1




More information about the wine-devel mailing list