[WIN32K]
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Sun, 8 Mar 2015 17:25:44 +0000 (17:25 +0000)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Sun, 8 Mar 2015 17:25:44 +0000 (17:25 +0000)
- Pass bitmap buffer size to SURFACE_AllocSurface and validate it
- Fix arithmetic overflow checks by using RtlULongMult
- GreExtTextOutW: do not allocate / blit zero sized bitmaps
- NtGdiStretchDIBitsInternal: do not pass negative y size to GreCreateBitmapEx
- DIB_CreateDIBSection: use calculated bitmap size, instead of biSizeImage when calculating the section view size and as size parameter to GreCreateBitmapEx
CORE-9245 #resolve

svn path=/trunk/; revision=66611

reactos/win32ss/gdi/eng/bitblt.c
reactos/win32ss/gdi/eng/surface.c
reactos/win32ss/gdi/eng/surface.h
reactos/win32ss/gdi/ntgdi/bitblt.c
reactos/win32ss/gdi/ntgdi/bitmaps.c
reactos/win32ss/gdi/ntgdi/dibobj.c
reactos/win32ss/gdi/ntgdi/freetype.c
reactos/win32ss/pch.h

index 83bc508..646cb15 100644 (file)
@@ -1078,6 +1078,7 @@ IntEngMaskBlt(
                                          psoDest->iBitmapFormat,
                                          0,
                                          0,
+                                         0,
                                          NULL);
         if (psurfTemp == NULL)
         {
index 3513a2d..d82434d 100644 (file)
@@ -120,6 +120,7 @@ SURFACE_AllocSurface(
     _In_ ULONG iFormat,
     _In_ ULONG fjBitmap,
     _In_opt_ ULONG cjWidth,
+    _In_opt_ ULONG cjBufSize,
     _In_opt_ PVOID pvBits)
 {
     ULONG cBitsPixel, cjBits, cjObject;
@@ -127,7 +128,9 @@ SURFACE_AllocSurface(
     SURFOBJ *pso;
     PVOID pvSection;
 
-    ASSERT(!pvBits || (iType == STYPE_BITMAP));
+    NT_ASSERT(!pvBits || (iType == STYPE_BITMAP));
+    NT_ASSERT((iFormat <= BMF_32BPP) || (cjBufSize != 0));
+    NT_ASSERT((LONG)cy > 0);
 
     /* Verify format */
     if ((iFormat < BMF_1BPP) || (iFormat > BMF_PNG))
@@ -151,8 +154,35 @@ SURFACE_AllocSurface(
         cjWidth = WIDTH_BYTES_ALIGN32(cx, cBitsPixel);
     }
 
-    /* Calculate the bitmap size in bytes */
-    cjBits = cjWidth * cy;
+    /* Is this an uncompressed format? */
+    if (iFormat <= BMF_32BPP)
+    {
+        /* Calculate the correct bitmap size in bytes */
+        if (!NT_SUCCESS(RtlULongMult(cjWidth, cy, &cjBits)))
+        {
+            DPRINT1("Overflow calculating size: cjWidth %lu, cy %lu\n",
+                    cjWidth, cy);
+            return NULL;
+        }
+
+        /* Did we get a buffer and size? */
+        if ((pvBits != NULL) && (cjBufSize != 0))
+        {
+            /* Make sure the buffer is large enough */
+            if (cjBufSize < cjBits)
+            {
+                DPRINT1("Buffer is too small, required: %lu, got %lu\n",
+                        cjBits, cjBufSize);
+                return NULL;
+            }
+        }
+    }
+    else
+    {
+        /* Compressed format, use the provided size */
+        NT_ASSERT(cjBufSize != 0);
+        cjBits = cjBufSize;
+    }
 
     /* Check if we need an extra large object */
     if ((iType == STYPE_BITMAP) && (pvBits == NULL) &&
@@ -168,9 +198,10 @@ SURFACE_AllocSurface(
     }
 
     /* Check for arithmetic overflow */
-    if ((cjBits < cjWidth) || (cjObject < sizeof(SURFACE)))
+    if (cjObject < sizeof(SURFACE))
     {
         /* Fail! */
+        DPRINT1("Overflow calculating cjObject: cjBits %lu\n", cjBits);
         return NULL;
     }
 
@@ -289,6 +320,7 @@ EngCreateBitmap(
                                  iFormat,
                                  fl,
                                  lWidth,
+                                 0,
                                  pvBits);
     if (!psurf)
     {
@@ -327,6 +359,7 @@ EngCreateDeviceBitmap(
                                  iFormat,
                                  0,
                                  0,
+                                 0,
                                  NULL);
     if (!psurf)
     {
@@ -365,6 +398,7 @@ EngCreateDeviceSurface(
                                  iFormat,
                                  0,
                                  0,
+                                 0,
                                  NULL);
     if (!psurf)
     {
index 355eb7b..2e2b84f 100644 (file)
@@ -123,6 +123,7 @@ SURFACE_AllocSurface(
     _In_ ULONG iFormat,
     _In_ ULONG fjBitmap,
     _In_opt_ ULONG cjWidth,
+    _In_opt_ ULONG cjBits,
     _In_opt_ PVOID pvBits);
 
 FORCEINLINE
index 9351979..9bcafe8 100644 (file)
@@ -1453,6 +1453,7 @@ NtGdiGetPixel(
                                      BMF_32BPP,
                                      0,
                                      0,
+                                     0,
                                      &ulRGBColor);
     if (psurfDest)
     {
index 3ef4ce9..37e8ad1 100644 (file)
@@ -103,6 +103,7 @@ GreCreateBitmapEx(
         pvCompressedBits = pvBits;
         pvBits = NULL;
         iFormat = (iFormat == BMF_4RLE) ? BMF_4BPP : BMF_8BPP;
+        cjSizeImage = 0;
     }
 
     /* Allocate a surface */
@@ -112,6 +113,7 @@ GreCreateBitmapEx(
                                  iFormat,
                                  fjBitmap,
                                  cjWidthBytes,
+                                 cjSizeImage,
                                  pvBits);
     if (!psurf)
     {
@@ -207,6 +209,7 @@ NtGdiCreateBitmap(
                                  iFormat,
                                  0,
                                  0,
+                                 0,
                                  NULL);
     if (!psurf)
     {
index c2b2926..9bedfbf 100644 (file)
@@ -1090,7 +1090,7 @@ NtGdiGetDIBitsInternal(
         _SEH2_TRY
         {
             /* Copy the data back */
-            cjMaxInfo = min(cjMaxInfo, DIB_BitmapInfoSize(pbmi, (WORD)iUsage));
+            cjMaxInfo = min(cjMaxInfo, (UINT)DIB_BitmapInfoSize(pbmi, (WORD)iUsage));
             ProbeForWrite(pbmiUser, cjMaxInfo, 1);
             RtlCopyMemory(pbmiUser, pbmi, cjMaxInfo);
         }
@@ -1228,7 +1228,7 @@ NtGdiStretchDIBitsInternal(
     RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
 
     hbmTmp = GreCreateBitmapEx(pbmi->bmiHeader.biWidth,
-                               pbmi->bmiHeader.biHeight,
+                               abs(pbmi->bmiHeader.biHeight),
                                0,
                                BitmapFormat(pbmi->bmiHeader.biBitCount,
                                             pbmi->bmiHeader.biCompression),
@@ -1652,7 +1652,7 @@ DIB_CreateDIBSection(
 
     // Get storage location for DIB bits.  Only use biSizeImage if it's valid and
     // we're dealing with a compressed bitmap.  Otherwise, use width * height.
-    totalSize = bi->biSizeImage && bi->biCompression != BI_RGB && bi->biCompression != BI_BITFIELDS
+    totalSize = (bi->biSizeImage && (bi->biCompression != BI_RGB) && (bi->biCompression != BI_BITFIELDS))
                 ? bi->biSizeImage : (ULONG)(bm.bmWidthBytes * effHeight);
 
     if (section)
@@ -1674,7 +1674,7 @@ DIB_CreateDIBSection(
         }
 
         mapOffset = offset - (offset % Sbi.AllocationGranularity);
-        mapSize = bi->biSizeImage + (offset - mapOffset);
+        mapSize = totalSize + (offset - mapOffset);
 
         SectionOffset.LowPart  = mapOffset;
         SectionOffset.HighPart = 0;
@@ -1724,7 +1724,7 @@ DIB_CreateDIBSection(
                             BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression),
                             BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT |
                             ((bi->biHeight < 0) ? BMF_TOPDOWN : 0),
-                            bi->biSizeImage,
+                            totalSize,
                             bm.bmBits,
                             0);
     if (!res)
index cffdc4f..86f3ae8 100644 (file)
@@ -3662,7 +3662,6 @@ GreExtTextOutW(
                 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
             MouseSafetyOnDrawEnd(dc->ppdev);
             BackgroundLeft = DestRect.right;
-
         }
 
         DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
@@ -3675,71 +3674,75 @@ GreExtTextOutW(
         MaskRect.right = realglyph->bitmap.width;
         MaskRect.bottom = realglyph->bitmap.rows;
 
-        /*
-         * We should create the bitmap out of the loop at the biggest possible
-         * glyph size. Then use memset with 0 to clear it and sourcerect to
-         * limit the work of the transbitblt.
-         */
-
-        HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
-                                       BMF_8BPP, BMF_TOPDOWN,
-                                       realglyph->bitmap.buffer);
-        if ( !HSourceGlyph )
+        /* Check if the bitmap has any pixels */
+        if ((bitSize.cx != 0) && (bitSize.cy != 0))
         {
-            DPRINT1("WARNING: EngLockSurface() failed!\n");
-            // FT_Done_Glyph(realglyph);
-            IntUnLockFreeType;
-            DC_vFinishBlit(dc, NULL);
-            goto fail2;
-        }
-        SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
-        if ( !SourceGlyphSurf )
-        {
-            EngDeleteSurface((HSURF)HSourceGlyph);
-            DPRINT1("WARNING: EngLockSurface() failed!\n");
-            IntUnLockFreeType;
-            DC_vFinishBlit(dc, NULL);
-            goto fail2;
-        }
+            /*
+             * We should create the bitmap out of the loop at the biggest possible
+             * glyph size. Then use memset with 0 to clear it and sourcerect to
+             * limit the work of the transbitblt.
+             */
+
+            HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
+                                           BMF_8BPP, BMF_TOPDOWN,
+                                           realglyph->bitmap.buffer);
+            if ( !HSourceGlyph )
+            {
+                DPRINT1("WARNING: EngCreateBitmap() failed!\n");
+                // FT_Done_Glyph(realglyph);
+                IntUnLockFreeType;
+                DC_vFinishBlit(dc, NULL);
+                goto fail2;
+            }
+            SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
+            if ( !SourceGlyphSurf )
+            {
+                EngDeleteSurface((HSURF)HSourceGlyph);
+                DPRINT1("WARNING: EngLockSurface() failed!\n");
+                IntUnLockFreeType;
+                DC_vFinishBlit(dc, NULL);
+                goto fail2;
+            }
 
-        /*
-         * Use the font data as a mask to paint onto the DCs surface using a
-         * brush.
-         */
+            /*
+             * Use the font data as a mask to paint onto the DCs surface using a
+             * brush.
+             */
 
-        if (lprc && (fuOptions & ETO_CLIPPED) &&
-                DestRect.right >= lprc->right + dc->ptlDCOrig.x)
-        {
-            // We do the check '>=' instead of '>' to possibly save an iteration
-            // through this loop, since it's breaking after the drawing is done,
-            // and x is always incremented.
-            DestRect.right = lprc->right + dc->ptlDCOrig.x;
-            DoBreak = TRUE;
-        }
-        if (lprc && (fuOptions & ETO_CLIPPED) &&
-                DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
-        {
-            DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
-        }
-        MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
-        if (!IntEngMaskBlt(
-            SurfObj,
-            SourceGlyphSurf,
-            &dc->co.ClipObj,
-            &exloRGB2Dst.xlo,
-            &exloDst2RGB.xlo,
-            &DestRect,
-            (PPOINTL)&MaskRect,
-            &dc->eboText.BrushObject,
-            &BrushOrigin))
-        {
-            DPRINT1("Failed to MaskBlt a glyph!\n");
-        }
+            if (lprc && (fuOptions & ETO_CLIPPED) &&
+                    DestRect.right >= lprc->right + dc->ptlDCOrig.x)
+            {
+                // We do the check '>=' instead of '>' to possibly save an iteration
+                // through this loop, since it's breaking after the drawing is done,
+                // and x is always incremented.
+                DestRect.right = lprc->right + dc->ptlDCOrig.x;
+                DoBreak = TRUE;
+            }
+            if (lprc && (fuOptions & ETO_CLIPPED) &&
+                    DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
+            {
+                DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
+            }
+            MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
+            if (!IntEngMaskBlt(
+                SurfObj,
+                SourceGlyphSurf,
+                &dc->co.ClipObj,
+                &exloRGB2Dst.xlo,
+                &exloDst2RGB.xlo,
+                &DestRect,
+                (PPOINTL)&MaskRect,
+                &dc->eboText.BrushObject,
+                &BrushOrigin))
+            {
+                DPRINT1("Failed to MaskBlt a glyph!\n");
+            }
 
-        MouseSafetyOnDrawEnd(dc->ppdev) ;
+            MouseSafetyOnDrawEnd(dc->ppdev) ;
 
-        EngUnlockSurface(SourceGlyphSurf);
-        EngDeleteSurface((HSURF)HSourceGlyph);
+            EngUnlockSurface(SourceGlyphSurf);
+            EngDeleteSurface((HSURF)HSourceGlyph);
+        }
 
         if (DoBreak)
         {
index 794a691..cd09813 100644 (file)
@@ -26,6 +26,7 @@
 #include <ndk/psfuncs.h>
 #include <ndk/rtlfuncs.h>
 #include <ntstrsafe.h>
+#include <ntintsafe.h>
 #include <ntddkbd.h>
 
 /* Win32 headers */