⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gdiobj.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 4 页
字号:
  /* HACK HACK HACK: simplest-possible quota implementation - don't allow a process
     to take too many GDI objects, itself. */
  if ( W32Process && W32Process->GDIObjects >= 0x2710 )
    return NULL;

  ASSERT(ObjectType != GDI_OBJECT_TYPE_DONTCARE);

  LookasideList = FindLookasideList(HandleTable, ObjectType);
  if(LookasideList != NULL)
  {
    newObject = ExAllocateFromPagedLookasideList(LookasideList);
    if(newObject != NULL)
    {
      PSLIST_ENTRY FreeEntry;
      PGDI_TABLE_ENTRY Entry;
      PGDIOBJ ObjectBody;
      LONG TypeInfo;

      CurrentProcessId = PsGetCurrentProcessId();
      LockedProcessId = (HANDLE)((ULONG_PTR)CurrentProcessId | 0x1);

      newObject->LockingThread = NULL;
      newObject->Locks = 0;

#ifdef GDI_DEBUG
      newObject->createdfile = file;
      newObject->createdline = line;
      newObject->lockfile = NULL;
      newObject->lockline = 0;
#endif

      ObjectBody = GDIHdrToBdy(newObject);

      RtlZeroMemory(ObjectBody, GetObjectSize(ObjectType));

      /* 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)
      {
        HANDLE PrevProcId;
        UINT Index;

        /* calculate the entry from the address of the entry in the free slot array */
        Index = ((ULONG_PTR)FreeEntry - (ULONG_PTR)&HandleTable->FreeEntries[0]) /
                sizeof(HandleTable->FreeEntries[0]);
        Entry = &HandleTable->Entries[Index];

LockHandle:
        PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, 0);
        if(PrevProcId == NULL)
        {
          HGDIOBJ Handle;

          ASSERT(Entry->KernelData == NULL);

          Entry->KernelData = ObjectBody;

          /* copy the reuse-counter */
          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 */
          Entry->Type = TypeInfo;

          /* unlock the entry */
          (void)InterlockedExchangePointer(&Entry->ProcessId, CurrentProcessId);

#ifdef GDI_DEBUG
          memset ( GDIHandleAllocator[Index], 0xcd, GDI_STACK_LEVELS * sizeof(ULONG) );
          KeRosGetStackFrames ( GDIHandleAllocator[Index], GDI_STACK_LEVELS );
#endif /* GDI_DEBUG */

          if(W32Process != NULL)
          {
            InterlockedIncrement(&W32Process->GDIObjects);
          }
          Handle = (HGDIOBJ)((Index & 0xFFFF) | (TypeInfo << GDI_ENTRY_UPPER_SHIFT));

          DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, ObjectBody);
          return Handle;
        }
        else
        {
#ifdef GDI_DEBUG
          if(++Attempts > 20)
          {
            DPRINT1("[%d]Waiting on handle in index 0x%x\n", Attempts, Index);
          }
#endif
          /* damn, someone is trying to lock the object even though it doesn't
             eve nexist anymore, wait a little and try again!
             FIXME - we shouldn't loop forever! Give up after some time! */
          DelayExecution();
          /* try again */
          goto LockHandle;
        }
      }

      ExFreeToPagedLookasideList(LookasideList, newObject);
      DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
#ifdef GDI_DEBUG
      IntDumpHandleTable(HandleTable);
#endif /* GDI_DEBUG */
    }
    else
    {
      DPRINT1("Not enough memory to allocate gdi object!\n");
    }
  }
  else
  {
    DPRINT1("Failed to find lookaside list for object type 0x%x\n", ObjectType);
  }
  return NULL;
}

/*!
 * Free memory allocated for the GDI object. For each object type this function calls the
 * appropriate cleanup routine.
 *
 * \param hObj       - handle of the object to be deleted.
 *
 * \return Returns TRUE if succesful.
 * \return Returns FALSE if the cleanup routine returned FALSE or the object doesn't belong
 * to the calling process.
*/
BOOL INTERNAL_CALL
#ifdef GDI_DEBUG
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 ExpectedType)
#endif /* GDI_DEBUG */
{
  PGDI_TABLE_ENTRY Entry;
  PPAGED_LOOKASIDE_LIST LookasideList;
  HANDLE ProcessId, LockedProcessId, PrevProcId;
  ULONG HandleType, HandleUpper;
  BOOL Silent;
#ifdef GDI_DEBUG
  ULONG Attempts = 0;
#endif

  DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj);

  if(GDI_HANDLE_IS_STOCKOBJ(hObj))
  {
    DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj);
#ifdef GDI_DEBUG
    DPRINT1("-> called from %s:%i\n", file, line);
#endif
    return FALSE;
  }

  ProcessId = PsGetCurrentProcessId();
  LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);

  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);

LockHandle:
  /* lock the object, we must not delete global objects, so don't exchange the locking
     process ID to zero when attempting to lock a global object... */
  PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, ProcessId);
  if(PrevProcId == ProcessId)
  {
    if( (Entry->KernelData != NULL) &&
        ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) )
    {
      PGDIOBJHDR GdiHdr;

      GdiHdr = GDIBdyToHdr(Entry->KernelData);

      if(GdiHdr->Locks == 0)
      {
        BOOL Ret;
        PW32PROCESS W32Process = PsGetCurrentProcessWin32Process();

        /* Clear the type field so when unlocking the handle it gets finally deleted and increment reuse counter */
        Entry->Type = (Entry->Type + GDI_ENTRY_REUSE_INC) & GDI_ENTRY_REUSE_MASK;
        Entry->KernelData = NULL;

        /* unlock the handle slot */
        (void)InterlockedExchangePointer(&Entry->ProcessId, NULL);

        /* push this entry to the free list */
        InterlockedPushEntrySList(&HandleTable->FreeEntriesHead,
                                  &HandleTable->FreeEntries[GDI_ENTRY_TO_INDEX(HandleTable, Entry)]);

        if(W32Process != NULL)
        {
          InterlockedDecrement(&W32Process->GDIObjects);
        }

        /* call the cleanup routine. */
        Ret = RunCleanupCallback(GDIHdrToBdy(GdiHdr), HandleType);

        /* Now it's time to free the memory */
        LookasideList = FindLookasideList(HandleTable, HandleType);
        if(LookasideList != NULL)
        {
          ExFreeToPagedLookasideList(LookasideList, GdiHdr);
        }

        return Ret;
      }
      else
      {
        /*
         * The object is currently locked, so freeing is forbidden!
         */
        DPRINT1("GdiHdr->Locks: %d\n", GdiHdr->Locks);
#ifdef GDI_DEBUG
        DPRINT1("Locked from: %s:%d\n", GdiHdr->lockfile, GdiHdr->lockline);
#endif
        ASSERT(FALSE);
      }
    }
    else
    {
      LockErrorDebugOutput(hObj, Entry, "GDIOBJ_FreeObj");
      (void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
    }
  }
  else if(PrevProcId == LockedProcessId)
  {
#ifdef GDI_DEBUG
    if(++Attempts > 20)
    {
      DPRINT1("[%d]Waiting on 0x%x\n", Attempts, hObj);
    }
#endif
    /* the object is currently locked, wait some time and try again.
       FIXME - we shouldn't loop forever! Give up after some time! */
    DelayExecution();
    /* try again */
    goto LockHandle;
  }
  else
  {
    if(!Silent)
    {
      if(((ULONG_PTR)PrevProcId & ~0x1) == 0)
      {
        DPRINT1("Attempted to free global gdi handle 0x%x, caller needs to get ownership first!!!\n", hObj);
        KeRosDumpStackFrames(NULL, 20);
      }
      else
      {
        DPRINT1("Attempted to free foreign handle: 0x%x Owner: 0x%x from Caller: 0x%x\n", hObj, (ULONG_PTR)PrevProcId & ~0x1, (ULONG_PTR)ProcessId & ~0x1);
        KeRosDumpStackFrames(NULL, 20);
      }
#ifdef GDI_DEBUG
      DPRINT1("-> called from %s:%i\n", file, line);
#endif
    }
  }

  return FALSE;
}

/*!
 * Delete GDI object
 * \param	hObject object handle
 * \return	if the function fails the returned value is FALSE.
*/
BOOL STDCALL
NtGdiDeleteObject(HGDIOBJ hObject)
{
  DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject);

  return NULL != hObject
         ? GDIOBJ_FreeObj(GdiHandleTable, hObject, GDI_OBJECT_TYPE_DONTCARE) : FALSE;
}

/*!
 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
 * \param	Process - PID of the process that will be destroyed.
*/
BOOL INTERNAL_CALL
GDI_CleanupForProcess (PGDI_HANDLE_TABLE HandleTable, struct _EPROCESS *Process)
{
  PGDI_TABLE_ENTRY Entry, End;
  PEPROCESS CurrentProcess;
  PW32PROCESS W32Process;
  HANDLE ProcId;
  ULONG Index = RESERVE_ENTRIES_COUNT;

  DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process, Process->UniqueProcessId);
  CurrentProcess = PsGetCurrentProcess();
  if (CurrentProcess != Process)
    {
      KeAttachProcess(&Process->Pcb);
    }
  W32Process = (PW32PROCESS)Process->Win32Process;
  ASSERT(W32Process);

  if(W32Process->GDIObjects > 0)
  {
    /* FIXME - Instead of building the handle here and delete it using GDIOBJ_FreeObj
               we should delete it directly here! */
    ProcId = Process->UniqueProcessId;

    End = &HandleTable->Entries[GDI_HANDLE_COUNT];
    for(Entry = &HandleTable->Entries[RESERVE_ENTRIES_COUNT];
        Entry != End;
        Entry++, Index++)
    {
      /* ignore the lock bit */
      if((HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcId && (Entry->Type & ~GDI_HANDLE_REUSE_MASK) != 0)
      {
        HGDIOBJ ObjectHandle;

        /* 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 << GDI_ENTRY_UPPER_SHIFT));

        if(GDIOBJ_FreeObj(HandleTable, ObjectHandle, GDI_OBJECT_TYPE_DONTCARE) &&
           W32Process->GDIObjects == 0)
        {
          /* there are no more gdi handles for this process, bail */
          break;
        }
      }
    }
  }

  if (CurrentProcess != Process)
    {
      KeDetachProcess();
    }

  DPRINT("Completed cleanup for process %d\n", Process->UniqueProcessId);

  return TRUE;
}

/*!
 * Return pointer to the object by handle.
 *
 * \param hObj 		Object handle
 * \return		Pointer to the object.
 *
 * \note Process can only get pointer to the objects it created or global objects.
 *
 * \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 ExpectedType)
#else /* !GDI_DEBUG */
GDIOBJ_LockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType)
#endif /* GDI_DEBUG */
{
   USHORT HandleIndex;
   PGDI_TABLE_ENTRY Entry;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -