Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

pool.c

Go to the documentation of this file.
00001 /**************************** Module Header ********************************\ 00002 * Module Name: pool.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Pool reallocation routines 00007 * 00008 * History: 00009 * 03-04-95 JimA Created. 00010 \***************************************************************************/ 00011 00012 #include "precomp.h" 00013 #pragma hdrstop 00014 00015 BOOL gdwPoolFlags; 00016 00017 #ifdef POOL_INSTR 00018 00019 /* 00020 * Globals used by RecordStackTrace 00021 */ 00022 00023 PVOID gRecordedStackTrace[RECORD_STACK_TRACE_SIZE]; 00024 PEPROCESS gpepRecorded; 00025 PETHREAD gpetRecorded; 00026 00027 00028 DWORD gdwAllocFailIndex; // the index of the allocation that's 00029 // going to fail 00030 00031 DWORD gdwAllocsToFail = 1; // how many allocs to fail 00032 00033 DWORD gdwFreeRecords; 00034 00035 /* 00036 * Targeted tag failures 00037 */ 00038 LPDWORD gparrTagsToFail; 00039 SIZE_T gdwTagsToFailCount; 00040 00041 /* 00042 * Support to keep records of failed pool allocations 00043 */ 00044 DWORD gdwFailRecords; 00045 DWORD gdwFailRecordCrtIndex; 00046 DWORD gdwFailRecordTotalFailures; 00047 00048 PPOOLRECORD gparrFailRecord; 00049 00050 /* 00051 * Support to keep records of pool free 00052 */ 00053 DWORD gdwFreeRecords; 00054 DWORD gdwFreeRecordCrtIndex; 00055 DWORD gdwFreeRecordTotalFrees; 00056 00057 PPOOLRECORD gparrFreeRecord; 00058 00059 FAST_MUTEX* gpAllocFastMutex; // mutex to syncronize pool allocations 00060 00061 Win32AllocStats gAllocList; 00062 00063 char gszTailAlloc[] = "Win32kAlloc"; 00064 #endif // POOL_INSTR 00065 00066 00067 00068 PVOID Win32AllocPoolWithTagZInit(SIZE_T uBytes, ULONG uTag) 00069 { 00070 PVOID pv; 00071 00072 pv = Win32AllocPool(uBytes, uTag); 00073 if (pv) { 00074 RtlZeroMemory(pv, uBytes); 00075 } 00076 00077 return pv; 00078 } 00079 00080 PVOID Win32AllocPoolWithQuotaTagZInit(SIZE_T uBytes, ULONG uTag) 00081 { 00082 PVOID pv; 00083 00084 pv = Win32AllocPoolWithQuota(uBytes, uTag); 00085 if (pv) { 00086 RtlZeroMemory(pv, uBytes); 00087 } 00088 00089 return pv; 00090 } 00091 00092 PVOID UserReAllocPoolWithTag( 00093 PVOID pSrc, 00094 SIZE_T uBytesSrc, 00095 SIZE_T uBytes, 00096 ULONG iTag) 00097 { 00098 PVOID pDest; 00099 00100 pDest = UserAllocPool(uBytes, iTag); 00101 if (pDest != NULL) { 00102 00103 /* 00104 * If the block is shrinking, don't copy too many bytes. 00105 */ 00106 if (uBytesSrc > uBytes) { 00107 uBytesSrc = uBytes; 00108 } 00109 00110 RtlCopyMemory(pDest, pSrc, uBytesSrc); 00111 00112 UserFreePool(pSrc); 00113 } 00114 00115 return pDest; 00116 } 00117 00118 PVOID UserReAllocPoolWithQuotaTag( 00119 PVOID pSrc, 00120 SIZE_T uBytesSrc, 00121 SIZE_T uBytes, 00122 ULONG iTag) 00123 { 00124 PVOID pDest; 00125 00126 pDest = UserAllocPoolWithQuota(uBytes, iTag); 00127 if (pDest != NULL) { 00128 00129 /* 00130 * If the block is shrinking, don't copy too many bytes. 00131 */ 00132 if (uBytesSrc > uBytes) 00133 uBytesSrc = uBytes; 00134 00135 RtlCopyMemory(pDest, pSrc, uBytesSrc); 00136 00137 UserFreePool(pSrc); 00138 } 00139 00140 return pDest; 00141 } 00142 00143 /* 00144 * Allocation routines for rtl functions 00145 */ 00146 00147 PVOID UserRtlAllocMem( 00148 SIZE_T uBytes) 00149 { 00150 return UserAllocPool(uBytes, TAG_RTL); 00151 } 00152 00153 VOID UserRtlFreeMem( 00154 PVOID pMem) 00155 { 00156 UserFreePool(pMem); 00157 } 00158 00159 #ifdef POOL_INSTR 00160 00161 void RecordStackTrace(void) 00162 { 00163 ULONG hash; 00164 00165 RtlZeroMemory(gRecordedStackTrace, RECORD_STACK_TRACE_SIZE * sizeof(PVOID)); 00166 00167 GetStackTrace(2, 00168 RECORD_STACK_TRACE_SIZE, 00169 gRecordedStackTrace, 00170 &hash); 00171 00172 gpepRecorded = PsGetCurrentProcess(); 00173 gpetRecorded = PsGetCurrentThread(); 00174 } 00175 00176 /***************************************************************************\ 00177 * RecordFailAllocation 00178 * 00179 * Records failed allocations 00180 * 00181 * 3-22-99 CLupu Created. 00182 \***************************************************************************/ 00183 void RecordFailAllocation( 00184 ULONG tag, 00185 SIZE_T size) 00186 { 00187 ULONG hash; 00188 00189 UserAssert(gdwPoolFlags & POOL_KEEP_FAIL_RECORD); 00190 00191 gparrFailRecord[gdwFailRecordCrtIndex].ExtraData = LongToPtr( tag ); 00192 gparrFailRecord[gdwFailRecordCrtIndex].size = size; 00193 00194 gdwFailRecordTotalFailures++; 00195 00196 RtlZeroMemory(gparrFailRecord[gdwFailRecordCrtIndex].trace, 00197 RECORD_STACK_TRACE_SIZE * sizeof(PVOID)); 00198 00199 GetStackTrace(2, 00200 RECORD_STACK_TRACE_SIZE, 00201 gparrFailRecord[gdwFailRecordCrtIndex].trace, 00202 &hash); 00203 00204 gdwFailRecordCrtIndex++; 00205 00206 if (gdwFailRecordCrtIndex >= gdwFailRecords) { 00207 gdwFailRecordCrtIndex = 0; 00208 } 00209 } 00210 00211 /***************************************************************************\ 00212 * RecordFreePool 00213 * 00214 * Records free pool 00215 * 00216 * 3-22-99 CLupu Created. 00217 \***************************************************************************/ 00218 void RecordFreePool( 00219 PVOID p, 00220 SIZE_T size) 00221 { 00222 ULONG hash; 00223 00224 UserAssert(gdwPoolFlags & POOL_KEEP_FREE_RECORD); 00225 00226 gparrFreeRecord[gdwFreeRecordCrtIndex].ExtraData = p; 00227 gparrFreeRecord[gdwFreeRecordCrtIndex].size = size; 00228 00229 gdwFreeRecordTotalFrees++; 00230 00231 RtlZeroMemory(gparrFreeRecord[gdwFreeRecordCrtIndex].trace, 00232 RECORD_STACK_TRACE_SIZE * sizeof(PVOID)); 00233 00234 GetStackTrace(2, 00235 RECORD_STACK_TRACE_SIZE, 00236 gparrFreeRecord[gdwFreeRecordCrtIndex].trace, 00237 &hash); 00238 00239 gdwFreeRecordCrtIndex++; 00240 00241 if (gdwFreeRecordCrtIndex >= gdwFreeRecords) { 00242 gdwFreeRecordCrtIndex = 0; 00243 } 00244 } 00245 00246 /***************************************************************************\ 00247 * HeavyAllocPool 00248 * 00249 * This will make UserAllocPool to fail if we do not provide enough memory 00250 * for the specified tag. 00251 * 00252 * 12-02-96 CLupu Created. 00253 \***************************************************************************/ 00254 PVOID HeavyAllocPool( 00255 SIZE_T uBytes, 00256 ULONG tag, 00257 DWORD dwFlags) 00258 { 00259 DWORD* p; 00260 PWin32PoolHead ph; 00261 00262 /* 00263 * Make instrumentations faster for the main session if POOL_ONLY_HEAVY_REMOTE 00264 * is used 00265 */ 00266 if (!(gdwPoolFlags & POOL_HEAVY_ALLOCS)) { 00267 if (dwFlags & DAP_USEQUOTA) { 00268 if (dwFlags & DAP_NONPAGEDPOOL) { 00269 p = ExAllocatePoolWithQuotaTag(SESSION_POOL_MASK | NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE, 00270 uBytes, 00271 tag); 00272 } else { 00273 p = ExAllocatePoolWithQuotaTag( 00274 SESSION_POOL_MASK | PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE, 00275 uBytes, 00276 tag); 00277 } 00278 } else { 00279 if (dwFlags & DAP_NONPAGEDPOOL) { 00280 p = ExAllocatePoolWithTag(SESSION_POOL_MASK | NonPagedPool, uBytes, tag); 00281 } else { 00282 p = ExAllocatePoolWithTag(SESSION_POOL_MASK | PagedPool, uBytes, tag); 00283 } 00284 } 00285 00286 if (p != NULL && (dwFlags & DAP_ZEROINIT)) { 00287 RtlZeroMemory(p, uBytes); 00288 } 00289 00290 return p; 00291 } 00292 00293 /* 00294 * Check for overflow 00295 */ 00296 if (uBytes >= MAXULONG - sizeof(Win32PoolHead) - sizeof(gszTailAlloc)) { 00297 00298 if (gdwPoolFlags & POOL_KEEP_FAIL_RECORD) { 00299 RecordFailAllocation(tag, 0); 00300 } 00301 return NULL; 00302 } 00303 00304 /* 00305 * Acquire the mutex when we play with the list of allocations 00306 */ 00307 KeEnterCriticalRegion(); 00308 ExAcquireFastMutexUnsafe(gpAllocFastMutex); 00309 00310 #ifdef POOL_INSTR_API 00311 /* 00312 * Fail the allocation if the flag is set 00313 * Don't fail allocations that will certainly get us to bugchecking in DBG (i.e. GLOBALTHREADLOCK) 00314 */ 00315 if (gdwPoolFlags & POOL_FAIL_ALLOCS 00316 #if DBG 00317 && (tag != TAG_GLOBALTHREADLOCK) 00318 #endif // DBG 00319 ) { 00320 00321 00322 SIZE_T dwInd; 00323 00324 for (dwInd = 0; dwInd < gdwTagsToFailCount; dwInd++) { 00325 if (tag == gparrTagsToFail[dwInd]) { 00326 break; 00327 } 00328 } 00329 00330 if (dwInd < gdwTagsToFailCount) { 00331 if (gdwPoolFlags & POOL_KEEP_FAIL_RECORD) { 00332 RecordFailAllocation(tag, uBytes); 00333 } 00334 00335 RIPMSG0(RIP_WARNING, "Pool allocation failed because of global restriction"); 00336 p = NULL; 00337 goto exit; 00338 } 00339 } 00340 #endif // POOL_INSTR_API 00341 00342 #if DBG 00343 if ((gdwPoolFlags & POOL_FAIL_BY_INDEX) && (tag != TAG_GLOBALTHREADLOCK)) { 00344 00345 /* 00346 * Count the calls to HeavyAllocPool 00347 */ 00348 gdwAllocCrt++; 00349 00350 if (gdwAllocCrt >= gdwAllocFailIndex && 00351 gdwAllocCrt < gdwAllocFailIndex + gdwAllocsToFail) { 00352 00353 RecordStackTrace(); 00354 00355 KdPrint(("\n--------------------------------------------------\n")); 00356 KdPrint(( 00357 "\nPool allocation %d failed because of registry settings", 00358 gdwAllocCrt)); 00359 KdPrint(("\n--------------------------------------------------\n\n")); 00360 00361 if (gdwPoolFlags & POOL_KEEP_FAIL_RECORD) { 00362 RecordFailAllocation(tag, uBytes); 00363 } 00364 p = NULL; 00365 goto exit; 00366 } 00367 } 00368 #endif // DBG 00369 00370 /* 00371 * Reserve space for the header 00372 */ 00373 uBytes += sizeof(Win32PoolHead); 00374 00375 if (gdwPoolFlags & POOL_TAIL_CHECK) { 00376 uBytes += sizeof(gszTailAlloc); 00377 } 00378 00379 if (dwFlags & DAP_USEQUOTA) { 00380 if (dwFlags & DAP_NONPAGEDPOOL) { 00381 p = ExAllocatePoolWithQuotaTag(SESSION_POOL_MASK | NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE, 00382 uBytes, 00383 tag); 00384 } else { 00385 p = ExAllocatePoolWithQuotaTag( 00386 SESSION_POOL_MASK | PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE, 00387 uBytes, 00388 tag); 00389 } 00390 } else { 00391 if (dwFlags & DAP_NONPAGEDPOOL) { 00392 p = ExAllocatePoolWithTag(SESSION_POOL_MASK | NonPagedPool, uBytes, tag); 00393 } else { 00394 p = ExAllocatePoolWithTag(SESSION_POOL_MASK | PagedPool, uBytes, tag); 00395 } 00396 } 00397 00398 /* 00399 * Return if ExAllocate... failed. 00400 */ 00401 if (p == NULL) { 00402 00403 if (gdwPoolFlags & POOL_KEEP_FAIL_RECORD) { 00404 00405 uBytes -= sizeof(Win32PoolHead); 00406 00407 if (gdwPoolFlags & POOL_TAIL_CHECK) { 00408 uBytes -= sizeof(gszTailAlloc); 00409 } 00410 00411 RecordFailAllocation(tag, uBytes); 00412 } 00413 00414 goto exit; 00415 } 00416 00417 uBytes -= sizeof(Win32PoolHead); 00418 00419 if (gdwPoolFlags & POOL_TAIL_CHECK) { 00420 uBytes -= sizeof(gszTailAlloc); 00421 00422 RtlCopyMemory(((BYTE*)p) + uBytes, gszTailAlloc, sizeof(gszTailAlloc)); 00423 } 00424 00425 /* 00426 * get the pointer to the header 00427 */ 00428 ph = (PWin32PoolHead)p; 00429 00430 p += (sizeof(Win32PoolHead) / sizeof(DWORD)); 00431 00432 /* 00433 * Update the global allocations info. 00434 */ 00435 gAllocList.dwCrtMem += uBytes; 00436 00437 if (gAllocList.dwMaxMem < gAllocList.dwCrtMem) { 00438 gAllocList.dwMaxMem = gAllocList.dwCrtMem; 00439 } 00440 00441 (gAllocList.dwCrtAlloc)++; 00442 00443 if (gAllocList.dwMaxAlloc < gAllocList.dwCrtAlloc) { 00444 gAllocList.dwMaxAlloc = gAllocList.dwCrtAlloc; 00445 } 00446 00447 /* 00448 * Grab the stack traces if the flags say so 00449 */ 00450 if (gdwPoolFlags & POOL_CAPTURE_STACK) { 00451 ph->pTrace = ExAllocatePoolWithTag(SESSION_POOL_MASK | PagedPool, 00452 POOL_ALLOC_TRACE_SIZE * sizeof(PVOID), 00453 TAG_STACK); 00454 00455 if (ph->pTrace != NULL) { 00456 00457 ULONG hash; 00458 00459 RtlZeroMemory(ph->pTrace, POOL_ALLOC_TRACE_SIZE * sizeof(PVOID)); 00460 00461 GetStackTrace(1, 00462 POOL_ALLOC_TRACE_SIZE, 00463 ph->pTrace, 00464 &hash); 00465 } 00466 } else { 00467 ph->pTrace = NULL; 00468 } 00469 00470 /* 00471 * Save the info in the header and return the pointer after the header. 00472 */ 00473 ph->size = uBytes; 00474 00475 /* 00476 * now, link it into the list for this tag (if any) 00477 */ 00478 ph->pPrev = NULL; 00479 ph->pNext = gAllocList.pHead; 00480 00481 if (gAllocList.pHead != NULL) 00482 gAllocList.pHead->pPrev = ph; 00483 00484 gAllocList.pHead = ph; 00485 00486 if (dwFlags & DAP_ZEROINIT) { 00487 RtlZeroMemory(p, uBytes); 00488 } 00489 00490 exit: 00491 /* 00492 * Release the mutex 00493 */ 00494 ExReleaseFastMutexUnsafe(gpAllocFastMutex); 00495 KeLeaveCriticalRegion(); 00496 00497 return p; 00498 } 00499 00500 /***************************************************************************\ 00501 * HeavyFreePool 00502 * 00503 * 12-02-96 CLupu Created. 00504 \***************************************************************************/ 00505 void HeavyFreePool( 00506 PVOID p) 00507 { 00508 SIZE_T uBytes; 00509 PWin32PoolHead ph; 00510 00511 /* 00512 * If POOL_HEAVY_ALLOCS is not defined 00513 * then the pointer is what we allocated 00514 */ 00515 if (!(gdwPoolFlags & POOL_HEAVY_ALLOCS)) { 00516 ExFreePool(p); 00517 return; 00518 } 00519 00520 /* 00521 * Acquire the mutex when we play with the list of allocations 00522 */ 00523 KeEnterCriticalRegion(); 00524 ExAcquireFastMutexUnsafe(gpAllocFastMutex); 00525 00526 ph = (PWin32PoolHead)((DWORD*)p - (sizeof(Win32PoolHead) / sizeof(DWORD))); 00527 00528 uBytes = ph->size; 00529 00530 /* 00531 * Check the tail 00532 */ 00533 if (gdwPoolFlags & POOL_TAIL_CHECK) { 00534 if (!RtlEqualMemory((BYTE*)p + uBytes, gszTailAlloc, sizeof(gszTailAlloc))) { 00535 RIPMSG1(RIP_ERROR, "POOL CORRUPTION for %#p", p); 00536 } 00537 } 00538 00539 gAllocList.dwCrtMem -= uBytes; 00540 00541 UserAssert(gAllocList.dwCrtAlloc > 0); 00542 00543 (gAllocList.dwCrtAlloc)--; 00544 00545 /* 00546 * now, remove it from the linked list 00547 */ 00548 if (ph->pPrev == NULL) { 00549 if (ph->pNext == NULL) { 00550 00551 UserAssert(gAllocList.dwCrtAlloc == 0); 00552 00553 gAllocList.pHead = NULL; 00554 } else { 00555 ph->pNext->pPrev = NULL; 00556 gAllocList.pHead = ph->pNext; 00557 } 00558 } else { 00559 ph->pPrev->pNext = ph->pNext; 00560 if (ph->pNext != NULL) { 00561 ph->pNext->pPrev = ph->pPrev; 00562 } 00563 } 00564 00565 /* 00566 * Free the stack traces 00567 */ 00568 if (ph->pTrace != NULL) { 00569 ExFreePool(ph->pTrace); 00570 } 00571 00572 if (gdwPoolFlags & POOL_KEEP_FREE_RECORD) { 00573 RecordFreePool(ph, ph->size); 00574 } 00575 00576 ExFreePool(ph); 00577 00578 /* 00579 * Release the mutex 00580 */ 00581 ExReleaseFastMutexUnsafe(gpAllocFastMutex); 00582 KeLeaveCriticalRegion(); 00583 } 00584 00585 /***************************************************************************\ 00586 * CleanupPoolAllocations 00587 * 00588 * 12-02-96 CLupu Created. 00589 \***************************************************************************/ 00590 00591 void CleanupPoolAllocations( 00592 void) 00593 { 00594 PWin32PoolHead pHead; 00595 PWin32PoolHead pNext; 00596 00597 if (gAllocList.dwCrtAlloc != 0) { 00598 00599 if ((gdwPoolFlags & POOL_BREAK_FOR_LEAKS) && 00600 **((PBOOLEAN*)&KdDebuggerEnabled)) { 00601 00602 /* 00603 * The below is as is because it is intended to work on both 00604 * free and checked builds. 00605 */ 00606 #undef DbgPrint 00607 DbgPrint("\n------------------------\n" 00608 "There is still pool memory not freed in win32k.sys !!!\n" 00609 "Use !dpa -vs to dump it\n" 00610 "-------------------------\n"); 00611 DbgBreakPoint(); 00612 } 00613 00614 pHead = gAllocList.pHead; 00615 00616 while (pHead != NULL) { 00617 00618 pNext = pHead->pNext; 00619 00620 UserFreePool(pHead + 1); 00621 00622 pHead = pNext; 00623 } 00624 } 00625 } 00626 00627 /***************************************************************************\ 00628 * CleanUpPoolLimitations 00629 * 00630 \***************************************************************************/ 00631 void CleanUpPoolLimitations(void) 00632 { 00633 if (gpAllocFastMutex != NULL) { 00634 ExFreePool(gpAllocFastMutex); 00635 gpAllocFastMutex = NULL; 00636 } 00637 00638 if (gparrFailRecord != NULL) { 00639 ExFreePool(gparrFailRecord); 00640 gparrFailRecord = NULL; 00641 } 00642 00643 if (gparrFreeRecord != NULL) { 00644 ExFreePool(gparrFreeRecord); 00645 gparrFreeRecord = NULL; 00646 } 00647 00648 if (gparrTagsToFail != NULL) { 00649 ExFreePool(gparrTagsToFail); 00650 gparrTagsToFail = NULL; 00651 } 00652 00653 } 00654 00655 /***************************************************************************\ 00656 * InitPoolLimitations 00657 * 00658 * 12-02-96 CLupu Created. 00659 \***************************************************************************/ 00660 void InitPoolLimitations(void) 00661 { 00662 UNICODE_STRING UnicodeString; 00663 OBJECT_ATTRIBUTES ObjectAttributes; 00664 HANDLE hkey; 00665 NTSTATUS Status; 00666 WCHAR achKeyName[512]; 00667 WCHAR achKeyValue[512]; 00668 DWORD dwData; 00669 ULONG ucb; 00670 00671 /* 00672 * Initialize a critical section structure that will be used to protect 00673 * all the HeavyAllocPool and HeavyFreePool calls 00674 */ 00675 gpAllocFastMutex = ExAllocatePoolWithTag(NonPagedPoolMustSucceed, 00676 sizeof(FAST_MUTEX), 00677 TAG_DEBUG); 00678 00679 UserAssert(gpAllocFastMutex != NULL); 00680 00681 ExInitializeFastMutex(gpAllocFastMutex); 00682 00683 /* 00684 * Default settings 00685 */ 00686 if (gbRemoteSession) { 00687 gdwPoolFlags = POOL_HEAVY_ALLOCS; 00688 00689 #if DBG 00690 gdwPoolFlags |= (POOL_CAPTURE_STACK | POOL_BREAK_FOR_LEAKS); 00691 #endif // DBG 00692 } 00693 00694 /* 00695 * Open the key containing the limits. 00696 */ 00697 RtlInitUnicodeString( 00698 &UnicodeString, 00699 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\SubSystems\\Pool"); 00700 00701 InitializeObjectAttributes( 00702 &ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); 00703 00704 Status = ZwOpenKey(&hkey, KEY_READ, &ObjectAttributes); 00705 if (!NT_SUCCESS(Status)) { 00706 00707 #if DBG 00708 /* 00709 * More default settings if the Pool key doesn't exist 00710 */ 00711 if (gbRemoteSession) { 00712 00713 gparrFailRecord = ExAllocatePoolWithTag(PagedPool, 00714 32 * sizeof(POOLRECORD), 00715 TAG_DEBUG); 00716 00717 if (gparrFailRecord != NULL) { 00718 gdwFailRecords = 32; 00719 gdwPoolFlags |= POOL_KEEP_FAIL_RECORD; 00720 } 00721 00722 gparrFreeRecord = ExAllocatePoolWithTag(PagedPool, 00723 32 * sizeof(POOLRECORD), 00724 TAG_DEBUG); 00725 00726 if (gparrFreeRecord != NULL) { 00727 gdwFreeRecords = 32; 00728 gdwPoolFlags |= POOL_KEEP_FREE_RECORD; 00729 } 00730 } 00731 #endif // DBG 00732 00733 return; 00734 } 00735 00736 if (gbRemoteSession) { 00737 00738 /* 00739 * Break in the debugger for memory leaks ? 00740 */ 00741 RtlInitUnicodeString(&UnicodeString, L"BreakForPoolLeaks"); 00742 00743 Status = ZwQueryValueKey( 00744 hkey, 00745 &UnicodeString, 00746 KeyValuePartialInformation, 00747 &achKeyValue, 00748 sizeof(achKeyValue), 00749 &ucb); 00750 00751 if (NT_SUCCESS(Status) && 00752 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) { 00753 00754 dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data); 00755 00756 if (dwData != 0) { 00757 gdwPoolFlags |= POOL_BREAK_FOR_LEAKS; 00758 } else { 00759 gdwPoolFlags &= ~POOL_BREAK_FOR_LEAKS; 00760 } 00761 } 00762 00763 /* 00764 * Heavy allocs/frees for remote sessions ? 00765 */ 00766 RtlInitUnicodeString(&UnicodeString, L"HeavyRemoteSession"); 00767 00768 Status = ZwQueryValueKey( 00769 hkey, 00770 &UnicodeString, 00771 KeyValuePartialInformation, 00772 &achKeyValue, 00773 sizeof(achKeyValue), 00774 &ucb); 00775 00776 if (NT_SUCCESS(Status) && 00777 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) { 00778 00779 dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data); 00780 00781 if (dwData == 0) { 00782 gdwPoolFlags &= ~POOL_HEAVY_ALLOCS; 00783 } 00784 } 00785 } else { 00786 00787 /* 00788 * Heavy allocs/frees for main session ? 00789 */ 00790 RtlInitUnicodeString(&UnicodeString, L"HeavyConsoleSession"); 00791 00792 Status = ZwQueryValueKey( 00793 hkey, 00794 &UnicodeString, 00795 KeyValuePartialInformation, 00796 &achKeyValue, 00797 sizeof(achKeyValue), 00798 &ucb); 00799 00800 if (NT_SUCCESS(Status) && 00801 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) { 00802 00803 dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data); 00804 00805 if (dwData != 0) { 00806 gdwPoolFlags |= POOL_HEAVY_ALLOCS; 00807 } 00808 } 00809 } 00810 00811 if (!(gdwPoolFlags & POOL_HEAVY_ALLOCS)) { 00812 ZwClose(hkey); 00813 return; 00814 } 00815 00816 /* 00817 * Check for stack traces 00818 */ 00819 RtlInitUnicodeString(&UnicodeString, L"StackTraces"); 00820 00821 RtlZeroMemory(achKeyName, sizeof(achKeyName)); 00822 00823 Status = ZwQueryValueKey( 00824 hkey, 00825 &UnicodeString, 00826 KeyValuePartialInformation, 00827 &achKeyValue, 00828 sizeof(achKeyValue), 00829 &ucb); 00830 00831 if (NT_SUCCESS(Status) && 00832 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) { 00833 00834 dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data); 00835 00836 if (dwData == 0) { 00837 gdwPoolFlags &= ~POOL_CAPTURE_STACK; 00838 } else { 00839 gdwPoolFlags |= POOL_CAPTURE_STACK; 00840 } 00841 } 00842 00843 /* 00844 * Use tail checks ? 00845 */ 00846 RtlInitUnicodeString(&UnicodeString, L"UseTailString"); 00847 00848 Status = ZwQueryValueKey( 00849 hkey, 00850 &UnicodeString, 00851 KeyValuePartialInformation, 00852 &achKeyValue, 00853 sizeof(achKeyValue), 00854 &ucb); 00855 00856 if (NT_SUCCESS(Status) && 00857 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) { 00858 00859 dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data); 00860 00861 if (dwData != 0) { 00862 gdwPoolFlags |= POOL_TAIL_CHECK; 00863 } 00864 } 00865 00866 /* 00867 * Keep a record of frees ? By default keep the last 32. 00868 */ 00869 #if DBG 00870 gdwFreeRecords = 32; 00871 #endif // DBG 00872 00873 RtlInitUnicodeString(&UnicodeString, L"KeepFreeRecords"); 00874 00875 Status = ZwQueryValueKey( 00876 hkey, 00877 &UnicodeString, 00878 KeyValuePartialInformation, 00879 &achKeyValue, 00880 sizeof(achKeyValue), 00881 &ucb); 00882 00883 if (NT_SUCCESS(Status) && 00884 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) { 00885 00886 gdwFreeRecords = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data); 00887 } 00888 00889 if (gdwFreeRecords != 0) { 00890 00891 gparrFreeRecord = ExAllocatePoolWithTag(PagedPool, 00892 gdwFreeRecords * sizeof(POOLRECORD), 00893 TAG_DEBUG); 00894 00895 if (gparrFreeRecord != NULL) { 00896 gdwPoolFlags |= POOL_KEEP_FREE_RECORD; 00897 } 00898 } 00899 00900 /* 00901 * Keep a record of failed allocations ? By default keep the last 32. 00902 */ 00903 #if DBG 00904 gdwFailRecords = 32; 00905 #endif // DBG 00906 00907 RtlInitUnicodeString(&UnicodeString, L"KeepFailRecords"); 00908 00909 Status = ZwQueryValueKey( 00910 hkey, 00911 &UnicodeString, 00912 KeyValuePartialInformation, 00913 &achKeyValue, 00914 sizeof(achKeyValue), 00915 &ucb); 00916 00917 if (NT_SUCCESS(Status) && 00918 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) { 00919 00920 gdwFailRecords = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data); 00921 } 00922 00923 if (gdwFailRecords != 0) { 00924 00925 gparrFailRecord = ExAllocatePoolWithTag(PagedPool, 00926 gdwFailRecords * sizeof(POOLRECORD), 00927 TAG_DEBUG); 00928 00929 if (gparrFailRecord != NULL) { 00930 gdwPoolFlags |= POOL_KEEP_FAIL_RECORD; 00931 } 00932 } 00933 00934 #if DBG 00935 /* 00936 * Open the key containing the allocation that should fail. 00937 */ 00938 RtlInitUnicodeString(&UnicodeString, L"AllocationIndex"); 00939 00940 Status = ZwQueryValueKey( 00941 hkey, 00942 &UnicodeString, 00943 KeyValuePartialInformation, 00944 &achKeyValue, 00945 sizeof(achKeyValue), 00946 &ucb); 00947 00948 if (NT_SUCCESS(Status) && 00949 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) { 00950 00951 gdwAllocFailIndex = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data); 00952 } 00953 00954 00955 RtlInitUnicodeString(&UnicodeString, L"AllocationsToFail"); 00956 00957 Status = ZwQueryValueKey( 00958 hkey, 00959 &UnicodeString, 00960 KeyValuePartialInformation, 00961 &achKeyValue, 00962 sizeof(achKeyValue), 00963 &ucb); 00964 00965 if (NT_SUCCESS(Status) && 00966 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) { 00967 00968 gdwAllocsToFail = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data); 00969 } 00970 00971 if (gdwAllocFailIndex != 0 && gdwAllocsToFail > 0) { 00972 gdwPoolFlags |= POOL_FAIL_BY_INDEX; 00973 } 00974 #endif // DBG 00975 00976 ZwClose(hkey); 00977 00978 return; 00979 } 00980 #endif // POOL_INSTR 00981 00982 #ifdef POOL_INSTR_API 00983 00984 BOOL _Win32PoolAllocationStats( 00985 LPDWORD parrTags, 00986 SIZE_T tagsCount, 00987 SIZE_T* lpdwMaxMem, 00988 SIZE_T* lpdwCrtMem, 00989 LPDWORD lpdwMaxAlloc, 00990 LPDWORD lpdwCrtAlloc) 00991 { 00992 BOOL bRet = FALSE; 00993 00994 /* 00995 * Do nothing if heavy allocs/frees are disabled 00996 */ 00997 if (!(gdwPoolFlags & POOL_HEAVY_ALLOCS)) { 00998 return FALSE; 00999 } 01000 01001 *lpdwMaxMem = gAllocList.dwMaxMem; 01002 *lpdwCrtMem = gAllocList.dwCrtMem; 01003 *lpdwMaxAlloc = gAllocList.dwMaxAlloc; 01004 *lpdwCrtAlloc = gAllocList.dwCrtAlloc; 01005 01006 /* 01007 * Acquire the mutex when we play with the list of allocations 01008 */ 01009 KeEnterCriticalRegion(); 01010 ExAcquireFastMutexUnsafe(gpAllocFastMutex); 01011 01012 if (gparrTagsToFail != NULL) { 01013 ExFreePool(gparrTagsToFail); 01014 gparrTagsToFail = NULL; 01015 gdwTagsToFailCount = 0; 01016 } 01017 01018 if (tagsCount != 0) { 01019 gdwPoolFlags |= POOL_FAIL_ALLOCS; 01020 01021 if (tagsCount > MAX_TAGS_TO_FAIL) { 01022 gdwTagsToFailCount = 0xFFFFFFFF; 01023 RIPMSG0(RIP_WARNING, "All pool allocations in WIN32K.SYS will fail !!!"); 01024 bRet = TRUE; 01025 goto exit; 01026 } 01027 01028 } else { 01029 gdwPoolFlags &= ~POOL_FAIL_ALLOCS; 01030 01031 RIPMSG0(RIP_WARNING, "Pool allocations in WIN32K.SYS back to normal !"); 01032 bRet = TRUE; 01033 goto exit; 01034 } 01035 01036 gparrTagsToFail = ExAllocatePoolWithTag(PagedPool, 01037 sizeof(DWORD) * tagsCount, 01038 TAG_DEBUG); 01039 01040 if (gparrTagsToFail == NULL) { 01041 gdwPoolFlags &= ~POOL_FAIL_ALLOCS; 01042 RIPMSG0(RIP_WARNING, "Pool allocations in WIN32K.SYS back to normal !"); 01043 goto exit; 01044 } 01045 01046 try { 01047 ProbeForRead(parrTags, sizeof(DWORD) * tagsCount, DATAALIGN); 01048 01049 RtlCopyMemory(gparrTagsToFail, parrTags, sizeof(DWORD) * tagsCount); 01050 01051 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 01052 01053 if (gparrTagsToFail != NULL) { 01054 ExFreePool(gparrTagsToFail); 01055 gparrTagsToFail = NULL; 01056 01057 gdwPoolFlags &= ~POOL_FAIL_ALLOCS; 01058 RIPMSG0(RIP_WARNING, "Pool allocations in WIN32K.SYS back to normal !"); 01059 goto exit; 01060 } 01061 } 01062 gdwTagsToFailCount = tagsCount; 01063 01064 RIPMSG0(RIP_WARNING, "Specific pool allocations in WIN32K.SYS will fail !!!"); 01065 01066 exit: 01067 /* 01068 * Release the mutex 01069 */ 01070 ExReleaseFastMutexUnsafe(gpAllocFastMutex); 01071 KeLeaveCriticalRegion(); 01072 01073 return TRUE; 01074 } 01075 01076 #endif // POOL_INSTR_API 01077 01078 #ifdef TRACE_MAP_VIEWS 01079 01080 FAST_MUTEX* gpSectionFastMutex; 01081 PWin32Section gpSections; 01082 01083 #define EnterSectionCrit() \ 01084 KeEnterCriticalRegion(); \ 01085 ExAcquireFastMutexUnsafe(gpSectionFastMutex); 01086 01087 #define LeaveSectionCrit() \ 01088 ExReleaseFastMutexUnsafe(gpSectionFastMutex); \ 01089 KeLeaveCriticalRegion(); 01090 01091 01092 /***************************************************************************\ 01093 * CleanUpSections 01094 * 01095 \***************************************************************************/ 01096 void CleanUpSections(void) 01097 { 01098 if (gpSectionFastMutex) { 01099 ExFreePool(gpSectionFastMutex); 01100 gpSectionFastMutex = NULL; 01101 } 01102 } 01103 01104 VOID InitSectionTrace(VOID) 01105 { 01106 gpSectionFastMutex = ExAllocatePoolWithTag(NonPagedPoolMustSucceed, 01107 sizeof(FAST_MUTEX), 01108 TAG_DEBUG); 01109 01110 UserAssert(gpSectionFastMutex != NULL); 01111 01112 ExInitializeFastMutex(gpSectionFastMutex); 01113 } 01114 01115 NTSTATUS _Win32CreateSection( 01116 PVOID* pSectionObject, 01117 ACCESS_MASK DesiredAccess, 01118 POBJECT_ATTRIBUTES ObjectAttributes, 01119 PLARGE_INTEGER pInputMaximumSize, 01120 ULONG SectionPageProtection, 01121 ULONG AllocationAttributes, 01122 HANDLE FileHandle, 01123 PFILE_OBJECT FileObject, 01124 DWORD SectionTag) 01125 { 01126 PWin32Section pSection; 01127 NTSTATUS Status; 01128 01129 #ifdef MAP_VIEW_STACK_TRACE 01130 ULONG hash; 01131 #endif 01132 01133 Status = MmCreateSection( 01134 pSectionObject, 01135 DesiredAccess, 01136 ObjectAttributes, 01137 pInputMaximumSize, 01138 SectionPageProtection, 01139 AllocationAttributes, 01140 FileHandle, 01141 FileObject); 01142 01143 if (!NT_SUCCESS(Status)) { 01144 RIPMSG1(RIP_WARNING, "MmCreateSection failed with Statu %x", Status); 01145 *pSectionObject = NULL; 01146 return Status; 01147 } 01148 01149 pSection = UserAllocPoolZInit(sizeof(Win32Section), TAG_SECTION); 01150 01151 if (pSection == NULL) { 01152 ObDereferenceObject(*pSectionObject); 01153 RIPMSG0(RIP_WARNING, "Failed to allocate memory for section"); 01154 *pSectionObject = NULL; 01155 return STATUS_UNSUCCESSFUL; 01156 } 01157 01158 EnterSectionCrit(); 01159 01160 pSection->pNext = gpSections; 01161 if (gpSections != NULL) { 01162 UserAssert(gpSections->pPrev == NULL); 01163 gpSections->pPrev = pSection; 01164 } 01165 01166 pSection->SectionObject = *pSectionObject; 01167 pSection->SectionSize = *pInputMaximumSize; 01168 pSection->SectionTag = SectionTag; 01169 01170 gpSections = pSection; 01171 01172 #ifdef MAP_VIEW_STACK_TRACE 01173 RtlZeroMemory(pSection->trace, MAP_VIEW_STACK_TRACE_SIZE * sizeof(PVOID)); 01174 01175 GetStackTrace(1, 01176 MAP_VIEW_STACK_TRACE_SIZE, 01177 pSection->trace, 01178 &hash); 01179 01180 #endif // MAP_VIEW_STACK_TRACE 01181 01182 LeaveSectionCrit(); 01183 01184 return STATUS_SUCCESS; 01185 01186 } 01187 01188 VOID _Win32DestroySection( 01189 PVOID Section) 01190 { 01191 PWin32Section ps; 01192 01193 EnterSectionCrit(); 01194 01195 ps = gpSections; 01196 01197 while (ps != NULL) { 01198 if (ps->SectionObject == Section) { 01199 01200 /* 01201 * Make sure there is no view mapped for this section 01202 */ 01203 if (ps->pFirstView != NULL) { 01204 RIPMSG1(RIP_ERROR, "Section %#p still has views", ps); 01205 } 01206 01207 /* 01208 * now, remove it from the linked list of this tag 01209 */ 01210 if (ps->pPrev == NULL) { 01211 01212 UserAssert(ps == gpSections); 01213 01214 gpSections = ps->pNext; 01215 01216 if (ps->pNext != NULL) { 01217 ps->pNext->pPrev = NULL; 01218 } 01219 } else { 01220 ps->pPrev->pNext = ps->pNext; 01221 if (ps->pNext != NULL) { 01222 ps->pNext->pPrev = ps->pPrev; 01223 } 01224 } 01225 ObDereferenceObject(Section); 01226 UserFreePool(ps); 01227 LeaveSectionCrit(); 01228 return; 01229 } 01230 ps = ps->pNext; 01231 } 01232 01233 RIPMSG1(RIP_ERROR, "Cannot find Section %#p", Section); 01234 LeaveSectionCrit(); 01235 } 01236 01237 NTSTATUS _Win32MapViewInSessionSpace( 01238 PVOID Section, 01239 PVOID* pMappedBase, 01240 PSIZE_T pViewSize) 01241 { 01242 NTSTATUS Status; 01243 PWin32Section ps; 01244 PWin32MapView pMapView; 01245 01246 #ifdef MAP_VIEW_STACK_TRACE 01247 ULONG hash; 01248 #endif 01249 01250 /* 01251 * First try to map the view 01252 */ 01253 Status = MmMapViewInSessionSpace(Section, pMappedBase, pViewSize); 01254 01255 if (!NT_SUCCESS(Status)) { 01256 RIPMSG1(RIP_WARNING, "MmMapViewInSessionSpace failed with Status %x", 01257 Status); 01258 *pMappedBase = NULL; 01259 return Status; 01260 } 01261 01262 /* 01263 * Now add a record for this view 01264 */ 01265 pMapView = UserAllocPoolZInit(sizeof(Win32MapView), TAG_SECTION); 01266 01267 if (pMapView == NULL) { 01268 RIPMSG0(RIP_WARNING, "_Win32MapViewInSessionSpace: Memory failure"); 01269 01270 MmUnmapViewInSessionSpace(*pMappedBase); 01271 *pMappedBase = NULL; 01272 return STATUS_NO_MEMORY; 01273 } 01274 01275 pMapView->pViewBase = *pMappedBase; 01276 pMapView->ViewSize = *pViewSize; 01277 01278 EnterSectionCrit(); 01279 01280 ps = gpSections; 01281 01282 while (ps != NULL) { 01283 if (ps->SectionObject == Section) { 01284 01285 pMapView->pSection = ps; 01286 01287 pMapView->pNext = ps->pFirstView; 01288 01289 if (ps->pFirstView != NULL) { 01290 ps->pFirstView->pPrev = pMapView; 01291 } 01292 ps->pFirstView = pMapView; 01293 01294 #ifdef MAP_VIEW_STACK_TRACE 01295 RtlZeroMemory(pMapView->trace, MAP_VIEW_STACK_TRACE_SIZE * sizeof(PVOID)); 01296 01297 GetStackTrace(1, 01298 MAP_VIEW_STACK_TRACE_SIZE, 01299 pMapView->trace, 01300 &hash); 01301 01302 #endif // MAP_VIEW_STACK_TRACE 01303 01304 LeaveSectionCrit(); 01305 return STATUS_SUCCESS; 01306 } 01307 ps = ps->pNext; 01308 } 01309 01310 RIPMSG1(RIP_ERROR, "_Win32MapViewInSessionSpace: Could not find section for %#p", 01311 Section); 01312 01313 LeaveSectionCrit(); 01314 01315 return STATUS_UNSUCCESSFUL; 01316 } 01317 01318 NTSTATUS _Win32UnmapViewInSessionSpace( 01319 PVOID MappedBase) 01320 { 01321 PWin32Section ps; 01322 PWin32MapView pv; 01323 NTSTATUS Status; 01324 01325 EnterSectionCrit(); 01326 01327 ps = gpSections; 01328 01329 while (ps != NULL) { 01330 01331 pv = ps->pFirstView; 01332 01333 while (pv != NULL) { 01334 01335 UserAssert(pv->pSection == ps); 01336 01337 if (pv->pViewBase == MappedBase) { 01338 /* 01339 * now, remove it from the linked list 01340 */ 01341 if (pv->pPrev == NULL) { 01342 01343 UserAssert(pv == ps->pFirstView); 01344 01345 ps->pFirstView = pv->pNext; 01346 01347 if (pv->pNext != NULL) { 01348 pv->pNext->pPrev = NULL; 01349 } 01350 } else { 01351 pv->pPrev->pNext = pv->pNext; 01352 if (pv->pNext != NULL) { 01353 pv->pNext->pPrev = pv->pPrev; 01354 } 01355 } 01356 01357 UserFreePool(pv); 01358 01359 Status = MmUnmapViewInSessionSpace(MappedBase); 01360 01361 LeaveSectionCrit(); 01362 01363 return Status; 01364 } 01365 pv = pv->pNext; 01366 } 01367 ps = ps->pNext; 01368 } 01369 01370 RIPMSG1(RIP_ERROR, "_Win32UnmapViewInSessionSpace: Could not find view for %#p", 01371 MappedBase); 01372 01373 LeaveSectionCrit(); 01374 01375 return STATUS_UNSUCCESSFUL; 01376 } 01377 01378 #endif // TRACE_MAP_VIEWS

Generated on Sat May 15 19:41:24 2004 for test by doxygen 1.3.7