Author: tkreuzer Date: Thu Jul 26 02:39:14 2007 New Revision: 27818
URL: http://svn.reactos.org/svn/reactos?rev=27818&view=rev Log: gdiobjects patch: - stockmask and reuse counter are stored in the lower 16 bits of the typeinfo field in the entry, not in the upper 16 bits! - take care of this when trying to lock an object (compare upper 16 bits of handle with lower 16 bits of typeinfo field) - some variable renaming - remove code duplication by moving debugoutput to an extra function - move checking for expected object type to a different location, should be removed completely later Fixes possible crashes if messing around with deleted / reused objects.
Modified: trunk/reactos/subsystems/win32/win32k/objects/gdiobj.c
Modified: trunk/reactos/subsystems/win32/win32k/objects/gdiobj.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/obj... ============================================================================== --- trunk/reactos/subsystems/win32/win32k/objects/gdiobj.c (original) +++ trunk/reactos/subsystems/win32/win32k/objects/gdiobj.c Thu Jul 26 02:39:14 2007 @@ -323,6 +323,33 @@ } #endif /* GDI_DEBUG */
+ +static void FASTCALL +LockErrorDebugOutput(HGDIOBJ hObj, PGDI_TABLE_ENTRY Entry, LPSTR Function) +{ + if (Entry->KernelData == NULL) + { + DPRINT1("%s: Attempted to lock object 0x%x that is deleted!\n", Function, hObj); + } + else if (GDI_HANDLE_GET_REUSECNT(hObj) != GDI_ENTRY_GET_REUSECNT(Entry->Type)) + { + DPRINT1("%s: Attempted to lock object 0x%x, wrong reuse counter (Handle: 0x%x, Entry: 0x%x)\n", + Function, hObj, GDI_HANDLE_GET_REUSECNT(hObj), GDI_ENTRY_GET_REUSECNT(Entry->Type)); + } + else if (GDI_HANDLE_GET_TYPE(hObj) != GDI_HANDLE_GET_TYPE(Entry->Type)) + { + DPRINT1("%s: Attempted to lock object 0x%x, type mismatch (Handle: 0x%x, Entry: 0x%x)\n", + Function, hObj, GDI_HANDLE_GET_TYPE(hObj), GDI_HANDLE_GET_TYPE(Entry->Type)); + } + else + { + DPRINT1("%s: Attempted to lock object 0x%x, something went wrong, typeinfo = 0x%x\n", + Function, hObj, Entry->Type); + } + KeRosDumpStackFrames(NULL, 20); + +} + /*! * Allocate memory for GDI object and return handle to it. * @@ -384,7 +411,10 @@
RtlZeroMemory(ObjectBody, GetObjectSize(ObjectType));
- TypeInfo = (ObjectType & GDI_HANDLE_TYPE_MASK) | (ObjectType >> 16); + /* FIXME: On Windows the higher 16 bit of the type field don't always match + the type from the handle, it is probably a storage type + (type = pen, storage = brush) */ + TypeInfo = (ObjectType & GDI_HANDLE_TYPE_MASK) | (ObjectType >> GDI_ENTRY_UPPER_SHIFT);
FreeEntry = InterlockedPopEntrySList(&HandleTable->FreeEntriesHead); if(FreeEntry != NULL) @@ -408,7 +438,7 @@ Entry->KernelData = ObjectBody;
/* copy the reuse-counter */ - TypeInfo |= Entry->Type & GDI_HANDLE_REUSE_MASK; + TypeInfo |= Entry->Type & GDI_ENTRY_REUSE_MASK;
/* we found a free entry, no need to exchange this field atomically since we're holding the lock */ @@ -426,7 +456,7 @@ { InterlockedIncrement(&W32Process->GDIObjects); } - Handle = (HGDIOBJ)((Index & 0xFFFF) | (TypeInfo & (GDI_HANDLE_TYPE_MASK | GDI_HANDLE_REUSE_MASK))); + Handle = (HGDIOBJ)((Index & 0xFFFF) | (TypeInfo << GDI_ENTRY_UPPER_SHIFT));
DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, ObjectBody); return Handle; @@ -478,15 +508,15 @@ */ BOOL INTERNAL_CALL #ifdef GDI_DEBUG -GDIOBJ_FreeObjDbg(PGDI_HANDLE_TABLE HandleTable, const char* file, int line, HGDIOBJ hObj, DWORD ObjectType) +GDIOBJ_FreeObjDbg(PGDI_HANDLE_TABLE HandleTable, const char* file, int line, HGDIOBJ hObj, DWORD ExpectedType) #else /* !GDI_DEBUG */ -GDIOBJ_FreeObj(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ObjectType) +GDIOBJ_FreeObj(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType) #endif /* GDI_DEBUG */ { PGDI_TABLE_ENTRY Entry; PPAGED_LOOKASIDE_LIST LookasideList; HANDLE ProcessId, LockedProcessId, PrevProcId; - LONG ExpectedType; + ULONG HandleType, HandleUpper; BOOL Silent; #ifdef GDI_DEBUG ULONG Attempts = 0; @@ -506,10 +536,21 @@ ProcessId = PsGetCurrentProcessId(); LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
- Silent = (ObjectType & GDI_OBJECT_TYPE_SILENT); - ObjectType &= ~GDI_OBJECT_TYPE_SILENT; - - ExpectedType = ((ObjectType != GDI_OBJECT_TYPE_DONTCARE) ? ObjectType : 0); + Silent = (ExpectedType & GDI_OBJECT_TYPE_SILENT); + ExpectedType &= ~GDI_OBJECT_TYPE_SILENT; + + HandleType = GDI_HANDLE_GET_TYPE(hObj); + HandleUpper = GDI_HANDLE_GET_UPPER(hObj); + + /* Check if we have the requested type */ + if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE && + HandleType != ExpectedType) || + HandleType == 0 ) + { + DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n", + hObj, HandleType, ExpectedType); + return FALSE; + }
Entry = GDI_HANDLE_GET_ENTRY(HandleTable, hObj);
@@ -519,10 +560,8 @@ PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, ProcessId); if(PrevProcId == ProcessId) { - if(Entry->Type != 0 && Entry->KernelData != NULL && - (ExpectedType == 0 || ((Entry->Type << 16) == ExpectedType)) && - (Entry->Type & (GDI_HANDLE_TYPE_MASK | GDI_HANDLE_REUSE_MASK)) == - ((ULONG_PTR)hObj & (GDI_HANDLE_TYPE_MASK | GDI_HANDLE_REUSE_MASK))) + if( (Entry->KernelData != NULL) && + ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) ) { PGDIOBJHDR GdiHdr;
@@ -532,10 +571,9 @@ { BOOL Ret; PW32PROCESS W32Process = PsGetCurrentProcessWin32Process(); - ULONG Type = Entry->Type << 16;
/* Clear the type field so when unlocking the handle it gets finally deleted and increment reuse counter */ - Entry->Type = ((Entry->Type >> GDI_HANDLE_REUSECNT_SHIFT) + 1) << GDI_HANDLE_REUSECNT_SHIFT; + Entry->Type = (Entry->Type + GDI_ENTRY_REUSE_INC) & GDI_ENTRY_REUSE_MASK; Entry->KernelData = NULL;
/* unlock the handle slot */ @@ -551,10 +589,10 @@ }
/* call the cleanup routine. */ - Ret = RunCleanupCallback(GDIHdrToBdy(GdiHdr), Type); + Ret = RunCleanupCallback(GDIHdrToBdy(GdiHdr), HandleType);
/* Now it's time to free the memory */ - LookasideList = FindLookasideList(HandleTable, Type); + LookasideList = FindLookasideList(HandleTable, HandleType); if(LookasideList != NULL) { ExFreeToPagedLookasideList(LookasideList, GdiHdr); @@ -576,16 +614,7 @@ } else { - if((Entry->Type & ~GDI_HANDLE_REUSE_MASK) != 0) - { - DPRINT1("Attempted to delete object 0x%x, type mismatch (0x%x : 0x%x)\n", hObj, ObjectType, ExpectedType); - KeRosDumpStackFrames(NULL, 20); - } - else - { - DPRINT1("Attempted to delete object 0x%x which was already deleted!\n", hObj); - KeRosDumpStackFrames(NULL, 20); - } + LockErrorDebugOutput(hObj, Entry, "GDIOBJ_FreeObj"); (void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId); } } @@ -678,11 +707,11 @@ { HGDIOBJ ObjectHandle;
- /* Create the object handle for the entry, the upper 16 bit of the + /* Create the object handle for the entry, the lower(!) 16 bit of the Type field includes the type of the object including the stock object flag - but since stock objects don't have a process id we can simply ignore this fact here. */ - ObjectHandle = (HGDIOBJ)(Index | (Entry->Type & 0xFFFF0000)); + ObjectHandle = (HGDIOBJ)(Index | (Entry->Type << GDI_ENTRY_UPPER_SHIFT));
if(GDIOBJ_FreeObj(HandleTable, ObjectHandle, GDI_OBJECT_TYPE_DONTCARE) && W32Process->GDIObjects == 0) @@ -712,30 +741,43 @@ * * \note Process can only get pointer to the objects it created or global objects. * - * \todo Get rid of the ObjectType parameter! + * \todo Get rid of the ExpectedType parameter! */ PGDIOBJ INTERNAL_CALL #ifdef GDI_DEBUG -GDIOBJ_LockObjDbg (PGDI_HANDLE_TABLE HandleTable, const char* file, int line, HGDIOBJ hObj, DWORD ObjectType) +GDIOBJ_LockObjDbg (PGDI_HANDLE_TABLE HandleTable, const char* file, int line, HGDIOBJ hObj, DWORD ExpectedType) #else /* !GDI_DEBUG */ -GDIOBJ_LockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ObjectType) +GDIOBJ_LockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType) #endif /* GDI_DEBUG */ { USHORT HandleIndex; - PGDI_TABLE_ENTRY HandleEntry; + PGDI_TABLE_ENTRY Entry; HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId; PGDIOBJ Object = NULL; + ULONG HandleType, HandleUpper;
HandleIndex = GDI_HANDLE_GET_INDEX(hObj); + HandleType = GDI_HANDLE_GET_TYPE(hObj); + HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
/* Check that the handle index is valid. */ if (HandleIndex >= GDI_HANDLE_COUNT) return NULL;
- HandleEntry = &HandleTable->Entries[HandleIndex]; + Entry = &HandleTable->Entries[HandleIndex]; + + /* Check if we have the requested type */ + if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE && + HandleType != ExpectedType) || + HandleType == 0 ) + { + DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n", + hObj, HandleType, ExpectedType); + return NULL; + }
ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1); - HandleProcessId = (HANDLE)((ULONG_PTR)HandleEntry->ProcessId & ~1); + HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
/* Check for invalid owner. */ if (ProcessId != HandleProcessId && HandleProcessId != NULL) @@ -760,25 +802,21 @@ { /* Lock the handle table entry. */ LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1); - PrevProcId = InterlockedCompareExchangePointer(&HandleEntry->ProcessId, + PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, HandleProcessId);
if (PrevProcId == HandleProcessId) { - LONG HandleType = HandleEntry->Type << 16; - /* * We're locking an object that belongs to our process or it's a * global object if HandleProcessId is 0 here. */
- /* FIXME: Check the upper 16-bits of handle number! */ - if (HandleType != 0 && HandleEntry->KernelData != NULL && - (ObjectType == GDI_OBJECT_TYPE_DONTCARE || - HandleType == ObjectType)) + if ( (Entry->KernelData != NULL) && + ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) ) { - PGDIOBJHDR GdiHdr = GDIBdyToHdr(HandleEntry->KernelData); + PGDIOBJHDR GdiHdr = GDIBdyToHdr(Entry->KernelData); PETHREAD Thread = PsGetCurrentThread();
if (GdiHdr->Locks == 0) @@ -789,7 +827,7 @@ GdiHdr->lockfile = file; GdiHdr->lockline = line; #endif - Object = HandleEntry->KernelData; + Object = Entry->KernelData; } else { @@ -799,12 +837,12 @@ InterlockedDecrement((PLONG)&GdiHdr->Locks);
/* Unlock the handle table entry. */ - (void)InterlockedExchangePointer(&HandleEntry->ProcessId, PrevProcId); + (void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
DelayExecution(); continue; } - Object = HandleEntry->KernelData; + Object = Entry->KernelData; } } else @@ -813,26 +851,15 @@ * Debugging code. Report attempts to lock deleted handles and * locking type mismatches. */ - - if ((HandleType & ~GDI_HANDLE_REUSE_MASK) == 0) - { - DPRINT1("Attempted to lock object 0x%x that is deleted!\n", hObj); - KeRosDumpStackFrames(NULL, 20); - } - else - { - DPRINT1("Attempted to lock object 0x%x, type mismatch (0x%x : 0x%x)\n", - hObj, HandleType & ~GDI_HANDLE_REUSE_MASK, ObjectType & ~GDI_HANDLE_REUSE_MASK); - - KeRosDumpStackFrames(NULL, 20); - } + LockErrorDebugOutput(hObj, Entry, "GDIOBJ_LockObj"); + #ifdef GDI_DEBUG DPRINT1("-> called from %s:%i\n", file, line); #endif }
/* Unlock the handle table entry. */ - (void)InterlockedExchangePointer(&HandleEntry->ProcessId, PrevProcId); + (void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
break; } @@ -862,30 +889,43 @@ * * \note Process can only get pointer to the objects it created or global objects. * - * \todo Get rid of the ObjectType parameter! + * \todo Get rid of the ExpectedType parameter! */ PGDIOBJ INTERNAL_CALL #ifdef GDI_DEBUG -GDIOBJ_ShareLockObjDbg (PGDI_HANDLE_TABLE HandleTable, const char* file, int line, HGDIOBJ hObj, DWORD ObjectType) +GDIOBJ_ShareLockObjDbg (PGDI_HANDLE_TABLE HandleTable, const char* file, int line, HGDIOBJ hObj, DWORD ExpectedType) #else /* !GDI_DEBUG */ -GDIOBJ_ShareLockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ObjectType) +GDIOBJ_ShareLockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType) #endif /* GDI_DEBUG */ { USHORT HandleIndex; - PGDI_TABLE_ENTRY HandleEntry; + PGDI_TABLE_ENTRY Entry; HANDLE ProcessId, HandleProcessId, LockedProcessId, PrevProcId; PGDIOBJ Object = NULL; + ULONG_PTR HandleType, HandleUpper;
HandleIndex = GDI_HANDLE_GET_INDEX(hObj); + HandleType = GDI_HANDLE_GET_TYPE(hObj); + HandleUpper = GDI_HANDLE_GET_UPPER(hObj);
/* Check that the handle index is valid. */ if (HandleIndex >= GDI_HANDLE_COUNT) return NULL;
- HandleEntry = &HandleTable->Entries[HandleIndex]; + /* Check if we have the requested type */ + if ( (ExpectedType != GDI_OBJECT_TYPE_DONTCARE && + HandleType != ExpectedType) || + HandleType == 0 ) + { + DPRINT1("Attempted to lock object 0x%x of wrong type (Handle: 0x%x, requested: 0x%x)\n", + hObj, HandleType, ExpectedType); + return NULL; + } + + Entry = &HandleTable->Entries[HandleIndex];
ProcessId = (HANDLE)((ULONG_PTR)PsGetCurrentProcessId() & ~1); - HandleProcessId = (HANDLE)((ULONG_PTR)HandleEntry->ProcessId & ~1); + HandleProcessId = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~1);
/* Check for invalid owner. */ if (ProcessId != HandleProcessId && HandleProcessId != NULL) @@ -910,25 +950,21 @@ { /* Lock the handle table entry. */ LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1); - PrevProcId = InterlockedCompareExchangePointer(&HandleEntry->ProcessId, + PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, HandleProcessId);
if (PrevProcId == HandleProcessId) { - LONG HandleType = HandleEntry->Type << 16; - /* * We're locking an object that belongs to our process or it's a * global object if HandleProcessId is 0 here. */
- /* FIXME: Check the upper 16-bits of handle number! */ - if (HandleType != 0 && HandleEntry->KernelData != NULL && - (ObjectType == GDI_OBJECT_TYPE_DONTCARE || - HandleType == ObjectType)) + if ( (Entry->KernelData != NULL) && + (HandleUpper == (Entry->Type << GDI_ENTRY_UPPER_SHIFT)) ) { - PGDIOBJHDR GdiHdr = GDIBdyToHdr(HandleEntry->KernelData); + PGDIOBJHDR GdiHdr = GDIBdyToHdr(Entry->KernelData);
#ifdef GDI_DEBUG if (InterlockedIncrement((PLONG)&GdiHdr->Locks) == 1) @@ -939,7 +975,7 @@ #else InterlockedIncrement((PLONG)&GdiHdr->Locks); #endif - Object = HandleEntry->KernelData; + Object = Entry->KernelData; } else { @@ -947,26 +983,15 @@ * Debugging code. Report attempts to lock deleted handles and * locking type mismatches. */ - - if ((HandleType & ~GDI_HANDLE_REUSE_MASK) == 0) - { - DPRINT1("Attempted to lock object 0x%x that is deleted!\n", hObj); - KeRosDumpStackFrames(NULL, 20); - } - else - { - DPRINT1("Attempted to lock object 0x%x, type mismatch (0x%x : 0x%x)\n", - hObj, HandleType & ~GDI_HANDLE_REUSE_MASK, ObjectType & ~GDI_HANDLE_REUSE_MASK); - - KeRosDumpStackFrames(NULL, 20); - } + LockErrorDebugOutput(hObj, Entry, "GDIOBJ_ShareLockObj"); + #ifdef GDI_DEBUG DPRINT1("-> called from %s:%i\n", file, line); #endif }
/* Unlock the handle table entry. */ - (void)InterlockedExchangePointer(&HandleEntry->ProcessId, PrevProcId); + (void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
break; } @@ -1069,14 +1094,16 @@ /* we're locking an object that belongs to our process. First calculate the new object type including the stock object flag and then try to exchange it.*/ + /* FIXME: On Windows the higher 16 bit of the type field don't always match + the type from the handle, it is probably a storage type + (type = pen, storage = brush) */ NewType = GDI_HANDLE_GET_TYPE(*hObj); - NewType |= NewType >> 16; - NewType |= (ULONG_PTR)(*hObj) & GDI_HANDLE_REUSE_MASK; + NewType |= GDI_HANDLE_GET_UPPER(*hObj) >> GDI_ENTRY_UPPER_SHIFT;
/* This is the type that the object should have right now, save it */ OldType = NewType; - /* As the object should be a stock object, set it's flag, but only in the upper 16 bits */ - NewType |= GDI_HANDLE_STOCK_MASK; + /* As the object should be a stock object, set it's flag, but only in the lower 16 bits */ + NewType |= GDI_ENTRY_STOCK_MASK;
/* Try to exchange the type field - but only if the old (previous type) matches! */ PrevType = InterlockedCompareExchange(&Entry->Type, NewType, OldType); @@ -1198,7 +1225,7 @@ { PETHREAD PrevThread;
- if((Entry->Type & ~GDI_HANDLE_REUSE_MASK) != 0 && Entry->KernelData != NULL) + if((Entry->Type & ~GDI_ENTRY_REUSE_MASK) != 0 && Entry->KernelData != NULL) { PGDIOBJHDR GdiHdr = GDIBdyToHdr(Entry->KernelData);
@@ -1334,7 +1361,7 @@ PETHREAD PrevThread; PGDIOBJHDR GdiHdr;
- if((FromEntry->Type & ~GDI_HANDLE_REUSE_MASK) != 0 && FromEntry->KernelData != NULL) + if((FromEntry->Type & ~GDI_ENTRY_REUSE_MASK) != 0 && FromEntry->KernelData != NULL) { GdiHdr = GDIBdyToHdr(FromEntry->KernelData);