Index: /trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp	(revision 38954)
+++ /trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp	(revision 38955)
@@ -1063,4 +1063,5 @@
         STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,ChunkR3MapTlbHits));
         pMap = pTlbe->pChunk;
+        AssertPtr(pMap->pv);
     }
     else
@@ -1072,5 +1073,7 @@
          */
         pMap = (PPGMCHUNKR3MAP)RTAvlU32Get(&pVM->pgm.s.ChunkR3Map.pTree, idChunk);
-        if (!pMap)
+        if (pMap)
+            AssertPtr(pMap->pv);
+        else
         {
 #ifdef IN_RING0
@@ -1084,4 +1087,5 @@
                 return rc;
 #endif
+            AssertPtr(pMap->pv);
         }
 
Index: /trunk/src/VBox/VMM/VMMR3/PGMPhys.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PGMPhys.cpp	(revision 38954)
+++ /trunk/src/VBox/VMM/VMMR3/PGMPhys.cpp	(revision 38955)
@@ -3769,34 +3769,41 @@
 static DECLCALLBACK(int) pgmR3PhysChunkUnmapCandidateCallback(PAVLU32NODECORE pNode, void *pvUser)
 {
-    PPGMCHUNKR3MAP pChunk = (PPGMCHUNKR3MAP)pNode;
-    PPGMR3PHYSCHUNKUNMAPCB pArg = (PPGMR3PHYSCHUNKUNMAPCB)pvUser;
-
-    if (    pChunk->iAge
-        &&  !pChunk->cRefs
-        &&  pArg->iLastAge < pChunk->iAge)
-    {
-        /*
-         * Check that it's not in any of the TLBs.
-         */
-        PVM pVM = pArg->pVM;
-        for (unsigned i = 0; i < RT_ELEMENTS(pVM->pgm.s.ChunkR3Map.Tlb.aEntries); i++)
-            if (pVM->pgm.s.ChunkR3Map.Tlb.aEntries[i].pChunk == pChunk)
-            {
-                pChunk = NULL;
-                break;
-            }
-        if (pChunk)
-            for (unsigned i = 0; i < RT_ELEMENTS(pVM->pgm.s.PhysTlbHC.aEntries); i++)
-                if (pVM->pgm.s.PhysTlbHC.aEntries[i].pMap == pChunk)
-                {
-                    pChunk = NULL;
-                    break;
-                }
-        if (pChunk)
-        {
-            pArg->pChunk = pChunk;
-            pArg->iLastAge = pChunk->iAge;
-        }
-    }
+    PPGMCHUNKR3MAP          pChunk = (PPGMCHUNKR3MAP)pNode;
+    PPGMR3PHYSCHUNKUNMAPCB  pArg   = (PPGMR3PHYSCHUNKUNMAPCB)pvUser;
+
+    /*
+     * Check for locks and age.
+     */
+    if (pChunk->cRefs)
+        return 0;
+    if (!pChunk->iAge)
+        return 0;
+    if (pArg->iLastAge >= pChunk->iAge)
+        return 0;
+
+    /*
+     * Check that it's not in any of the TLBs.
+     */
+    PVM pVM = pArg->pVM;
+    if (   pVM->pgm.s.ChunkR3Map.Tlb.aEntries[PGM_CHUNKR3MAPTLB_IDX(pChunk->Core.Key)].idChunk
+        == pChunk->Core.Key)
+    {
+        pChunk = NULL;
+        return 0;
+    }
+#ifdef VBOX_STRICT
+    for (unsigned i = 0; i < RT_ELEMENTS(pVM->pgm.s.ChunkR3Map.Tlb.aEntries); i++)
+    {
+        Assert(pVM->pgm.s.ChunkR3Map.Tlb.aEntries[i].pChunk != pChunk);
+        Assert(pVM->pgm.s.ChunkR3Map.Tlb.aEntries[i].idChunk != pChunk->Core.Key);
+    }
+#endif
+
+    for (unsigned i = 0; i < RT_ELEMENTS(pVM->pgm.s.PhysTlbHC.aEntries); i++)
+        if (pVM->pgm.s.PhysTlbHC.aEntries[i].pMap == pChunk)
+            return 0;
+
+    pArg->pChunk   = pChunk;
+    pArg->iLastAge = pChunk->iAge;
     return 0;
 }
@@ -3838,4 +3845,6 @@
     if (Args.pChunk)
     {
+        Assert(Args.pChunk->cRefs == 0);
+        Assert(Args.pChunk->cPermRefs == 0);
         STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->StatChunkFindCandidate, a);
         return Args.pChunk->Core.Key;
@@ -3845,4 +3854,5 @@
     return INT32_MAX;
 }
+
 
 /**
@@ -3866,5 +3876,6 @@
     {
         /* Flush the pgm pool cache; call the internal rendezvous handler as we're already in a rendezvous handler here. */
-        /* todo: also not really efficient to unmap a chunk that contains PD or PT pages. */
+        /** @todo also not really efficient to unmap a chunk that contains PD
+         *  or PT pages. */
         pgmR3PoolClearAllRendezvous(pVM, &pVM->aCpus[0], NULL /* no need to flush the REM TLB as we already did that above */);
 
@@ -3874,9 +3885,8 @@
         GMMMAPUNMAPCHUNKREQ Req;
         Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
-        Req.Hdr.cbReq = sizeof(Req);
-        Req.pvR3 = NULL;
-        Req.idChunkMap = NIL_GMM_CHUNKID;
+        Req.Hdr.cbReq    = sizeof(Req);
+        Req.pvR3         = NULL;
+        Req.idChunkMap   = NIL_GMM_CHUNKID;
         Req.idChunkUnmap = pgmR3PhysChunkFindUnmapCandidate(pVM);
-
         if (Req.idChunkUnmap != INT32_MAX)
         {
@@ -3886,8 +3896,12 @@
             if (RT_SUCCESS(rc))
             {
-                /* remove the unmapped one. */
+                /*
+                 * Remove the unmapped one.
+                 */
                 PPGMCHUNKR3MAP pUnmappedChunk = (PPGMCHUNKR3MAP)RTAvlU32Remove(&pVM->pgm.s.ChunkR3Map.pTree, Req.idChunkUnmap);
                 AssertRelease(pUnmappedChunk);
-                pUnmappedChunk->pv = NULL;
+                AssertRelease(!pUnmappedChunk->cRefs);
+                AssertRelease(!pUnmappedChunk->cPermRefs);
+                pUnmappedChunk->pv       = NULL;
                 pUnmappedChunk->Core.Key = UINT32_MAX;
 #ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
@@ -3899,6 +3913,8 @@
                 pVM->pgm.s.cUnmappedChunks++;
 
-                /* Flush dangling PGM pointers (R3 & R0 ptrs to GC physical addresses) */
-                /* todo: we should not flush chunks which include cr3 mappings. */
+                /*
+                 * Flush dangling PGM pointers (R3 & R0 ptrs to GC physical addresses).
+                 */
+                /** todo: we should not flush chunks which include cr3 mappings. */
                 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
                 {
@@ -3993,15 +4009,4 @@
     if (RT_SUCCESS(rc))
     {
-        /*
-         * Update the tree.
-         */
-        /* insert the new one. */
-        AssertPtr(Req.pvR3);
-        pChunk->pv = Req.pvR3;
-        bool fRc = RTAvlU32Insert(&pVM->pgm.s.ChunkR3Map.pTree, &pChunk->Core);
-        AssertRelease(fRc);
-        pVM->pgm.s.ChunkR3Map.c++;
-        pVM->pgm.s.cMappedChunks++;
-
         /*
          * If we're running out of virtual address space, then we should
@@ -4021,5 +4026,5 @@
          *        map+unmap as one kernel call without any rendezvous or
          *        other precautions. */
-        if (pVM->pgm.s.ChunkR3Map.c >= pVM->pgm.s.ChunkR3Map.cMax)
+        if (pVM->pgm.s.ChunkR3Map.c + 1 >= pVM->pgm.s.ChunkR3Map.cMax)
         {
             switch (VMR3GetState(pVM))
@@ -4043,4 +4048,16 @@
             }
         }
+
+        /*
+         * Update the tree.  We must do this after any unmapping to make sure
+         * the chunk we're going to return isn't unmapped by accident.
+         */
+        /* insert the new one. */
+        AssertPtr(Req.pvR3);
+        pChunk->pv = Req.pvR3;
+        bool fRc = RTAvlU32Insert(&pVM->pgm.s.ChunkR3Map.pTree, &pChunk->Core);
+        AssertRelease(fRc);
+        pVM->pgm.s.ChunkR3Map.c++;
+        pVM->pgm.s.cMappedChunks++;
     }
     else
Index: /trunk/src/VBox/VMM/include/PGMInline.h
===================================================================
--- /trunk/src/VBox/VMM/include/PGMInline.h	(revision 38954)
+++ /trunk/src/VBox/VMM/include/PGMInline.h	(revision 38955)
@@ -491,4 +491,6 @@
         STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,PageMapTlbHits));
         rc = VINF_SUCCESS;
+        AssertPtr(pTlbe->pv);
+        Assert(!pTlbe->pMap || RT_VALID_PTR(pTlbe->pMap->pv));
     }
     else
