gdi32: Add a GdiConvertToDevmodeW test, make it pass under Wine

Dmitry Timoshkov dmitry at codeweavers.com
Tue Dec 18 06:21:40 CST 2007


Hello,

this patch should fix a crash reported in the bug 10799. It's caused by
a buggy app that doesn't initialize the dmSize field leaving it much larger
than the DEVMODEA struct passed to ChangeDisplaySettingsA leading to an
attempt to read beyond the end of buffer.

Changelog:
    gdi32: Add a GdiConvertToDevmodeW test, make it pass under Wine.
---
 dlls/gdi32/driver.c   |   14 ++++++++----
 dlls/gdi32/tests/dc.c |   50 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 5 deletions(-)

diff --git a/dlls/gdi32/driver.c b/dlls/gdi32/driver.c
index 8dc14fe..4d1aaad 100644
--- a/dlls/gdi32/driver.c
+++ b/dlls/gdi32/driver.c
@@ -413,8 +413,12 @@ DEVMODEW * WINAPI GdiConvertToDevmodeW(const DEVMODEA *dmA)
     DEVMODEW *dmW;
     WORD dmW_size;
 
-    dmW_size = dmA->dmSize + CCHDEVICENAME;
-    if (dmA->dmSize >= (const char *)dmA->dmFormName - (const char *)dmA + CCHFORMNAME)
+    dmW_size = dmA->dmSize;
+    if (dmW_size > sizeof(DEVMODEA))
+        dmW_size = sizeof(DEVMODEA);
+
+    dmW_size += CCHDEVICENAME;
+    if (dmA->dmSize >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME)
         dmW_size += CCHFORMNAME;
 
     dmW = HeapAlloc(GetProcessHeap(), 0, dmW_size + dmA->dmDriverExtra);
@@ -425,12 +429,12 @@ DEVMODEW * WINAPI GdiConvertToDevmodeW(const DEVMODEA *dmA)
     /* copy slightly more, to avoid long computations */
     memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion, dmA->dmSize - CCHDEVICENAME);
 
-    if (dmA->dmSize >= (const char *)dmA->dmFormName - (const char *)dmA + CCHFORMNAME)
+    if (dmA->dmSize >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME)
     {
         MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmFormName, CCHFORMNAME,
                                        dmW->dmFormName, CCHFORMNAME);
-        if (dmA->dmSize > (const char *)&dmA->dmLogPixels - (const char *)dmA)
-            memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize - ((const char *)&dmA->dmLogPixels - (const char *)dmA));
+        if (dmA->dmSize > FIELD_OFFSET(DEVMODEA, dmLogPixels))
+            memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize - FIELD_OFFSET(DEVMODEA, dmLogPixels));
     }
 
     if (dmA->dmDriverExtra)
diff --git a/dlls/gdi32/tests/dc.c b/dlls/gdi32/tests/dc.c
index 72cd155..f292c37 100644
--- a/dlls/gdi32/tests/dc.c
+++ b/dlls/gdi32/tests/dc.c
@@ -173,8 +173,58 @@ static void test_savedc(void)
     DeleteDC(hdc);
 }
 
+static void test_GdiConvertToDevmodeW(void)
+{
+    DEVMODEW * (WINAPI *pGdiConvertToDevmodeW)(const DEVMODEA *);
+    DEVMODEA dmA;
+    DEVMODEW *dmW;
+    BOOL ret;
+
+    pGdiConvertToDevmodeW = (void *)GetProcAddress(GetModuleHandleA("gdi32.dll"), "GdiConvertToDevmodeW");
+    if (!pGdiConvertToDevmodeW)
+    {
+        skip("GdiConvertToDevmodeW is not available on this platform\n");
+        return;
+    }
+
+    ret = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &dmA);
+    ok(ret, "EnumDisplaySettingsExA error %u\n", GetLastError());
+    ok(dmA.dmSize >= FIELD_OFFSET(DEVMODEA, dmICMMethod), "dmSize is too small: %04x\n", dmA.dmSize);
+    ok(dmA.dmSize <= sizeof(DEVMODEA), "dmSize is too large: %04x\n", dmA.dmSize);
+
+    dmW = pGdiConvertToDevmodeW(&dmA);
+    ok(dmW->dmSize >= FIELD_OFFSET(DEVMODEW, dmICMMethod), "dmSize is too small: %04x\n", dmW->dmSize);
+    ok(dmW->dmSize <= sizeof(DEVMODEW), "dmSize is too large: %04x\n", dmW->dmSize);
+    HeapFree(GetProcessHeap(), 0, dmW);
+
+    dmA.dmSize = FIELD_OFFSET(DEVMODEA, dmFields) + sizeof(dmA.dmFields);
+    dmW = pGdiConvertToDevmodeW(&dmA);
+    ok(dmW->dmSize == FIELD_OFFSET(DEVMODEW, dmFields) + sizeof(dmW->dmFields),
+       "expected %04x, got %04x\n",
+        FIELD_OFFSET(DEVMODEW, dmFields) + sizeof(dmW->dmFields), dmW->dmSize);
+    HeapFree(GetProcessHeap(), 0, dmW);
+
+    dmA.dmICMMethod = DMICMMETHOD_NONE;
+    dmA.dmSize = FIELD_OFFSET(DEVMODEA, dmICMMethod) + sizeof(dmA.dmICMMethod);
+    dmW = pGdiConvertToDevmodeW(&dmA);
+    ok(dmW->dmSize == FIELD_OFFSET(DEVMODEW, dmICMMethod) + sizeof(dmW->dmICMMethod),
+       "expected %04x, got %04x\n",
+        FIELD_OFFSET(DEVMODEW, dmICMMethod) + sizeof(dmW->dmICMMethod), dmW->dmSize);
+    ok(dmW->dmICMMethod == DMICMMETHOD_NONE,
+       "expected DMICMMETHOD_NONE, got %u\n", dmW->dmICMMethod);
+    HeapFree(GetProcessHeap(), 0, dmW);
+
+    dmA.dmSize = 1024;
+    dmW = pGdiConvertToDevmodeW(&dmA);
+    ok(dmW->dmSize == FIELD_OFFSET(DEVMODEW, dmPanningHeight) + sizeof(dmW->dmPanningHeight),
+       "expected %04x, got %04x\n",
+        FIELD_OFFSET(DEVMODEW, dmPanningHeight) + sizeof(dmW->dmPanningHeight), dmW->dmSize);
+    HeapFree(GetProcessHeap(), 0, dmW);
+}
+
 START_TEST(dc)
 {
     test_savedc();
     test_savedc_2();
+    test_GdiConvertToDevmodeW();
 }
-- 
1.5.3.7






More information about the wine-patches mailing list