test: pool.c Source File

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