RFC: usp10/tests: Reserve for InClass a byte for every character in teststr.

Bernhard Übelacker bernhardu at mailbox.org
Tue Aug 2 16:33:53 CDT 2016


https://bugs.winehq.org/show_bug.cgi?id=40385

ScriptStringAnalyse crashes if InClass is just one byte in size
followed by memory marked as PAGE_NOACCESS.
By testing the size it seems it should have the same size as characters
in teststr are given to the function.
---
 dlls/usp10/tests/usp10.c | 103 +++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 95 insertions(+), 8 deletions(-)

diff --git a/dlls/usp10/tests/usp10.c b/dlls/usp10/tests/usp10.c
index 6b2152f..7eb0592 100644
--- a/dlls/usp10/tests/usp10.c
+++ b/dlls/usp10/tests/usp10.c
@@ -2900,7 +2900,7 @@ static void test_ScriptString(HDC hdc)
     DWORD           Flags = SSA_GLYPHS;
     int             ReqWidth = 100;
     const int       Dx[5] = {10, 10, 10, 10, 10};
-    const BYTE      InClass = 0;
+    const BYTE      InClass[len];
     SCRIPT_STRING_ANALYSIS ssa = NULL;
 
     int             X = 10; 
@@ -2916,29 +2916,30 @@ static void test_ScriptString(HDC hdc)
 
 
     Charset = -1;     /* this flag indicates unicode input */
+    memset((void*)InClass, 0, sizeof(InClass));
     /* Test without hdc to get E_PENDING */
     hr = ScriptStringAnalyse( NULL, teststr, len, Glyphs, Charset, Flags,
                               ReqWidth, NULL, NULL, Dx, NULL,
-                              &InClass, &ssa);
+                              InClass, &ssa);
     ok(hr == E_PENDING, "ScriptStringAnalyse Stub should return E_PENDING not %08x\n", hr);
 
     /* Test that 0 length string returns E_INVALIDARG  */
     hr = ScriptStringAnalyse( hdc, teststr, 0, Glyphs, Charset, Flags,
                               ReqWidth, NULL, NULL, Dx, NULL,
-                              &InClass, &ssa);
+                              InClass, &ssa);
     ok(hr == E_INVALIDARG, "ScriptStringAnalyse should return E_INVALIDARG not %08x\n", hr);
 
     /* test with hdc, this should be a valid test  */
     hr = ScriptStringAnalyse( hdc, teststr, len, Glyphs, Charset, Flags,
                               ReqWidth, NULL, NULL, Dx, NULL,
-                              &InClass, &ssa);
+                              InClass, &ssa);
     ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
     ScriptStringFree(&ssa);
 
     /* test makes sure that a call with a valid pssa still works */
     hr = ScriptStringAnalyse( hdc, teststr, len, Glyphs, Charset, Flags,
                               ReqWidth, NULL, NULL, Dx, NULL,
-                              &InClass, &ssa);
+                              InClass, &ssa);
     ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
     ok(ssa != NULL, "ScriptStringAnalyse pssa should not be NULL\n");
 
@@ -2982,7 +2983,7 @@ static void test_ScriptStringXtoCP_CPtoX(HDC hdc)
     int             Charset = -1;                       /* unicode                        */
     DWORD           Flags = SSA_GLYPHS;
     int             ReqWidth = 100;
-    const BYTE      InClass = 0;
+    const BYTE      InClass[String_len];
     SCRIPT_STRING_ANALYSIS ssa = NULL;
 
     int             Ch;                                  /* Character position in string */
@@ -2992,6 +2993,8 @@ static void test_ScriptStringXtoCP_CPtoX(HDC hdc)
     int             trail,lead;
     BOOL            fTrailing;
 
+    memset((void*)InClass, 0, sizeof(InClass));
+
     /* Test with hdc, this should be a valid test
      * Here we generate an SCRIPT_STRING_ANALYSIS that will be used as input to the
      * following character positions to X and X to character position functions.
@@ -2999,7 +3002,7 @@ static void test_ScriptStringXtoCP_CPtoX(HDC hdc)
 
     hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
                               ReqWidth, NULL, NULL, NULL, NULL,
-                              &InClass, &ssa);
+                              InClass, &ssa);
     ok(hr == S_OK ||
        hr == E_INVALIDARG, /* NT */
        "ScriptStringAnalyse should return S_OK or E_INVALIDARG not %08x\n", hr);
@@ -3139,7 +3142,7 @@ static void test_ScriptStringXtoCP_CPtoX(HDC hdc)
          */
         hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
                                   ReqWidth, NULL, NULL, NULL, NULL,
-                                  &InClass, &ssa);
+                                  InClass, &ssa);
         ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
 
         /*
@@ -3610,6 +3613,86 @@ static void test_ScriptGetFontFunctions(HDC hdc)
     }
 }
 
+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_ScriptStringAnalyse_InClass_length(HDC hdc, int crash)
+{
+    HRESULT         hr;
+    static const WCHAR teststr1[]  = {0x05e9, 'i', 0x05dc, 'n', 0x05d5, 'e', 0x05dd, '.',0};
+    void            *String = (WCHAR *) &teststr1;      /* ScriptStringAnalysis needs void */
+    int             String_len = (sizeof(teststr1)/sizeof(WCHAR))-1;
+    int             Glyphs = String_len * 2 + 16;       /* size of buffer as recommended  */
+    int             Charset = -1;                       /* unicode                        */
+    DWORD           Flags = SSA_GLYPHS;
+    int             ReqWidth = 100;
+    const BYTE      *InClass;
+    SCRIPT_STRING_ANALYSIS ssa = NULL;
+
+    void*           base_address = NULL;
+
+    /* Get a chunk of memory followed by memory with PAGE_NOACCESS to
+     * trigger an exception on access.
+     *
+     * Seems InClass should point to memory with at least the length String_len.
+     */
+    InClass = (BYTE*)get_guarded_memory(String_len - (crash?1:0), 1, &base_address);
+    *(BYTE*)InClass = 0;
+
+    trace("before ScriptStringAnalyse crash=%d\n", crash);
+    hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
+                              ReqWidth, NULL, NULL, NULL, NULL,
+                              InClass, &ssa);
+    ok(!crash, "expected access violation but succeeded.\n");
+    ScriptStringFree(&ssa);
+    free_guarded_memory(base_address);
+}
+
 START_TEST(usp10)
 {
     HWND            hwnd;
@@ -3664,6 +3747,10 @@ START_TEST(usp10)
 
     test_ScriptGetFontFunctions(hdc);
 
+    test_ScriptStringAnalyse_InClass_length(hdc, 0);
+    if (0)
+        test_ScriptStringAnalyse_InClass_length(hdc, 1);  /* is supposed to crash */
+
     ReleaseDC(hwnd, hdc);
     DestroyWindow(hwnd);
 }
-- 
2.1.4




More information about the wine-patches mailing list