[WIN32SS]
authorJérôme Gardou <jerome.gardou@reactos.org>
Mon, 23 Oct 2017 18:34:02 +0000 (20:34 +0200)
committerJérôme Gardou <zefklop@users.noreply.github.com>
Sat, 18 Nov 2017 11:15:45 +0000 (12:15 +0100)
 - Do not call the driver Escape routine while holding locks on GDI objects
CORE-7727

win32ss/gdi/eng/pdevobj.h
win32ss/gdi/eng/surface.h
win32ss/gdi/ntgdi/print.c

index 4fabfe1..9b986ac 100644 (file)
@@ -201,4 +201,11 @@ PDEVOBJ_pdmMatchDevMode(
     PPDEVOBJ ppdev,
     PDEVMODEW pdm);
 
+FORCEINLINE
+VOID
+PDEVOBJ_vReference(PPDEVOBJ ppdev)
+{
+    InterlockedIncrement(&ppdev->cPdevRefs);
+}
+
 #endif /* !__WIN32K_PDEVOBJ_H */
index 96a35b1..ee05847 100644 (file)
@@ -90,6 +90,13 @@ enum _SURFACEFLAGS
 /* NOTE: Use shared locks! */
 #define  SURFACE_ShareLockSurface(hBMObj) \
   ((PSURFACE) GDIOBJ_ShareLockObj ((HGDIOBJ) hBMObj, GDI_OBJECT_TYPE_BITMAP))
+FORCEINLINE
+VOID
+SURFACE_ShareLockByPointer(PSURFACE psurf)
+{
+    GDIOBJ_vReferenceObjectByPointer(&psurf->BaseObject);
+}
+
 #define  SURFACE_UnlockSurface(pBMObj)  \
   GDIOBJ_vUnlockObject ((POBJ)pBMObj)
 #define  SURFACE_ShareUnlockSurface(pBMObj)  \
index 5139eaa..582bfca 100644 (file)
@@ -75,43 +75,6 @@ NtGdiEscape(HDC  hDC,
   return ret;
 }
 
-INT
-APIENTRY
-IntGdiExtEscape(
-   PDC    dc,
-   INT    Escape,
-   INT    InSize,
-   LPCSTR InData,
-   INT    OutSize,
-   LPSTR  OutData)
-{
-   SURFACE *psurf;
-   INT Result;
-
-   if ((dc->ppdev->DriverFunctions.Escape == NULL) ||
-       (dc->dclevel.pSurface == NULL))
-   {
-      Result = 0;
-   }
-   else
-   {
-      DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
-      psurf = dc->dclevel.pSurface;
-
-      Result = dc->ppdev->DriverFunctions.Escape(
-         &psurf->SurfObj,
-         Escape,
-         InSize,
-         (PVOID)InData,
-         OutSize,
-         (PVOID)OutData );
-
-      DC_vFinishBlit(dc, NULL);
-   }
-
-   return Result;
-}
-
 INT
 APIENTRY
 NtGdiExtEscape(
@@ -124,22 +87,73 @@ NtGdiExtEscape(
    INT    OutSize,
    OPTIONAL LPSTR  UnsafeOutData)
 {
-   PDC      pDC;
    LPVOID   SafeInData = NULL;
    LPVOID   SafeOutData = NULL;
    NTSTATUS Status = STATUS_SUCCESS;
    INT      Result;
+   PPDEVOBJ ppdev;
+   PSURFACE psurf;
+
+   if (hDC == NULL)
+   {
+      if (pDriver)
+      {
+         /* FIXME : Get the pdev from its name */
+         UNIMPLEMENTED;
+         return -1;
+      }
 
-   if (hDC == 0)
+      ppdev = EngpGetPDEV(NULL);
+      if (!ppdev)
+      {
+         EngSetLastError(ERROR_BAD_DEVICE);
+         return -1;
+      }
+
+      /* We're using the primary surface of the pdev. Lock it */
+      EngAcquireSemaphore(ppdev->hsemDevLock);
+
+      psurf = ppdev->pSurface;
+      if (!psurf)
+      {
+         EngReleaseSemaphore(ppdev->hsemDevLock);
+         PDEVOBJ_vRelease(ppdev);
+         return 0;
+      }
+      SURFACE_ShareLockByPointer(psurf);
+   }
+   else
    {
-       hDC = UserGetWindowDC(NULL);
+      PDC pDC = DC_LockDc(hDC);
+      if ( pDC == NULL )
+      {
+         EngSetLastError(ERROR_INVALID_HANDLE);
+         return -1;
+      }
+
+      /* Get the PDEV from the DC */
+      ppdev = pDC->ppdev;
+      PDEVOBJ_vReference(ppdev);
+
+      /* Check if we have a surface */
+      psurf = pDC->dclevel.pSurface;
+      if (!psurf)
+      {
+         DC_UnlockDc(pDC);
+         PDEVOBJ_vRelease(ppdev);
+         return 0;
+      }
+      SURFACE_ShareLockByPointer(psurf);
+
+      /* We're done with the DC */
+      DC_UnlockDc(pDC);
    }
 
-   pDC = DC_LockDc(hDC);
-   if ( pDC == NULL )
+   /* See if we actually have a driver function to call */
+   if (ppdev->DriverFunctions.Escape == NULL)
    {
-      EngSetLastError(ERROR_INVALID_HANDLE);
-      return -1;
+      Result = 0;
+      goto Exit;
    }
 
    if ( InSize && UnsafeInData )
@@ -158,17 +172,16 @@ NtGdiExtEscape(
 
       if (!NT_SUCCESS(Status))
       {
-        DC_UnlockDc(pDC);
-        SetLastNtError(Status);
-        return -1;
+         Result = -1;
+         goto Exit;
       }
 
       SafeInData = ExAllocatePoolWithTag ( PagedPool, InSize, GDITAG_TEMP );
       if ( !SafeInData )
       {
-         DC_UnlockDc(pDC);
          EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
-         return -1;
+         Result = -1;
+         goto Exit;
       }
 
       _SEH2_TRY
@@ -186,10 +199,9 @@ NtGdiExtEscape(
 
       if ( !NT_SUCCESS(Status) )
       {
-         ExFreePoolWithTag ( SafeInData, GDITAG_TEMP );
-         DC_UnlockDc(pDC);
          SetLastNtError(Status);
-         return -1;
+         Result = -1;
+         goto Exit;
       }
    }
 
@@ -209,50 +221,65 @@ NtGdiExtEscape(
 
       if (!NT_SUCCESS(Status))
       {
-        SetLastNtError(Status);
-        goto freeout;
+         SetLastNtError(Status);
+         Result = -1;
+         goto Exit;
       }
 
       SafeOutData = ExAllocatePoolWithTag ( PagedPool, OutSize, GDITAG_TEMP );
       if ( !SafeOutData )
       {
          EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
-freeout:
-         if ( SafeInData )
-            ExFreePoolWithTag ( SafeInData, GDITAG_TEMP );
-         DC_UnlockDc(pDC);
-         return -1;
+         Result = -1;
+         goto Exit;
       }
    }
 
-   Result = IntGdiExtEscape ( pDC, Escape, InSize, SafeInData, OutSize, SafeOutData );
+   /* Finally call the driver */
+   Result = ppdev->DriverFunctions.Escape(
+         &psurf->SurfObj,
+         Escape,
+         InSize,
+         SafeInData,
+         OutSize,
+         SafeOutData );
 
-   DC_UnlockDc(pDC);
+Exit:
+   if (hDC == NULL)
+   {
+      EngReleaseSemaphore(ppdev->hsemDevLock);
+   }
+   SURFACE_ShareUnlockSurface(psurf);
+   PDEVOBJ_vRelease(ppdev);
 
    if ( SafeInData )
+   {
       ExFreePoolWithTag ( SafeInData ,GDITAG_TEMP );
+   }
 
    if ( SafeOutData )
    {
-      _SEH2_TRY
-      {
-        /* Pointers were already probed! */
-        RtlCopyMemory(UnsafeOutData,
-                      SafeOutData,
-                      OutSize);
-      }
-      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+      if (Result > 0)
       {
-        Status = _SEH2_GetExceptionCode();
+         _SEH2_TRY
+         {
+            /* Pointers were already probed! */
+            RtlCopyMemory(UnsafeOutData, SafeOutData, OutSize);
+         }
+         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+         {
+            Status = _SEH2_GetExceptionCode();
+         }
+         _SEH2_END;
+
+         if ( !NT_SUCCESS(Status) )
+         {
+            SetLastNtError(Status);
+            Result = -1;
+         }
       }
-      _SEH2_END;
 
       ExFreePoolWithTag ( SafeOutData, GDITAG_TEMP );
-      if ( !NT_SUCCESS(Status) )
-      {
-         SetLastNtError(Status);
-         return -1;
-      }
    }
 
    return Result;