When fuOptions has ETO_PDY specified, the DxBuffer in NtGdiExtTextOutW consists of...
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Sat, 20 Dec 2008 20:38:23 +0000 (20:38 +0000)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Sat, 20 Dec 2008 20:38:23 +0000 (20:38 +0000)
See issue #3958 for more details.

svn path=/trunk/; revision=38201

reactos/subsystems/win32/win32k/objects/freetype.c

index af69675..16551d6 100644 (file)
@@ -3135,6 +3135,8 @@ NtGdiExtTextOutW(
     BOOL DoBreak = FALSE;
     LPCWSTR String, SafeString = NULL;
     HPALETTE hDestPalette;
+    PVOID TmpBuffer = NULL;
+    ULONG TmpBufSize, StringSize, DxSize = 0;
 
     // TODO: Write test-cases to exactly match real Windows in different
     // bad parameters (e.g. does Windows check the DC or the RECT first?).
@@ -3160,41 +3162,70 @@ NtGdiExtTextOutW(
         SetLastWin32Error(ERROR_INVALID_PARAMETER);
         goto fail;
     }
+
+    Status = STATUS_SUCCESS;
     if (Count > 0)
     {
-        SafeString = ExAllocatePoolWithTag(PagedPool, Count * sizeof(WCHAR), TAG_GDITEXT);
-        if (!SafeString)
+        TmpBufSize = StringSize = Count * sizeof(WCHAR);
+        if (UnsafeDx)
         {
-            goto fail;
+            /* If ETO_PDY is specified, we have pairs of INTs */
+            DxSize = Count * sizeof(INT) * (fuOptions & ETO_PDY ? 2 : 1);
+            TmpBufSize += DxSize;
         }
-        Status = MmCopyFromCaller(SafeString, UnsafeString, Count * sizeof(WCHAR));
-        if (! NT_SUCCESS(Status))
+
+        /* Allocate a temp buffer for the string and the Dx values */
+        TmpBuffer = ExAllocatePoolWithTag(PagedPool, TmpBufSize, TAG_GDITEXT);
+        SafeString = TmpBuffer;
+        if (!TmpBuffer)
         {
+            SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
             goto fail;
         }
-    }
-    String = SafeString;
 
-    if (NULL != UnsafeDx && Count > 0)
-    {
-        Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
-        if (NULL == Dx)
+        /* Probe and copy user mode data to the temp buffer */
+        _SEH2_TRY
         {
-            goto fail;
+            if (UnsafeString)
+            {
+                ProbeForRead(UnsafeString, StringSize, 1);
+                memcpy((PVOID)SafeString, UnsafeString, StringSize);
+            }
+
+            if (UnsafeDx)
+            {
+                ProbeForRead(UnsafeDx, DxSize, 1);
+                Dx = (INT*)((ULONG_PTR)TmpBuffer + StringSize);
+                memcpy(Dx, UnsafeString, DxSize);
+            }
+
         }
-        Status = MmCopyFromCaller(Dx, UnsafeDx, Count * sizeof(INT));
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            Status = _SEH2_GetExceptionCode();
+        }
+        _SEH2_END
         if (!NT_SUCCESS(Status))
         {
             goto fail;
         }
     }
+    String = SafeString;
 
     if (lprc)
     {
-        Status = MmCopyFromCaller(&SpecifiedDestRect, lprc, sizeof(RECT));
+        _SEH2_TRY
+        {
+            ProbeForRead(lprc, sizeof(RECT), 1);
+            memcpy(&SpecifiedDestRect, lprc, sizeof(RECT));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            Status = _SEH2_GetExceptionCode();
+        }
+        _SEH2_END
         if (!NT_SUCCESS(Status))
         {
-            SetLastWin32Error(ERROR_INVALID_PARAMETER);
             goto fail;
         }
     }
@@ -3692,13 +3723,9 @@ fail:
         BRUSHOBJ_UnlockBrush(BrushFg);
         NtGdiDeleteObject(hBrushFg);
     }
-    if (NULL != SafeString)
-    {
-        ExFreePoolWithTag((void*)SafeString, TAG_GDITEXT);
-    }
-    if (NULL != Dx)
+    if (TmpBuffer)
     {
-        ExFreePoolWithTag(Dx, TAG_GDITEXT);
+        ExFreePoolWithTag(TmpBuffer, TAG_GDITEXT);
     }
     DC_UnlockDc(dc);