Dmitry Timoshkov : gdi32: Make sure that we don't read/ write beyond the provided buffer in GetOutlineTextMetricsA, add a test case .

Alexandre Julliard julliard at wine.codeweavers.com
Mon Feb 5 07:45:10 CST 2007


Module: wine
Branch: master
Commit: e915a3cfb102870ed71843844b62c337af758ac4
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=e915a3cfb102870ed71843844b62c337af758ac4

Author: Dmitry Timoshkov <dmitry at codeweavers.com>
Date:   Fri Feb  2 18:18:15 2007 +0800

gdi32: Make sure that we don't read/write beyond the provided buffer in GetOutlineTextMetricsA, add a test case.

---

 dlls/gdi32/font.c       |   32 +++++++++++++----
 dlls/gdi32/tests/font.c |   86 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 110 insertions(+), 8 deletions(-)

diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c
index 527a0d9..ee57ba8 100644
--- a/dlls/gdi32/font.c
+++ b/dlls/gdi32/font.c
@@ -1484,17 +1484,33 @@ UINT WINAPI GetOutlineTextMetricsA(
 
         /* check if the string offsets really fit into the provided size */
         /* FIXME: should we check string length as well? */
-        if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
-            lpOTM->otmpFamilyName = 0; /* doesn't fit */
+        /* make sure that we don't read/write beyond the provided buffer */
+        if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(LPSTR))
+        {
+            if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
+                lpOTM->otmpFamilyName = 0; /* doesn't fit */
+        }
 
-        if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
-            lpOTM->otmpFaceName = 0; /* doesn't fit */
+        /* make sure that we don't read/write beyond the provided buffer */
+        if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(LPSTR))
+        {
+            if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
+                lpOTM->otmpFaceName = 0; /* doesn't fit */
+        }
 
-        if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
-            lpOTM->otmpStyleName = 0; /* doesn't fit */
+            /* make sure that we don't read/write beyond the provided buffer */
+        if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(LPSTR))
+        {
+            if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
+                lpOTM->otmpStyleName = 0; /* doesn't fit */
+        }
 
-        if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
-            lpOTM->otmpFullName = 0; /* doesn't fit */
+        /* make sure that we don't read/write beyond the provided buffer */
+        if (lpOTM->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(LPSTR))
+        {
+            if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
+                lpOTM->otmpFullName = 0; /* doesn't fit */
+        }
     }
 
 end:
diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c
index e18bffe..670ec36 100644
--- a/dlls/gdi32/tests/font.c
+++ b/dlls/gdi32/tests/font.c
@@ -732,6 +732,91 @@ todo_wine {
     ReleaseDC(0, hdc);
 }
 
+static void test_GetOutlineTextMetrics(void)
+{
+    OUTLINETEXTMETRIC *otm;
+    LOGFONT lf;
+    HFONT hfont, hfont_old;
+    HDC hdc;
+    DWORD ret, otm_size;
+
+    hdc = GetDC(0);
+
+    if (!is_font_installed("Arial"))
+    {
+        skip("Arial is not installed\n");
+        return;
+    }
+
+    memset(&lf, 0, sizeof(lf));
+    strcpy(lf.lfFaceName, "Arial");
+    lf.lfHeight = -13;
+    lf.lfWeight = FW_NORMAL;
+    lf.lfPitchAndFamily = DEFAULT_PITCH;
+    lf.lfQuality = PROOF_QUALITY;
+    hfont = CreateFontIndirect(&lf);
+    assert(hfont != 0);
+
+    hfont_old = SelectObject(hdc, hfont);
+    otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
+    trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
+
+    otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
+
+    memset(otm, 0xAA, otm_size);
+    SetLastError(0xdeadbeef);
+    otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
+    ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
+    ok(ret == 1 /* Win9x */ ||
+       ret == otm->otmSize /* XP*/,
+       "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
+    if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
+    {
+        ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
+        ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
+        ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
+        ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
+    }
+
+    memset(otm, 0xAA, otm_size);
+    SetLastError(0xdeadbeef);
+    otm->otmSize = otm_size; /* just in case for Win9x compatibility */
+    ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
+    ok(ret == 1 /* Win9x */ ||
+       ret == otm->otmSize /* XP*/,
+       "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
+    if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
+    {
+        ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
+        ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
+        ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
+        ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
+    }
+
+    /* ask about truncated data */
+    memset(otm, 0xAA, otm_size);
+    SetLastError(0xdeadbeef);
+    otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
+    ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
+    ok(ret == 1 /* Win9x */ ||
+       ret == otm->otmSize /* XP*/,
+       "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
+    if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
+    {
+        ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
+        ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
+        ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
+    }
+    ok(otm->otmpFullName == (LPSTR)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm->otmpFullName);
+
+    HeapFree(GetProcessHeap(), 0, otm);
+
+    SelectObject(hdc, hfont_old);
+    DeleteObject(hfont);
+
+    ReleaseDC(0, hdc);
+}
+
 START_TEST(font)
 {
     test_logfont();
@@ -742,4 +827,5 @@ START_TEST(font)
     test_text_extents();
     test_GetGlyphIndices();
     test_GetKerningPairs();
+    test_GetOutlineTextMetrics();
 }




More information about the wine-cvs mailing list