[WIN32SS][NTGDI] Fix wrong IN/OUT (#1539)
[reactos.git] / win32ss / gdi / ntgdi / gdiobj.c
index 2273dfd..2635aab 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * PROJECT:         ReactOS win32 kernel mode subsystem
  * LICENSE:         GPL - See COPYING in the top level directory
- * FILE:            subsystems/win32/win32k/objects/gdiobj.c
+ * FILE:            win32ss/gdi/ntgdi/gdiobj.c
  * PURPOSE:         General GDI object manipulation routines
  * PROGRAMMERS:     Timo Kreuzer
  */
  *   object from being locked by another thread. A shared lock will simply fail,
  *   while an exclusive lock will succeed after the object was unlocked.
  *
+ * Ownership:
+ *
+ * Owner:               POWNED  PUBLIC  NONE    spec
+ * ---------------------------------------------------
+ * LockForRead          +       +       -       PUBLIC
+ * LockForWrite         +       -       -       POWNED
+ * LockAny              +       +       +       NONE
+ * NtGdiDeleteObjectApp +       -       -       PUBLIC
+ * GreDeleteObject      +       +       +       NONE
+ * GreSetOwner(POWNED)  -       -       +       -
+ * GreSetOwner(PUBLIC)  +       -       +       -
+ * GreSetOwner(NONE)    +       -       -       -
+ *
  */
 
 /* INCLUDES ******************************************************************/
 #define NDEBUG
 #include <debug.h>
 
-// Move to gdidbg.h
+FORCEINLINE
+ULONG
+InterlockedReadUlong(
+    _In_ _Interlocked_operand_ ULONG volatile *Source)
+{
+    return *Source;
+}
+
+FORCEINLINE
+void
+INCREASE_THREAD_LOCK_COUNT(
+    _In_ HANDLE hobj)
+{
+    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+    DBG_UNREFERENCED_PARAMETER(hobj);
+    if (pti)
+    {
+#if DBG
+        pti->acExclusiveLockCount[((ULONG_PTR)hobj >> 16) & 0x1f]++;
+#endif
+        pti->cExclusiveLocks++;
+    }
+}
+
+FORCEINLINE
+void
+DECREASE_THREAD_LOCK_COUNT(
+    _In_ HANDLE hobj)
+{
+    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+    DBG_UNREFERENCED_PARAMETER(hobj);
+    if (pti)
+    {
 #if DBG
-#define DBG_INCREASE_LOCK_COUNT(pti, hobj) \
-    if (pti) ((PTHREADINFO)pti)->acExclusiveLockCount[((ULONG_PTR)hobj >> 16) & 0x1f]++;
-#define DBG_DECREASE_LOCK_COUNT(pti, hobj) \
-    if (pti) ((PTHREADINFO)pti)->acExclusiveLockCount[((ULONG_PTR)hobj >> 16) & 0x1f]--;
+        pti->acExclusiveLockCount[((ULONG_PTR)hobj >> 16) & 0x1f]--;
+#endif
+        pti->cExclusiveLocks--;
+    }
+}
+
+#if DBG
+VOID
+ASSERT_LOCK_ORDER(
+    _In_ UCHAR objt)
+{
+    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+    ULONG i;
+
+    if (pti)
+    {
+        /* Ensure correct locking order! */
+        for (i = objt + 1; i < GDIObjTypeTotal; i++)
+        {
+            NT_ASSERT(pti->acExclusiveLockCount[i] == 0);
+        }
+    }
+}
 #define ASSERT_SHARED_OBJECT_TYPE(objt) \
     ASSERT((objt) == GDIObjType_SURF_TYPE || \
            (objt) == GDIObjType_PAL_TYPE || \
 #define ASSERT_TRYLOCK_OBJECT_TYPE(objt) \
     ASSERT((objt) == GDIObjType_DRVOBJ_TYPE)
 #else
-#define DBG_INCREASE_LOCK_COUNT(ppi, hobj)
-#define DBG_DECREASE_LOCK_COUNT(x, y)
+#define ASSERT_LOCK_ORDER(hobj)
 #define ASSERT_SHARED_OBJECT_TYPE(objt)
 #define ASSERT_EXCLUSIVE_OBJECT_TYPE(objt)
 #define ASSERT_TRYLOCK_OBJECT_TYPE(objt)
@@ -83,8 +146,8 @@ enum
 static PVOID gpvGdiHdlTblSection = NULL;
 PENTRY gpentHmgr;
 PULONG gpaulRefCount;
-ULONG gulFirstFree;
-ULONG gulFirstUnused;
+volatile ULONG gulFirstFree;
+volatile ULONG gulFirstUnused;
 static PPAGED_LOOKASIDE_LIST gpaLookasideList;
 
 static VOID NTAPI GDIOBJ_vCleanup(PVOID ObjectBody);
@@ -109,7 +172,7 @@ apfnCleanup[] =
     NULL,              /* 0d GDIObjType_PFT_TYPE, unused */
     GDIOBJ_vCleanup,   /* 0e GDIObjType_ICMCXF_TYPE */
     NULL,              /* 0f GDIObjType_SPRITE_TYPE, unused */
-    BRUSH_vCleanup,    /* 10 GDIObjType_BRUSH_TYPE, BRUSH, PEN, EXTPEN */
+    NULL,              /* 10 GDIObjType_BRUSH_TYPE, BRUSH, PEN, EXTPEN */
     NULL,              /* 11 GDIObjType_UMPD_TYPE, unused */
     NULL,              /* 12 GDIObjType_UNUSED4_TYPE */
     NULL,              /* 13 GDIObjType_SPACE_TYPE, unused */
@@ -127,6 +190,44 @@ apfnCleanup[] =
     NULL,              /* 1f reserved entry */
 };
 
+static const
+GDIOBJDELETEPROC
+apfnDelete[] =
+{
+    NULL,              /* 00 GDIObjType_DEF_TYPE */
+    NULL,              /* 01 GDIObjType_DC_TYPE */
+    NULL,              /* 02 GDIObjType_UNUSED1_TYPE */
+    NULL,              /* 03 GDIObjType_UNUSED2_TYPE */
+    NULL,              /* 04 GDIObjType_RGN_TYPE */
+    NULL,              /* 05 GDIObjType_SURF_TYPE */
+    NULL,              /* 06 GDIObjType_CLIENTOBJ_TYPE */
+    NULL,              /* 07 GDIObjType_PATH_TYPE */
+    NULL,              /* 08 GDIObjType_PAL_TYPE */
+    NULL,              /* 09 GDIObjType_ICMLCS_TYPE */
+    NULL,              /* 0a GDIObjType_LFONT_TYPE */
+    NULL,              /* 0b GDIObjType_RFONT_TYPE, unused */
+    NULL,              /* 0c GDIObjType_PFE_TYPE, unused */
+    NULL,              /* 0d GDIObjType_PFT_TYPE, unused */
+    NULL,              /* 0e GDIObjType_ICMCXF_TYPE */
+    NULL,                 /* 0f GDIObjType_SPRITE_TYPE, unused */
+    BRUSH_vDeleteObject,  /* 10 GDIObjType_BRUSH_TYPE, BRUSH, PEN, EXTPEN */
+    NULL,              /* 11 GDIObjType_UMPD_TYPE, unused */
+    NULL,              /* 12 GDIObjType_UNUSED4_TYPE */
+    NULL,              /* 13 GDIObjType_SPACE_TYPE, unused */
+    NULL,              /* 14 GDIObjType_UNUSED5_TYPE */
+    NULL,              /* 15 GDIObjType_META_TYPE, unused */
+    NULL,              /* 16 GDIObjType_EFSTATE_TYPE, unused */
+    NULL,              /* 17 GDIObjType_BMFD_TYPE, unused */
+    NULL,              /* 18 GDIObjType_VTFD_TYPE, unused */
+    NULL,              /* 19 GDIObjType_TTFD_TYPE, unused */
+    NULL,              /* 1a GDIObjType_RC_TYPE, unused */
+    NULL,              /* 1b GDIObjType_TEMP_TYPE, unused */
+    NULL,              /* 1c GDIObjType_DRVOBJ_TYPE */
+    NULL,              /* 1d GDIObjType_DCIOBJ_TYPE, unused */
+    NULL,              /* 1e GDIObjType_SPOOL_TYPE, unused */
+    NULL,              /* 1f reserved entry */
+};
+
 /* INTERNAL FUNCTIONS ********************************************************/
 
 static
@@ -250,6 +351,7 @@ IncrementGdiHandleCount(ULONG ulProcessId)
 
     Status = PsLookupProcessByProcessId(ULongToHandle(ulProcessId), &pep);
     NT_ASSERT(NT_SUCCESS(Status));
+    __analysis_assume(NT_SUCCESS(Status));
 
     ppi = PsGetProcessWin32Process(pep);
     if (ppi) InterlockedIncrement((LONG*)&ppi->GDIHandleCount);
@@ -266,6 +368,7 @@ DecrementGdiHandleCount(ULONG ulProcessId)
 
     Status = PsLookupProcessByProcessId(ULongToHandle(ulProcessId), &pep);
     NT_ASSERT(NT_SUCCESS(Status));
+    __analysis_assume(NT_SUCCESS(Status));
 
     ppi = PsGetProcessWin32Process(pep);
     if (ppi) InterlockedDecrement((LONG*)&ppi->GDIHandleCount);
@@ -284,7 +387,7 @@ ENTRY_pentPopFreeEntry(VOID)
     do
     {
         /* Get the index and sequence number of the first free entry */
-        iFirst = gulFirstFree;
+        iFirst = InterlockedReadUlong(&gulFirstFree);
 
         /* Check if we have a free entry */
         if (!(iFirst & GDI_HANDLE_INDEX_MASK))
@@ -296,6 +399,10 @@ ENTRY_pentPopFreeEntry(VOID)
             if (iFirst >= GDI_HANDLE_COUNT)
             {
                 DPRINT1("No more GDI handles left!\n");
+#if DBG_ENABLE_GDIOBJ_BACKTRACES
+                DbgDumpGdiHandleTableWithBT();
+#endif
+                InterlockedDecrement((LONG*)&gulFirstUnused);
                 return 0;
             }
 
@@ -307,7 +414,7 @@ ENTRY_pentPopFreeEntry(VOID)
         pentFree = &gpentHmgr[iFirst & GDI_HANDLE_INDEX_MASK];
 
         /* Create a new value with an increased sequence number */
-        iNext = (USHORT)(ULONG_PTR)pentFree->einfo.pobj;
+        iNext = GDI_HANDLE_GET_INDEX(pentFree->einfo.hFree);
         iNext |= (iFirst & ~GDI_HANDLE_INDEX_MASK) + 0x10000;
 
         /* Try to exchange the FirstFree value */
@@ -348,7 +455,7 @@ ENTRY_vPushFreeEntry(PENTRY pentFree)
     do
     {
         /* Get the current first free index and sequence number */
-        iFirst = gulFirstFree;
+        iFirst = InterlockedReadUlong(&gulFirstFree);
 
         /* Set the einfo.pobj member to the index of the first free entry */
         pentFree->einfo.pobj = UlongToPtr(iFirst & GDI_HANDLE_INDEX_MASK);
@@ -373,7 +480,6 @@ ENTRY_ReferenceEntryByHandle(HGDIOBJ hobj, FLONG fl)
 
     /* Get the handle index and check if its too big */
     ulIndex = GDI_HANDLE_GET_INDEX(hobj);
-    if (ulIndex >= GDI_HANDLE_COUNT) return NULL;
 
     /* Get pointer to the entry */
     pentry = &gpentHmgr[ulIndex];
@@ -473,6 +579,9 @@ GDIOBJ_AllocateObject(UCHAR objt, ULONG cjSize, FLONG fl)
     pobj->BaseFlags = fl & 0xffff;
     DBG_INITLOG(&pobj->slhLog);
     DBG_LOGEVENT(&pobj->slhLog, EVENT_ALLOCATE, 0);
+#if DBG_ENABLE_GDIOBJ_BACKTRACES
+    DbgCaptureStackBackTace(pobj->apvBackTrace, 1, GDI_OBJECT_STACK_LEVELS);
+#endif /* GDI_DEBUG */
 
     return pobj;
 }
@@ -488,18 +597,27 @@ GDIOBJ_vFreeObject(POBJ pobj)
     /* Get the object type */
     objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0x1f;
 
-    /* Call the cleanup procedure */
-    ASSERT(apfnCleanup[objt]);
-    apfnCleanup[objt](pobj);
-
-    /* Check if the object is allocated from a lookaside list */
-    if (pobj->BaseFlags & BASEFLAG_LOOKASIDE)
+    /* Check if we have a delete procedure (for C++ based objects) */
+    if (apfnDelete[objt] != NULL)
     {
-        ExFreeToPagedLookasideList(&gpaLookasideList[objt], pobj);
+        /* Invoke the delete procedure */
+        apfnDelete[objt](pobj);
     }
     else
     {
-        ExFreePoolWithTag(pobj, GDIOBJ_POOL_TAG(objt));
+        /* Call the cleanup procedure */
+        NT_ASSERT(apfnCleanup[objt]);
+        apfnCleanup[objt](pobj);
+
+        /* Check if the object is allocated from a lookaside list */
+        if (pobj->BaseFlags & BASEFLAG_LOOKASIDE)
+        {
+            ExFreeToPagedLookasideList(&gpaLookasideList[objt], pobj);
+        }
+        else
+        {
+            ExFreePoolWithTag(pobj, GDIOBJ_POOL_TAG(objt));
+        }
     }
 }
 
@@ -516,6 +634,10 @@ GDIOBJ_vDereferenceObject(POBJ pobj)
     if (ulIndex)
     {
         /* Decrement reference count */
+        if ((gpaulRefCount[ulIndex] & REF_MASK_COUNT) == 0)
+        {
+            DBG_DUMP_EVENT_LIST(&pobj->slhLog);
+        }
         ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0);
         cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]);
         DBG_LOGEVENT(&pobj->slhLog, EVENT_DEREFERENCE, cRefs);
@@ -590,7 +712,7 @@ GDIOBJ_ReferenceObjectByHandle(
     /* Check if the object is exclusively locked */
     if (pobj->cExclusiveLock != 0)
     {
-        DPRINT1("GDIOBJ: Cannot reference oject %p with exclusive lock.\n", hobj);
+        DPRINT1("GDIOBJ: Cannot reference object %p with exclusive lock.\n", hobj);
         GDIOBJ_vDereferenceObject(pobj);
         DBG_DUMP_EVENT_LIST(&pobj->slhLog);
         return NULL;
@@ -643,6 +765,9 @@ GDIOBJ_TryLockObject(
         return NULL;
     }
 
+    /* Make sure lock order is correct */
+    ASSERT_LOCK_ORDER(objt);
+
     /* Reference the handle entry */
     pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
     if (!pentry)
@@ -684,7 +809,7 @@ GDIOBJ_TryLockObject(
 
     /* Increase lock count */
     pobj->cExclusiveLock++;
-    DBG_INCREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), hobj);
+    INCREASE_THREAD_LOCK_COUNT(hobj);
     DBG_LOGEVENT(&pobj->slhLog, EVENT_LOCK, 0);
 
     /* Return the object */
@@ -709,6 +834,9 @@ GDIOBJ_LockObject(
         return NULL;
     }
 
+    /* Make sure lock order is correct */
+    ASSERT_LOCK_ORDER(objt);
+
     /* Reference the handle entry */
     pentry = ENTRY_ReferenceEntryByHandle(hobj, 0);
     if (!pentry)
@@ -735,7 +863,7 @@ GDIOBJ_LockObject(
 
     /* Increase lock count */
     pobj->cExclusiveLock++;
-    DBG_INCREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), hobj);
+    INCREASE_THREAD_LOCK_COUNT(hobj);
     DBG_LOGEVENT(&pobj->slhLog, EVENT_LOCK, 0);
 
     /* Return the object */
@@ -751,7 +879,7 @@ GDIOBJ_vUnlockObject(POBJ pobj)
 
     /* Decrease lock count */
     pobj->cExclusiveLock--;
-    DBG_DECREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
+    DECREASE_THREAD_LOCK_COUNT(pobj->hHmgr);
     DBG_LOGEVENT(&pobj->slhLog, EVENT_UNLOCK, 0);
 
     /* Check if this was the last lock */
@@ -802,7 +930,7 @@ GDIOBJ_hInsertObject(
     ExAcquirePushLockExclusive(&pobj->pushlock);
     pobj->cExclusiveLock = 1;
     pobj->dwThreadId = PtrToUlong(PsGetCurrentThreadId());
-    DBG_INCREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
+    INCREASE_THREAD_LOCK_COUNT(pobj->hHmgr);
 
     /* Get object type from the hHmgr field */
     objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0xff;
@@ -1000,7 +1128,7 @@ GDIOBJ_vDeleteObject(POBJ pobj)
             /* Release the pushlock and reenable APCs */
             ExReleasePushLockExclusive(&pobj->pushlock);
             KeLeaveCriticalRegion();
-            DBG_DECREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), pobj->hHmgr);
+            DECREASE_THREAD_LOCK_COUNT(pobj->hHmgr);
         }
     }
 
@@ -1131,7 +1259,7 @@ NTAPI
 GreGetObject(
     IN HGDIOBJ hobj,
     IN INT cbCount,
-    IN PVOID pvBuffer)
+    OUT PVOID pvBuffer)
 {
     PVOID pvObj;
     UCHAR objt;
@@ -1246,6 +1374,15 @@ NtGdiCreateClientObj(
     POBJ pObject;
     HANDLE handle;
 
+    /* Check if ulType is valid */
+    if ((ulType != GDILoObjType_LO_METAFILE16_TYPE) &&
+        (ulType != GDILoObjType_LO_METAFILE_TYPE) &&
+        (ulType != GDILoObjType_LO_METADC16_TYPE))
+    {
+        DPRINT1("NtGdiCreateClientObj: Invalid object type 0x%lx.\n", ulType);
+        return NULL;
+    }
+
     /* Allocate a new object */
     pObject = GDIOBJ_AllocateObject(GDIObjType_CLIENTOBJ_TYPE,
                                     sizeof(CLIENTOBJ),
@@ -1256,9 +1393,6 @@ NtGdiCreateClientObj(
         return NULL;
     }
 
-    /* Mask out everything that would change the type in a wrong manner */
-    ulType &= (GDI_HANDLE_TYPE_MASK & ~GDI_HANDLE_BASETYPE_MASK);
-
     /* Set the real object type */
     pObject->hHmgr = UlongToHandle(ulType | GDILoObjType_LO_CLIENTOBJ_TYPE);
 
@@ -1381,7 +1515,7 @@ GDI_MapHandleTable(PEPROCESS pProcess)
     PVOID pvMappedView = NULL;
     NTSTATUS Status;
     LARGE_INTEGER liOffset;
-    ULONG cjViewSize = sizeof(GDI_HANDLE_TABLE);
+    SIZE_T cjViewSize = sizeof(GDI_HANDLE_TABLE);
 
     liOffset.QuadPart = 0;
 
@@ -1438,9 +1572,7 @@ GDI_CleanupForProcess(struct _EPROCESS *Process)
     }
 
 #if DBG
-//#ifdef GDI_DEBUG
-       DbgGdiHTIntegrityCheck();
-//#endif
+    DbgGdiHTIntegrityCheck();
 #endif
 
     ppi = PsGetCurrentProcessWin32Process();
@@ -1470,5 +1602,16 @@ GDI_CleanupForProcess(struct _EPROCESS *Process)
     return TRUE;
 }
 
+/// HACK!
+PGDI_POOL
+GetBrushAttrPool(VOID)
+{
+    PPROCESSINFO ppi;
+
+    ppi = PsGetCurrentProcessWin32Process();
+    NT_ASSERT(ppi != NULL);
+
+    return ppi->pPoolBrushAttr;
+}
 
 /* EOF */