RFC: dinput8/tests: Add valid wide string termination to actionName member.

Bernhard √úbelacker bernhardu at mailbox.org
Tue Aug 2 16:34:10 CDT 2016


https://bugs.winehq.org/show_bug.cgi?id=40384
https://www.winehq.org/pipermail/wine-devel/2016-July/114054.html

DirectX SDK offers the possibility to increase debug
output via "DirectX Control Panel".
This prints this error:
  DINPUT8: ERROR IDirectInput8::EnumDevicesBySemantics: arg 2: invalid UNICODE string

It looks like ansi version of EnumDevicesBySemantics forwards the string to
the wide variant without conversation.
So the assumption is that with the old compiler version we got
enough valid wide string termination between the ansi string actionName
member and the next invalid memory page.
This is the added test trying to prove by putting the string right before
a memory page with PAGE_NOACCESS.
---
 dlls/dinput8/tests/device.c | 10 +++---
 dlls/dinput8/tests/dinput.c | 79 ++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 79 insertions(+), 10 deletions(-)

diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c
index fc415b7..aacee7d 100644
--- a/dlls/dinput8/tests/device.c
+++ b/dlls/dinput8/tests/device.c
@@ -49,15 +49,15 @@ enum {
 static DIACTIONA actionMapping[]=
 {
   /* axis */
-  { 0, 0x01008A01 /* DIAXIS_DRIVINGR_STEER */ , 0, { "Steer" } },
+  { 0, 0x01008A01 /* DIAXIS_DRIVINGR_STEER */ , 0, { "Steer.\0" } }, /* Prepare a valid wide string termination. */
   /* button */
-  { 1, 0x01000C01 /* DIBUTTON_DRIVINGR_SHIFTUP */ , 0, { "Upshift" } },
+  { 1, 0x01000C01 /* DIBUTTON_DRIVINGR_SHIFTUP */ , 0, { "Upshift.\0" } },
   /* keyboard key */
-  { 2, DIKEYBOARD_SPACE , 0, { "Missile" } },
+  { 2, DIKEYBOARD_SPACE , 0, { "Missile.\0" } },
   /* mouse button */
-  { 3, DIMOUSE_BUTTON0, 0, { "Select" } },
+  { 3, DIMOUSE_BUTTON0, 0, { "Select\0" } },
   /* mouse axis */
-  { 4, DIMOUSE_YAXIS, 0, { "Y Axis" } }
+  { 4, DIMOUSE_YAXIS, 0, { "Y Axis\0" } }
 };
 
 static void flush_events(void)
diff --git a/dlls/dinput8/tests/dinput.c b/dlls/dinput8/tests/dinput.c
index 57f5505..08e5ce0 100644
--- a/dlls/dinput8/tests/dinput.c
+++ b/dlls/dinput8/tests/dinput.c
@@ -443,15 +443,15 @@ struct enum_semantics_test
 static DIACTIONA actionMapping[]=
 {
   /* axis */
-  { 0, 0x01008A01 /* DIAXIS_DRIVINGR_STEER */,      0, { "Steer" }   },
+  { 0, 0x01008A01 /* DIAXIS_DRIVINGR_STEER */,      0, { "Steer.\0" }   }, /* Prepare a valid wide string termination. */
   /* button */
-  { 1, 0x01000C01 /* DIBUTTON_DRIVINGR_SHIFTUP */,  0, { "Upshift" } },
+  { 1, 0x01000C01 /* DIBUTTON_DRIVINGR_SHIFTUP */,  0, { "Upshift.\0" } },
   /* keyboard key */
-  { 2, DIKEYBOARD_SPACE,                            0, { "Missile" } },
+  { 2, DIKEYBOARD_SPACE,                            0, { "Missile.\0" } },
   /* mouse button */
-  { 3, DIMOUSE_BUTTON0,                             0, { "Select" }  },
+  { 3, DIMOUSE_BUTTON0,                             0, { "Select\0" }  },
   /* mouse axis */
-  { 4, DIMOUSE_YAXIS,                               0, { "Y Axis" }  }
+  { 4, DIMOUSE_YAXIS,                               0, { "Y Axis\0" }  }
 };
 
 static BOOL CALLBACK enum_semantics_callback(const DIDEVICEINSTANCEA *lpddi, IDirectInputDevice8A *lpdid, DWORD dwFlags, DWORD dwRemaining, void *context)
@@ -485,6 +485,54 @@ static BOOL CALLBACK set_action_map_callback(const DIDEVICEINSTANCEA *lpddi, IDi
     return DIENUM_CONTINUE;
 }
 
+static DWORD get_pagesize(void)
+{
+    SYSTEM_INFO si;
+    GetSystemInfo(&si);
+
+    return si.dwPageSize;
+}
+
+static void* get_guarded_memory(int size, int at_end_of_page, void**base_address)
+{
+    DWORD pagesize = get_pagesize();
+    char *buf;
+    char *ret;
+    DWORD old_protect = 0;
+
+    buf = VirtualAlloc(NULL, ((size / pagesize) + 3) * pagesize, MEM_COMMIT, PAGE_READWRITE);
+    if (!buf)
+    {
+        trace("VirtualAlloc failed\n");
+        return NULL;
+    }
+    *base_address = buf;
+
+    if (!VirtualProtect(buf, pagesize, PAGE_NOACCESS, &old_protect)) {
+        trace("VirtualProtect failed\n");
+    }
+
+    ret = buf + pagesize;
+    if (at_end_of_page) {
+        ret += pagesize - size;
+    }
+
+    if (!VirtualProtect(buf + (pagesize * 2), pagesize, PAGE_NOACCESS, &old_protect)) {
+        trace("VirtualProtect failed\n");
+    }
+
+    return ret;
+}
+
+static void free_guarded_memory(void* base_address)
+{
+    if (base_address)
+    {
+        if (!VirtualFree(base_address, 0, MEM_RELEASE))
+            trace("VirtualFree failed\n");
+    }
+}
+
 static void test_EnumDevicesBySemantics(void)
 {
     IDirectInput8A *pDI;
@@ -493,6 +541,9 @@ static void test_EnumDevicesBySemantics(void)
     const GUID ACTION_MAPPING_GUID = { 0x1, 0x2, 0x3, { 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb } };
     struct enum_semantics_test data = { 0, FALSE, FALSE, &diaf, NULL };
     int device_total = 0;
+    const char actionName_orig[] = { 'S','t','e','e','r','.',0,'x' };
+    void *actionName_base = NULL;
+    char *actionName;
 
     hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL);
     if (FAILED(hr))
@@ -511,6 +562,23 @@ static void test_EnumDevicesBySemantics(void)
     diaf.dwGenre = 0x01000000; /* DIVIRTUAL_DRIVING_RACE */
     diaf.dwBufferSize = 32;
 
+    /* Test should fail because lptszActionName contains a terminated ansi string,
+     * followed by a memory page with PAGE_NOACCESS.
+     * It looks like ansi version of EnumDevicesBySemantics forwards the string to
+     * the wide variant without conversation. */
+    actionName = (char*)get_guarded_memory(sizeof(actionName_orig), 1, &actionName_base);
+    memcpy(actionName, actionName_orig, sizeof(actionName_orig));
+    actionMapping[0].lptszActionName = actionName;
+    data.device_count = 0;
+    hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_ATTACHEDONLY);
+    todo_wine
+    ok (data.device_count == 0, "EnumDevicesBySemantics did call the callback, even with non double terminated string. hr=%08x\n", hr);
+    todo_wine
+    ok(FAILED(hr), "EnumDevicesBySemantics succeeded with non double terminated string hr=%08x\n", hr);
+    /* Replace the 'x' behind the ansi string termination to get a valid wide string termination.
+     * And the following tests should succeed. */
+    actionName[sizeof(actionName_orig)-1] = '\0';
+
     /* Test enumerating all attached and installed devices */
     data.keyboard = FALSE;
     data.mouse = FALSE;
@@ -582,6 +650,7 @@ static void test_EnumDevicesBySemantics(void)
     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, NULL, 0);
     todo_wine ok(FAILED(hr), "EnumDevicesBySemantics succeeded with invalid GUID hr=%08x\n", hr);
 
+    free_guarded_memory(actionName_base);
     IDirectInput8_Release(pDI);
 }
 
-- 
2.1.4




More information about the wine-patches mailing list