Index: /trunk/include/VBox/log.h
===================================================================
--- /trunk/include/VBox/log.h	(revision 65219)
+++ /trunk/include/VBox/log.h	(revision 65220)
@@ -268,4 +268,6 @@
     /** IEM group. */
     LOG_GROUP_IEM,
+    /** I/O buffer management group. */
+    LOG_GROUP_IOBUFMGMT,
     /** IOM group. */
     LOG_GROUP_IOM,
@@ -915,4 +917,5 @@
     "HM",           \
     "IEM",          \
+    "IOBUFMGMT",    \
     "IOM",          \
     "IPC",          \
Index: /trunk/src/VBox/Devices/Storage/IOBufMgmt.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/IOBufMgmt.cpp	(revision 65219)
+++ /trunk/src/VBox/Devices/Storage/IOBufMgmt.cpp	(revision 65220)
@@ -15,6 +15,8 @@
  * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
  */
+#define LOG_GROUP LOG_GROUP_IOBUFMGMT
 #include <VBox/cdefs.h>
 #include <VBox/err.h>
+#include <VBox/log.h>
 #include <iprt/assert.h>
 #include <iprt/critsect.h>
@@ -22,5 +24,9 @@
 #include <iprt/memsafer.h>
 #include <iprt/sg.h>
+#include <iprt/string.h>
 #include <iprt/asm.h>
+
+/** Set to verify the allocations for distinct memory areas. */
+//#define IOBUFMGR_VERIFY_ALLOCATIONS 1
 
 /** The minimum bin size to create - power of two!. */
@@ -83,4 +89,8 @@
     /** Array of bins. */
     PIOBUFMGRBIN        paBins;
+#ifdef IOBUFMGR_VERIFY_ALLOCATIONS
+    /** Pointer to the object state (allocated/free) bitmap. */
+    void                *pbmObjState;
+#endif
     /** Array of pointer entries for the various bins - variable in size. */
     void               *apvObj[1];
@@ -131,4 +141,26 @@
 }
 
+DECLINLINE(void) iobufMgrBinObjAdd(PIOBUFMGRBIN pBin, void *pvObj)
+{
+    LogFlowFunc(("pBin=%#p{.iFree=%u} pvObj=%#p\n", pBin, pBin->iFree, pvObj));
+    AssertPtr(pvObj);
+    pBin->papvFree[pBin->iFree] = pvObj;
+    pBin->iFree++;
+    LogFlowFunc(("return pBin=%#p{.iFree=%u}\n", pBin, pBin->iFree));
+}
+
+DECLINLINE(void *) iobufMgrBinObjRemove(PIOBUFMGRBIN pBin)
+{
+    LogFlowFunc(("pBin=%#p{.iFree=%u}\n", pBin, pBin->iFree));
+    Assert(pBin->iFree > 0);
+
+    pBin->iFree--;
+    void *pvObj = pBin->papvFree[pBin->iFree];
+    AssertPtr(pvObj);
+
+    LogFlowFunc(("returns pvObj=%#p pBin=%#p{.iFree=%u}\n", pvObj, pBin, pBin->iFree));
+    return pvObj;
+}
+
 /**
  * Resets the bins to factory default (memory resigin in the largest bin).
@@ -157,8 +189,7 @@
             while (cbMax)
             {
-                pBin->papvFree[pBin->iFree] = pbMem;
+                iobufMgrBinObjAdd(pBin, pbMem);
                 cbMax -= cbBin;
                 pbMem += cbBin;
-                pBin->iFree++;
 
                 if (cbMax < cbBin) /** @todo Populate smaller bins and don't waste memory. */
@@ -216,6 +247,5 @@
             if (pBinCur->iFree != 0)
             {
-                pBinCur->iFree--;
-                uint8_t *pbMem = (uint8_t *)pBinCur->papvFree[pBinCur->iFree];
+                uint8_t *pbMem = (uint8_t *)iobufMgrBinObjRemove(pBinCur);
                 AssertPtr(pbMem);
 
@@ -225,11 +255,9 @@
                     iBinCur--;
                     pBinCur = &pThis->paBins[iBinCur];
-                    pBinCur->papvFree[pBinCur->iFree] = pbMem + (size_t)RT_BIT(iBinCur + pThis->u32OrderMin); /* (RT_BIT causes weird MSC warning without cast) */
-                    pBinCur->iFree++;
+                    iobufMgrBinObjAdd(pBinCur, pbMem + (size_t)RT_BIT(iBinCur + pThis->u32OrderMin)); /* (RT_BIT causes weird MSC warning without cast) */
                 }
 
                 /* For the last bin we will get two new memory blocks. */
-                pBinCur->papvFree[pBinCur->iFree] = pbMem;
-                pBinCur->iFree++;
+                iobufMgrBinObjAdd(pBinCur, pbMem);
                 Assert(pBin == pBinCur);
                 break;
@@ -270,6 +298,5 @@
     else if (pBin->iFree != 0)
     {
-        pBin->iFree--;
-        pSeg->pvSeg = pBin->papvFree[pBin->iFree];
+        pSeg->pvSeg = iobufMgrBinObjRemove(pBin);
         pSeg->cbSeg = (size_t)RT_BIT_32(u32Order);
         cbAlloc = pSeg->cbSeg;
@@ -277,4 +304,19 @@
 
         pThis->cbFree -= cbAlloc;
+
+#ifdef IOBUFMGR_VERIFY_ALLOCATIONS
+        /* Mark the objects as allocated. */
+        uint32_t iBinStart = ((uintptr_t)pSeg->pvSeg - (uintptr_t)pThis->pvMem) / IOBUFMGR_BIN_SIZE_MIN;
+        Assert(   !(((uintptr_t)pSeg->pvSeg - (uintptr_t)pThis->pvMem) % IOBUFMGR_BIN_SIZE_MIN)
+               && !(pSeg->cbSeg % IOBUFMGR_BIN_SIZE_MIN));
+        uint32_t iBinEnd = iBinStart + (pSeg->cbSeg / IOBUFMGR_BIN_SIZE_MIN);
+        while (iBinStart < iBinEnd)
+        {
+            bool fState = ASMBitTestAndSet(pThis->pbmObjState, iBinStart);
+            //LogFlowFunc(("iBinStart=%u fState=%RTbool -> true\n", iBinStart, fState));
+            AssertMsg(!fState, ("Trying to allocate an already allocated object\n"));
+            iBinStart++;
+        }
+#endif
     }
 
@@ -304,5 +346,12 @@
         pThis->paBins = (PIOBUFMGRBIN)((uint8_t *)pThis + RT_OFFSETOF(IOBUFMGRINT, apvObj[cObjs]));
 
-        rc = RTCritSectInit(&pThis->CritSectAlloc);
+#ifdef IOBUFMGR_VERIFY_ALLOCATIONS
+        pThis->pbmObjState = RTMemAllocZ((cbMax / IOBUFMGR_BIN_SIZE_MIN / 8) + 1);
+        if (!pThis->pbmObjState)
+            rc = VERR_NO_MEMORY;
+#endif
+
+        if (RT_SUCCESS(rc))
+            rc = RTCritSectInit(&pThis->CritSectAlloc);
         if (RT_SUCCESS(rc))
         {
@@ -351,4 +400,10 @@
                 RTMemPageFree(pThis->pvMem, RT_ALIGN_Z(pThis->cbMax, _4K));
 
+#ifdef IOBUFMGR_VERIFY_ALLOCATIONS
+            AssertPtr(pThis->pbmObjState);
+            RTMemFree(pThis->pbmObjState);
+            pThis->pbmObjState = NULL;
+#endif
+
             RTCritSectLeave(&pThis->CritSectAlloc);
             RTCritSectDelete(&pThis->CritSectAlloc);
@@ -369,4 +424,7 @@
 {
     PIOBUFMGRINT pThis = hIoBufMgr;
+
+    LogFlowFunc(("pThis=%#p pIoBufDesc=%#p cbIoBuf=%zu pcbIoBufAllocated=%#p\n",
+                 pThis, pIoBufDesc, cbIoBuf, pcbIoBufAllocated));
 
     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
@@ -418,4 +476,6 @@
     PIOBUFMGRINT pThis = pIoBufDesc->Int.pIoBufMgr;
 
+    LogFlowFunc(("pIoBufDesc=%#p{.cSegsUsed=%u}\n", pIoBufDesc, pIoBufDesc->Int.cSegsUsed));
+
     AssertPtr(pThis);
 
@@ -434,7 +494,25 @@
             Assert(iBin < pThis->cBins);
             PIOBUFMGRBIN pBin = &pThis->paBins[iBin];
-            pBin->papvFree[pBin->iFree] = pSeg->pvSeg;
-            pBin->iFree++;
+            iobufMgrBinObjAdd(pBin, pSeg->pvSeg);
             pThis->cbFree += pSeg->cbSeg;
+
+#ifdef IOBUFMGR_VERIFY_ALLOCATIONS
+            /* Mark the objects as free. */
+            uint32_t iBinStart = ((uintptr_t)pSeg->pvSeg - (uintptr_t)pThis->pvMem) / IOBUFMGR_BIN_SIZE_MIN;
+            Assert(   !(((uintptr_t)pSeg->pvSeg - (uintptr_t)pThis->pvMem) % IOBUFMGR_BIN_SIZE_MIN)
+                   && !(pSeg->cbSeg % IOBUFMGR_BIN_SIZE_MIN));
+            uint32_t iBinEnd = iBinStart + (pSeg->cbSeg / IOBUFMGR_BIN_SIZE_MIN);
+            while (iBinStart < iBinEnd)
+            {
+                bool fState = ASMBitTestAndClear(pThis->pbmObjState, iBinStart);
+                //LogFlowFunc(("iBinStart=%u fState=%RTbool -> false\n", iBinStart, fState));
+                AssertMsg(fState, ("Trying to free a non allocated object\n"));
+                iBinStart++;
+            }
+
+            /* Poison the state. */
+            pSeg->cbSeg = ~0;
+            pSeg->pvSeg = (void *)~(uintptr_t)0;
+#endif
         }
 
@@ -450,4 +528,7 @@
 
     pIoBufDesc->Int.cSegsUsed = 0;
-}
-
+#ifdef IOBUFMGR_VERIFY_ALLOCATIONS
+    memset(&pIoBufDesc->SgBuf, 0xff, sizeof(pIoBufDesc->SgBuf));
+#endif
+}
+
