}
}
+VOID
+NTAPI
+ExpCheckPoolAllocation(
+ PVOID P,
+ POOL_TYPE PoolType,
+ ULONG Tag)
+{
+ PPOOL_HEADER Entry;
+ ULONG i;
+ KIRQL OldIrql;
+ POOL_TYPE RealPoolType;
+
+ /* Get the pool header */
+ Entry = ((PPOOL_HEADER)P) - 1;
+
+ /* Check if this is a large allocation */
+ if (PAGE_ALIGN(P) == P)
+ {
+ /* Lock the pool table */
+ KeAcquireSpinLock(&ExpLargePoolTableLock, &OldIrql);
+
+ /* Find the pool tag */
+ for (i = 0; i < PoolBigPageTableSize; i++)
+ {
+ /* Check if this is our allocation */
+ if (PoolBigPageTable[i].Va == P)
+ {
+ /* Make sure the tag is ok */
+ if (PoolBigPageTable[i].Key != Tag)
+ {
+ KeBugCheckEx(BAD_POOL_CALLER, 0x0A, (ULONG_PTR)P, PoolBigPageTable[i].Key, Tag);
+ }
+
+ break;
+ }
+ }
+
+ /* Release the lock */
+ KeReleaseSpinLock(&ExpLargePoolTableLock, OldIrql);
+
+ if (i == PoolBigPageTableSize)
+ {
+ /* Did not find the allocation */
+ //ASSERT(FALSE);
+ }
+
+ /* Get Pool type by address */
+ RealPoolType = MmDeterminePoolType(P);
+ }
+ else
+ {
+ /* Verify the tag */
+ if (Entry->PoolTag != Tag)
+ {
+ DPRINT1("Allocation has wrong pool tag! Expected '%.4s', got '%.4s' (0x%08lx)\n",
+ &Tag, &Entry->PoolTag, Entry->PoolTag);
+ KeBugCheckEx(BAD_POOL_CALLER, 0x0A, (ULONG_PTR)P, Entry->PoolTag, Tag);
+ }
+
+ /* Check the rest of the header */
+ ExpCheckPoolHeader(Entry);
+
+ /* Get Pool type from entry */
+ RealPoolType = (Entry->PoolType - 1);
+ }
+
+ /* Should we check the pool type? */
+ if (PoolType != -1)
+ {
+ /* Verify the pool type */
+ if (RealPoolType != PoolType)
+ {
+ DPRINT1("Wrong pool type! Expected %s, got %s\n",
+ PoolType & BASE_POOL_TYPE_MASK ? "PagedPool" : "NonPagedPool",
+ (Entry->PoolType - 1) & BASE_POOL_TYPE_MASK ? "PagedPool" : "NonPagedPool");
+ KeBugCheckEx(BAD_POOL_CALLER, 0xCC, (ULONG_PTR)P, Entry->PoolTag, Tag);
+ }
+ }
+}
+
VOID
NTAPI
ExpCheckPoolBlocks(IN PVOID Block)
Table = PoolTrackTable;
TableMask = PoolTrackTableMask;
TableSize = PoolTrackTableSize;
+ DBG_UNREFERENCED_LOCAL_VARIABLE(TableSize);
//
// Compute the hash for this key, and loop all the possible buckets
//
if (!TableEntry->Key)
{
- DPRINT1("Empty item reached in tracker table. Tag=0x%08lx, NumberOfBytes=%lu, PoolType=%d\n",
- Key, (ULONG)NumberOfBytes, PoolType);
+ DPRINT1("Empty item reached in tracker table. Hash=0x%lx, TableMask=0x%lx, Tag=0x%08lx, NumberOfBytes=%lu, PoolType=%d\n",
+ Hash, TableMask, Key, (ULONG)NumberOfBytes, PoolType);
ASSERT(Hash == TableMask);
}
Table = PoolTrackTable;
TableMask = PoolTrackTableMask;
TableSize = PoolTrackTableSize;
+ DBG_UNREFERENCED_LOCAL_VARIABLE(TableSize);
//
// Compute the hash for this key, and loop all the possible buckets
//
// During development, print this out so we can see what's happening
//
- DPRINT1("EXPOOL: Pool Tracker Table at: 0x%p with 0x%lx bytes\n",
+ DPRINT("EXPOOL: Pool Tracker Table at: 0x%p with 0x%lx bytes\n",
PoolTrackTable, PoolTrackTableSize * sizeof(POOL_TRACKER_TABLE));
- DPRINT1("EXPOOL: Big Pool Tracker Table at: 0x%p with 0x%lx bytes\n",
+ DPRINT("EXPOOL: Big Pool Tracker Table at: 0x%p with 0x%lx bytes\n",
PoolBigPageTable, PoolBigPageTableSize * sizeof(POOL_TRACKER_BIG_PAGES));
//
InterlockedIncrementUL(&ExpPoolBigEntriesInUse);
if ((i >= 16) && (ExpPoolBigEntriesInUse > (TableSize / 4)))
{
- DPRINT1("Should attempt expansion since we now have %lu entries\n",
+ DPRINT("Should attempt expansion since we now have %lu entries\n",
ExpPoolBigEntriesInUse);
}
//
if (ExpPoolFlags & POOL_FLAG_DBGPRINT_ON_FAILURE)
{
- DPRINT1("EX: ExAllocatePool (%p, 0x%x) returning NULL\n",
+ DPRINT1("EX: ExAllocatePool (%lu, 0x%x) returning NULL\n",
NumberOfBytes,
OriginalType);
if (ExpPoolFlags & POOL_FLAG_CRASH_ON_FAILURE) DbgBreakPoint();
//
// Handle lookaside list optimization for both paged and nonpaged pool
//
- if (i <= MAXIMUM_PROCESSORS)
+ if (i <= NUMBER_POOL_LOOKASIDE_LISTS)
{
//
// Try popping it from the per-CPU lookaside list
// Get the real entry, write down its pool type, and track it
//
Entry--;
- Entry->PoolType = PoolType + 1;
+ Entry->PoolType = OriginalType + 1;
ExpInsertPoolTracker(Tag,
Entry->BlockSize * POOL_BLOCK_SIZE,
OriginalType);
// We have found an entry for this allocation, so set the pool type
// and release the lock since we're done
//
- Entry->PoolType = PoolType + 1;
+ Entry->PoolType = OriginalType + 1;
ExpCheckPoolBlocks(Entry);
ExUnlockPool(PoolDesc, OldIrql);
//
// There were no free entries left, so we have to allocate a new fresh page
//
- Entry = MiAllocatePoolPages(PoolType, PAGE_SIZE);
+ Entry = MiAllocatePoolPages(OriginalType, PAGE_SIZE);
if (!Entry)
{
//
//
if (ExpPoolFlags & POOL_FLAG_DBGPRINT_ON_FAILURE)
{
- DPRINT1("EX: ExAllocatePool (%p, 0x%x) returning NULL\n",
+ DPRINT1("EX: ExAllocatePool (%lu, 0x%x) returning NULL\n",
NumberOfBytes,
OriginalType);
if (ExpPoolFlags & POOL_FLAG_CRASH_ON_FAILURE) DbgBreakPoint();
//
Entry->Ulong1 = 0;
Entry->BlockSize = i;
- Entry->PoolType = PoolType + 1;
+ Entry->PoolType = OriginalType + 1;
//
// This page will have two entries -- one for the allocation (which we just
InterlockedIncrement((PLONG)&PoolDesc->RunningAllocs);
ExpInsertPoolTracker(Tag,
Entry->BlockSize * POOL_BLOCK_SIZE,
- PoolType);
+ OriginalType);
//
// And return the pool allocation
PFN_NUMBER PageCount, RealPageCount;
PKPRCB Prcb = KeGetCurrentPrcb();
PGENERAL_LOOKASIDE LookasideList;
+ PEPROCESS Process;
//
// Check if any of the debug flags are enabled
BlockSize * POOL_BLOCK_SIZE,
Entry->PoolType - 1);
+ //
+ // Release pool quota, if any
+ //
+ if ((Entry->PoolType - 1) & QUOTA_POOL_MASK)
+ {
+ Process = ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1];
+ ASSERT(Process != NULL);
+ if (Process)
+ {
+ if (Process->Pcb.Header.Type != ProcessObject)
+ {
+ DPRINT1("Object %p is not a process. Type %u, pool type 0x%x, block size %u\n",
+ Process, Process->Pcb.Header.Type, Entry->PoolType, BlockSize);
+ KeBugCheckEx(BAD_POOL_CALLER,
+ 0x0D,
+ (ULONG_PTR)P,
+ Tag,
+ (ULONG_PTR)Process);
+ }
+ PsReturnPoolQuota(Process, PoolType, BlockSize * POOL_BLOCK_SIZE);
+ ObDereferenceObject(Process);
+ }
+ }
+
//
// Is this allocation small enough to have come from a lookaside list?
//
- if (BlockSize <= MAXIMUM_PROCESSORS)
+ if (BlockSize <= NUMBER_POOL_LOOKASIDE_LISTS)
{
//
// Try pushing it into the per-CPU lookaside list
IN SIZE_T NumberOfBytes,
IN ULONG Tag)
{
+ BOOLEAN Raise = TRUE;
+ PVOID Buffer;
+ PPOOL_HEADER Entry;
+ NTSTATUS Status;
+ PEPROCESS Process = PsGetCurrentProcess();
+
//
- // Allocate the pool
+ // Check if we should fail instead of raising an exception
//
- UNIMPLEMENTED;
- return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
+ if (PoolType & POOL_QUOTA_FAIL_INSTEAD_OF_RAISE)
+ {
+ Raise = FALSE;
+ PoolType &= ~POOL_QUOTA_FAIL_INSTEAD_OF_RAISE;
+ }
+
+ //
+ // Inject the pool quota mask
+ //
+ PoolType += QUOTA_POOL_MASK;
+
+ //
+ // Check if we have enough space to add the quota owner process, as long as
+ // this isn't the system process, which never gets charged quota
+ //
+ ASSERT(NumberOfBytes != 0);
+ if ((NumberOfBytes <= (PAGE_SIZE - POOL_BLOCK_SIZE - sizeof(PVOID))) &&
+ (Process != PsInitialSystemProcess))
+ {
+ //
+ // Add space for our EPROCESS pointer
+ //
+ NumberOfBytes += sizeof(PEPROCESS);
+ }
+ else
+ {
+ //
+ // We won't be able to store the pointer, so don't use quota for this
+ //
+ PoolType -= QUOTA_POOL_MASK;
+ }
+
+ //
+ // Allocate the pool buffer now
+ //
+ Buffer = ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
+
+ //
+ // If the buffer is page-aligned, this is a large page allocation and we
+ // won't touch it
+ //
+ if (PAGE_ALIGN(Buffer) != Buffer)
+ {
+ //
+ // Also if special pool is enabled, and this was allocated from there,
+ // we won't touch it either
+ //
+ if ((ExpPoolFlags & POOL_FLAG_SPECIAL_POOL) &&
+ (MmIsSpecialPoolAddress(Buffer)))
+ {
+ return Buffer;
+ }
+
+ //
+ // If it wasn't actually allocated with quota charges, ignore it too
+ //
+ if (!(PoolType & QUOTA_POOL_MASK)) return Buffer;
+
+ //
+ // If this is the system process, we don't charge quota, so ignore
+ //
+ if (Process == PsInitialSystemProcess) return Buffer;
+
+ //
+ // Actually go and charge quota for the process now
+ //
+ Entry = POOL_ENTRY(Buffer);
+ Status = PsChargeProcessPoolQuota(Process,
+ PoolType & BASE_POOL_TYPE_MASK,
+ Entry->BlockSize * POOL_BLOCK_SIZE);
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // Quota failed, back out the allocation, clear the owner, and fail
+ //
+ ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1] = NULL;
+ ExFreePoolWithTag(Buffer, Tag);
+ if (Raise) RtlRaiseStatus(Status);
+ return NULL;
+ }
+
+ //
+ // Quota worked, write the owner and then reference it before returning
+ //
+ ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1] = Process;
+ ObReferenceObject(Process);
+ }
+ else if (!(Buffer) && (Raise))
+ {
+ //
+ // The allocation failed, raise an error if we are in raise mode
+ //
+ RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ //
+ // Return the allocated buffer
+ //
+ return Buffer;
}
+#if DBG && KDBG
+
+BOOLEAN
+ExpKdbgExtPool(
+ ULONG Argc,
+ PCHAR Argv[])
+{
+ ULONG_PTR Address = 0, Flags = 0;
+ PVOID PoolPage;
+ PPOOL_HEADER Entry;
+ BOOLEAN ThisOne;
+ PULONG Data;
+
+ if (Argc > 1)
+ {
+ /* Get address */
+ if (!KdbpGetHexNumber(Argv[1], &Address))
+ {
+ KdbpPrint("Invalid parameter: %s\n", Argv[0]);
+ return TRUE;
+ }
+ }
+
+ if (Argc > 2)
+ {
+ /* Get address */
+ if (!KdbpGetHexNumber(Argv[1], &Flags))
+ {
+ KdbpPrint("Invalid parameter: %s\n", Argv[0]);
+ return TRUE;
+ }
+ }
+
+ /* Check if we got an address */
+ if (Address != 0)
+ {
+ /* Get the base page */
+ PoolPage = PAGE_ALIGN(Address);
+ }
+ else
+ {
+ KdbpPrint("Heap is unimplemented\n");
+ return TRUE;
+ }
+
+ /* No paging support! */
+ if (!MmIsAddressValid(PoolPage))
+ {
+ KdbpPrint("Address not accessible!\n");
+ return TRUE;
+ }
+
+ /* Get pool type */
+ if ((Address >= (ULONG_PTR)MmPagedPoolStart) && (Address <= (ULONG_PTR)MmPagedPoolEnd))
+ KdbpPrint("Allocation is from PagedPool region\n");
+ else if ((Address >= (ULONG_PTR)MmNonPagedPoolStart) && (Address <= (ULONG_PTR)MmNonPagedPoolEnd))
+ KdbpPrint("Allocation is from NonPagedPool region\n");
+ else
+ {
+ KdbpPrint("Address 0x%p is not within any pool!\n", (PVOID)Address);
+ return TRUE;
+ }
+
+ /* Loop all entries of that page */
+ Entry = PoolPage;
+ do
+ {
+ /* Check if the address is within that entry */
+ ThisOne = ((Address >= (ULONG_PTR)Entry) &&
+ (Address < (ULONG_PTR)(Entry + Entry->BlockSize)));
+
+ if (!(Flags & 1) || ThisOne)
+ {
+ /* Print the line */
+ KdbpPrint("%c%p size: %4d previous size: %4d %s %.4s\n",
+ ThisOne ? '*' : ' ', Entry, Entry->BlockSize, Entry->PreviousSize,
+ (Flags & 0x80000000) ? "" : (Entry->PoolType ? "(Allocated)" : "(Free) "),
+ (Flags & 0x80000000) ? "" : (PCHAR)&Entry->PoolTag);
+ }
+
+ if (Flags & 1)
+ {
+ Data = (PULONG)(Entry + 1);
+ KdbpPrint(" %p %08lx %08lx %08lx %08lx\n"
+ " %p %08lx %08lx %08lx %08lx\n",
+ &Data[0], Data[0], Data[1], Data[2], Data[3],
+ &Data[4], Data[4], Data[5], Data[6], Data[7]);
+ }
+
+ /* Go to next entry */
+ Entry = POOL_BLOCK(Entry, Entry->BlockSize);
+ }
+ while ((Entry->BlockSize != 0) && ((ULONG_PTR)Entry < (ULONG_PTR)PoolPage + PAGE_SIZE));
+
+ return TRUE;
+}
+
+#endif // DBG && KDBG
+
/* EOF */