Index: /trunk/src/VBox/Devices/VMMDev/VMMDev.cpp
===================================================================
--- /trunk/src/VBox/Devices/VMMDev/VMMDev.cpp	(revision 25642)
+++ /trunk/src/VBox/Devices/VMMDev/VMMDev.cpp	(revision 25643)
@@ -78,5 +78,5 @@
 
 /** The saved state version. */
-#define VMMDEV_SAVED_STATE_VERSION          12
+#define VMMDEV_SAVED_STATE_VERSION          13
 /** The saved state version used by VirtualBox 3.0.
  *  This doesn't have the config part. */
Index: /trunk/src/VBox/Devices/VMMDev/VMMDevHGCM.cpp
===================================================================
--- /trunk/src/VBox/Devices/VMMDev/VMMDevHGCM.cpp	(revision 25642)
+++ /trunk/src/VBox/Devices/VMMDev/VMMDevHGCM.cpp	(revision 25643)
@@ -79,15 +79,4 @@
     struct VBOXHGCMCMD *pPrev;
 
-    /* Size of memory buffer for this command structure, including trailing paHostParms.
-     * This field simplifies loading of saved state.
-     */
-/** @todo @bugref{4500} - Now that we require states to be portable between
- * systems and between 32-bit/64-bit variants of the same OS, this field no
- * longer simplifies loading of saved state. :-(  Needs proper fixing... */
-    uint32_t cbCmd;
-/** HACK ALERT! (TEMPORARY)
- * Factor to muliply cbCmd by when reading it from a saved state.  */
-#define CMD_SIZE_HACK_FACTOR    4
-
     /* The type of the command. */
     VBOXHGCMCMDTYPE enmCmdType;
@@ -455,8 +444,17 @@
 }
 
-static void logRelSavedCmdSizeMismatch (const char *pszFunction, uint32_t cbExpected, uint32_t cbCmdSize)
-{
-    LogRel(("Warning: VMMDev %s command length %d (expected %d)\n",
-            pszFunction, cbCmdSize, cbExpected));
+static void vmmdevRestoreSavedCommand(VBOXHGCMCMD *pCmd, VBOXHGCMCMD *pSavedCmd)
+{
+    /* Copy relevant saved command information to the new allocated structure. */
+    pCmd->enmCmdType   = pSavedCmd->enmCmdType;
+    pCmd->fCancelled   = pSavedCmd->fCancelled;
+    pCmd->GCPhys       = pSavedCmd->GCPhys;
+    pCmd->cbSize       = pSavedCmd->cbSize;
+    pCmd->cLinPtrs     = pSavedCmd->cLinPtrs;
+    pCmd->cLinPtrPages = pSavedCmd->cLinPtrPages;
+    pCmd->paLinPtrs    = pSavedCmd->paLinPtrs;
+    
+    /* The new allocated command owns the 'paLinPtrs' pointer. */
+    pSavedCmd->paLinPtrs = NULL;
 }
 
@@ -477,5 +475,4 @@
         memcpy(pHGCMConnectCopy, pHGCMConnect, pHGCMConnect->header.header.size);
 
-        pCmd->cbCmd       = cbCmdSize;
         pCmd->paHostParms = NULL;
         pCmd->cLinPtrs = 0;
@@ -483,6 +480,6 @@
 
         /* Only allow the guest to use existing services! */
-        Assert(pHGCMConnect->loc.type == VMMDevHGCMLoc_LocalHost_Existing);
-        pHGCMConnect->loc.type = VMMDevHGCMLoc_LocalHost_Existing;
+        Assert(pHGCMConnectCopy->loc.type == VMMDevHGCMLoc_LocalHost_Existing);
+        pHGCMConnectCopy->loc.type = VMMDevHGCMLoc_LocalHost_Existing;
 
         rc = pVMMDevState->pHGCMDrv->pfnConnect (pVMMDevState->pHGCMDrv, pCmd, &pHGCMConnectCopy->loc, &pHGCMConnectCopy->u32ClientID);
@@ -496,32 +493,38 @@
 }
 
-static int vmmdevHGCMConnectSaved (VMMDevState *pVMMDevState, VMMDevHGCMConnect *pHGCMConnect, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd)
+static int vmmdevHGCMConnectSaved (VMMDevState *pVMMDevState, VMMDevHGCMConnect *pHGCMConnect, RTGCPHYS GCPhys, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd, VBOXHGCMCMD **ppCmd)
 {
     int rc = VINF_SUCCESS;
 
+    /* Allocate buffer for the new command. */
     uint32_t cbCmdSize = sizeof (struct VBOXHGCMCMD) + pHGCMConnect->header.header.size;
 
-#ifdef CMD_SIZE_HACK_FACTOR /*HACK ALERT!*/
-    if (pSavedCmd->cbCmd * CMD_SIZE_HACK_FACTOR < cbCmdSize)
-#else
-    if (pSavedCmd->cbCmd < cbCmdSize)
-#endif
-    {
-        logRelSavedCmdSizeMismatch ("HGCMConnect", pSavedCmd->cbCmd, cbCmdSize);
-        return VERR_INVALID_PARAMETER;
-    }
-
-    VMMDevHGCMConnect *pHGCMConnectCopy = (VMMDevHGCMConnect *)(pSavedCmd+1);
-
-    memcpy(pHGCMConnectCopy, pHGCMConnect, pHGCMConnect->header.header.size);
-
-    /* Only allow the guest to use existing services! */
-    Assert(pHGCMConnect->loc.type == VMMDevHGCMLoc_LocalHost_Existing);
-    pHGCMConnect->loc.type = VMMDevHGCMLoc_LocalHost_Existing;
-
-    rc = pVMMDevState->pHGCMDrv->pfnConnect (pVMMDevState->pHGCMDrv, pSavedCmd, &pHGCMConnectCopy->loc, &pHGCMConnectCopy->u32ClientID);
-    if (RT_SUCCESS (rc))
-    {
-        *pfHGCMCalled = true;
+    PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (cbCmdSize);
+
+    if (pCmd)
+    {
+        vmmdevRestoreSavedCommand(pCmd, pSavedCmd);
+        *ppCmd = pCmd;
+
+        VMMDevHGCMConnect *pHGCMConnectCopy = (VMMDevHGCMConnect *)(pCmd+1);
+
+        vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMConnect->header.header.size, VBOXHGCMCMDTYPE_CONNECT);
+
+        memcpy(pHGCMConnectCopy, pHGCMConnect, pHGCMConnect->header.header.size);
+
+        /* Only allow the guest to use existing services! */
+        Assert(pHGCMConnectCopy->loc.type == VMMDevHGCMLoc_LocalHost_Existing);
+        pHGCMConnectCopy->loc.type = VMMDevHGCMLoc_LocalHost_Existing;
+
+        rc = pVMMDevState->pHGCMDrv->pfnConnect (pVMMDevState->pHGCMDrv, pCmd, &pHGCMConnectCopy->loc, &pHGCMConnectCopy->u32ClientID);
+
+        if (RT_SUCCESS (rc))
+        {
+            *pfHGCMCalled = true;
+        }
+    }
+    else
+    {
+        rc = VERR_NO_MEMORY;
     }
 
@@ -541,5 +544,4 @@
         vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMDisconnect->header.header.size, VBOXHGCMCMDTYPE_DISCONNECT);
 
-        pCmd->cbCmd       = cbCmdSize;
         pCmd->paHostParms = NULL;
         pCmd->cLinPtrs = 0;
@@ -556,5 +558,5 @@
 }
 
-static int vmmdevHGCMDisconnectSaved (VMMDevState *pVMMDevState, VMMDevHGCMDisconnect *pHGCMDisconnect, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd)
+static int vmmdevHGCMDisconnectSaved (VMMDevState *pVMMDevState, VMMDevHGCMDisconnect *pHGCMDisconnect, RTGCPHYS GCPhys, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd, VBOXHGCMCMD **ppCmd)
 {
     int rc = VINF_SUCCESS;
@@ -562,18 +564,27 @@
     uint32_t cbCmdSize = sizeof (struct VBOXHGCMCMD);
 
-#ifdef CMD_SIZE_HACK_FACTOR  /*HACK ALERT!*/
-    if (pSavedCmd->cbCmd * CMD_SIZE_HACK_FACTOR < cbCmdSize)
-#else
-    if (pSavedCmd->cbCmd < cbCmdSize)
-#endif
-    {
-        logRelSavedCmdSizeMismatch ("HGCMConnect", pSavedCmd->cbCmd, cbCmdSize);
-        return VERR_INVALID_PARAMETER;
-    }
-
-    rc = pVMMDevState->pHGCMDrv->pfnDisconnect (pVMMDevState->pHGCMDrv, pSavedCmd, pHGCMDisconnect->u32ClientID);
-    if (RT_SUCCESS (rc))
-    {
-        *pfHGCMCalled = true;
+    PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (cbCmdSize);
+
+    if (pCmd)
+    {
+        vmmdevRestoreSavedCommand(pCmd, pSavedCmd);
+        *ppCmd = pCmd;
+
+        vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMDisconnect->header.header.size, VBOXHGCMCMDTYPE_DISCONNECT);
+
+        pCmd->paHostParms = NULL;
+        pCmd->cLinPtrs = 0;
+        pCmd->paLinPtrs = NULL;
+
+        rc = pVMMDevState->pHGCMDrv->pfnDisconnect (pVMMDevState->pHGCMDrv, pCmd, pHGCMDisconnect->u32ClientID);
+
+        if (RT_SUCCESS (rc))
+        {
+            *pfHGCMCalled = true;
+        }
+    }
+    else
+    {
+        rc = VERR_NO_MEMORY;
     }
 
@@ -727,5 +738,4 @@
     memset (pCmd, 0, sizeof (*pCmd));
 
-    pCmd->cbCmd       = cbCmdSize;
     pCmd->paHostParms = NULL;
     pCmd->cLinPtrs    = cLinPtrs;
@@ -1087,5 +1097,5 @@
 
 
-static int vmmdevHGCMCallSaved (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, uint32_t cbHGCMCall, bool f64Bits, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd)
+static int vmmdevHGCMCallSaved (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, RTGCPHYS GCPhys, uint32_t cbHGCMCall, bool f64Bits, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd, VBOXHGCMCMD **ppCmd)
 {
     int rc = VINF_SUCCESS;
@@ -1107,5 +1117,141 @@
      */
 
-    pSavedCmd->paHostParms = NULL;
+    uint32_t cbCmdSize = sizeof (struct VBOXHGCMCMD) + cParms * sizeof (VBOXHGCMSVCPARM);
+
+    uint32_t i;
+
+    uint32_t cLinPtrs = 0;
+    uint32_t cLinPtrPages  = 0;
+
+    if (f64Bits)
+    {
+#ifdef VBOX_WITH_64_BITS_GUESTS
+        HGCMFunctionParameter64 *pGuestParm = VMMDEV_HGCM_CALL_PARMS64(pHGCMCall);
+#else
+        HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
+        AssertFailed (); /* This code should not be called in this case */
+#endif /* VBOX_WITH_64_BITS_GUESTS */
+
+        /* Look for pointer parameters, which require a host buffer. */
+        for (i = 0; i < cParms && RT_SUCCESS(rc); i++, pGuestParm++)
+        {
+            switch (pGuestParm->type)
+            {
+                case VMMDevHGCMParmType_LinAddr_In:  /* In (read) */
+                case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
+                case VMMDevHGCMParmType_LinAddr:     /* In & Out */
+                {
+                    if (pGuestParm->u.Pointer.size > 0)
+                    {
+                        /* Only pointers with some actual data are counted. */
+                        cbCmdSize += pGuestParm->u.Pointer.size;
+
+                        cLinPtrs++;
+                        /* Take the offset into the current page also into account! */
+                        cLinPtrPages += ((pGuestParm->u.Pointer.u.linearAddr & PAGE_OFFSET_MASK)
+                                          + pGuestParm->u.Pointer.size + PAGE_SIZE - 1) / PAGE_SIZE;
+                    }
+
+                    Log(("vmmdevHGCMCall: linptr size = %d\n", pGuestParm->u.Pointer.size));
+                } break;
+
+                case VMMDevHGCMParmType_PageList:
+                {
+                    cbCmdSize += pGuestParm->u.PageList.size;
+                    Log(("vmmdevHGCMCall: pagelist size = %d\n", pGuestParm->u.PageList.size));
+                } break;
+
+                case VMMDevHGCMParmType_32bit:
+                case VMMDevHGCMParmType_64bit:
+                {
+                } break;
+
+                default:
+                case VMMDevHGCMParmType_PhysAddr:
+                {
+                    AssertMsgFailed(("vmmdevHGCMCall: invalid parameter type %x\n", pGuestParm->type));
+                    rc = VERR_INVALID_PARAMETER;
+                    break;
+                }
+            }
+        }
+    }
+    else
+    {
+#ifdef VBOX_WITH_64_BITS_GUESTS
+        HGCMFunctionParameter32 *pGuestParm = VMMDEV_HGCM_CALL_PARMS32(pHGCMCall);
+#else
+        HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
+#endif /* VBOX_WITH_64_BITS_GUESTS */
+
+        /* Look for pointer parameters, which require a host buffer. */
+        for (i = 0; i < cParms && RT_SUCCESS(rc); i++, pGuestParm++)
+        {
+            switch (pGuestParm->type)
+            {
+                case VMMDevHGCMParmType_LinAddr_In:  /* In (read) */
+                case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
+                case VMMDevHGCMParmType_LinAddr:     /* In & Out */
+                {
+                    if (pGuestParm->u.Pointer.size > 0)
+                    {
+                        /* Only pointers with some actual data are counted. */
+                        cbCmdSize += pGuestParm->u.Pointer.size;
+
+                        cLinPtrs++;
+                        /* Take the offset into the current page also into account! */
+                        cLinPtrPages += ((pGuestParm->u.Pointer.u.linearAddr & PAGE_OFFSET_MASK)
+                                          + pGuestParm->u.Pointer.size + PAGE_SIZE - 1) / PAGE_SIZE;
+                    }
+
+                    Log(("vmmdevHGCMCall: linptr size = %d\n", pGuestParm->u.Pointer.size));
+                } break;
+
+                case VMMDevHGCMParmType_PageList:
+                {
+                    cbCmdSize += pGuestParm->u.PageList.size;
+                    Log(("vmmdevHGCMCall: pagelist size = %d\n", pGuestParm->u.PageList.size));
+                } break;
+
+                case VMMDevHGCMParmType_32bit:
+                case VMMDevHGCMParmType_64bit:
+                {
+                } break;
+
+                default:
+                {
+                    AssertMsgFailed(("vmmdevHGCMCall: invalid parameter type %x\n", pGuestParm->type));
+                    rc = VERR_INVALID_PARAMETER;
+                    break;
+                }
+            }
+        }
+    }
+
+    if (RT_FAILURE (rc))
+    {
+        return rc;
+    }
+
+    if (   pSavedCmd->cLinPtrs     != cLinPtrs
+        || pSavedCmd->cLinPtrPages != cLinPtrPages)
+    {
+        LogRel(("VMMDev: invalid saved command ptrs: %d/%d, pages %d/%d\n",
+                pSavedCmd->cLinPtrs, cLinPtrs, pSavedCmd->cLinPtrPages, cLinPtrPages));
+        AssertFailed();
+        return VERR_INVALID_PARAMETER;
+    }
+
+    PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (cbCmdSize);
+
+    if (pCmd == NULL)
+    {
+        return VERR_NO_MEMORY;
+    }
+
+    vmmdevRestoreSavedCommand(pCmd, pSavedCmd);
+    *ppCmd = pCmd;
+
+    vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMCall->header.header.size, VBOXHGCMCMDTYPE_CALL);
 
     /* Process parameters, changing them to host context pointers for easy
@@ -1117,9 +1263,9 @@
     {
         /* Compute addresses of host parms array and first memory buffer. */
-        VBOXHGCMSVCPARM *pHostParm = (VBOXHGCMSVCPARM *)((uint8_t *)pSavedCmd + sizeof (struct VBOXHGCMCMD));
+        VBOXHGCMSVCPARM *pHostParm = (VBOXHGCMSVCPARM *)((uint8_t *)pCmd + sizeof (struct VBOXHGCMCMD));
 
         uint8_t *pu8Buf = (uint8_t *)pHostParm + cParms * sizeof (VBOXHGCMSVCPARM);
 
-        pSavedCmd->paHostParms = pHostParm;
+        pCmd->paHostParms = pHostParm;
 
         uint32_t iParm;
@@ -1186,13 +1332,13 @@
                              if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_Out)
                              {
-                                 if (   iLinPtr >= pSavedCmd->cLinPtrs
-                                     || pSavedCmd->paLinPtrs[iLinPtr].iParm != iParm)
+                                 if (   iLinPtr >= pCmd->cLinPtrs
+                                     || pCmd->paLinPtrs[iLinPtr].iParm != iParm)
                                  {
-                                     logRelLoadStatePointerIndexMismatch (iParm, pSavedCmd->paLinPtrs[iLinPtr].iParm, iLinPtr, pSavedCmd->cLinPtrs);
+                                     logRelLoadStatePointerIndexMismatch (iParm, pCmd->paLinPtrs[iLinPtr].iParm, iLinPtr, pCmd->cLinPtrs);
                                      rc = VERR_INVALID_PARAMETER;
                                  }
                                  else
                                  {
-                                     VBOXHGCMLINPTR *pLinPtr = &pSavedCmd->paLinPtrs[iLinPtr];
+                                     VBOXHGCMLINPTR *pLinPtr = &pCmd->paLinPtrs[iLinPtr];
 
                                      uint32_t iPage;
@@ -1366,13 +1512,13 @@
                              if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_Out)
                              {
-                                 if (   iLinPtr >= pSavedCmd->cLinPtrs
-                                     || pSavedCmd->paLinPtrs[iLinPtr].iParm != iParm)
+                                 if (   iLinPtr >= pCmd->cLinPtrs
+                                     || pCmd->paLinPtrs[iLinPtr].iParm != iParm)
                                  {
-                                     logRelLoadStatePointerIndexMismatch (iParm, pSavedCmd->paLinPtrs[iLinPtr].iParm, iLinPtr, pSavedCmd->cLinPtrs);
+                                     logRelLoadStatePointerIndexMismatch (iParm, pCmd->paLinPtrs[iLinPtr].iParm, iLinPtr, pCmd->cLinPtrs);
                                      rc = VERR_INVALID_PARAMETER;
                                  }
                                  else
                                  {
-                                     VBOXHGCMLINPTR *pLinPtr = &pSavedCmd->paLinPtrs[iLinPtr];
+                                     VBOXHGCMLINPTR *pLinPtr = &pCmd->paLinPtrs[iLinPtr];
 
                                      uint32_t iPage;
@@ -1492,5 +1638,5 @@
     {
         /* Pass the function call to HGCM connector for actual processing */
-        rc = pVMMDevState->pHGCMDrv->pfnCall (pVMMDevState->pHGCMDrv, pSavedCmd, pHGCMCall->u32ClientID, pHGCMCall->u32Function, cParms, pSavedCmd->paHostParms);
+        rc = pVMMDevState->pHGCMDrv->pfnCall (pVMMDevState->pHGCMDrv, pCmd, pHGCMCall->u32ClientID, pHGCMCall->u32Function, cParms, pCmd->paHostParms);
         if (RT_SUCCESS (rc))
         {
@@ -2106,9 +2252,4 @@
              */
 
-            /* Size of entire command. */
-/** @todo @bugref{4500} - Not portable, see other todos. */
-            rc = SSMR3PutU32(pSSM, pIter->cbCmd);
-            AssertRCReturn(rc, rc);
-
             /* The type of the command. */
             rc = SSMR3PutU32(pSSM, (uint32_t)pIter->enmCmdType);
@@ -2210,4 +2351,6 @@
             AssertReturn(pCmd, VERR_NO_MEMORY);
 
+            pCmd->enmCmdType = VBOXHGCMCMDTYPE_LOADSTATE; /* This marks the "old" saved command. */
+
             vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, cbSize, VBOXHGCMCMDTYPE_LOADSTATE);
         }
@@ -2236,12 +2379,18 @@
             LogFlowFunc (("Restoring %RGp size %x bytes\n", GCPhys, cbSize));
 
-            /* Size of entire command. */
-/** @todo @bugref{4500} - Not portable, see other todos. */
-            rc = SSMR3GetU32(pSSM, &u32);
-            AssertRCReturn(rc, rc);
-
-            PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (u32 * CMD_SIZE_HACK_FACTOR); /*HACK ALERT!*/
+            /* For uVersion <= 12, this was the size of entire command.
+             * Now the size is recalculated in vmmdevHGCMLoadStateDone.
+             */
+            if (uVersion <= 12)
+            {
+                rc = SSMR3Skip(pSSM, sizeof (uint32_t));
+                AssertRCReturn(rc, rc);
+            }
+
+            /* Allocate only VBOXHGCMCMD structure. vmmdevHGCMLoadStateDone will rellocate the command
+             * with aditional space for parameters and for pointer/pagelists buffer.
+             */
+            PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (sizeof (VBOXHGCMCMD));
             AssertReturn(pCmd, VERR_NO_MEMORY);
-            pCmd->cbCmd = u32;
 
             /* The type of the command. */
@@ -2352,7 +2501,15 @@
          * New commands will be inserted at the list head, so they will not be seen by
          * this loop.
+         *
+         * Note: The list contains only VBOXHGCMCMD structures, place for HGCM parameters
+         *       and for data buffers has not been allocated.
+         *       Command handlers compute the command size and reallocate it before
+         *       resubmitting the command to HGCM services.
+         *       New commands will be inserted to the list.
          */
         PVBOXHGCMCMD pIter = pVMMDevState->pHGCMCmdList;
 
+        pVMMDevState->pHGCMCmdList = NULL; /* Reset the list. Saved commands will be processed and deallocated. */
+
         while (pIter)
         {
@@ -2363,4 +2520,6 @@
 
             PVBOXHGCMCMD pNext = pIter->pNext;
+
+            PVBOXHGCMCMD pCmd = NULL; /* Resubmitted command. */
 
             VMMDevHGCMRequestHeader *requestHeader = (VMMDevHGCMRequestHeader *)RTMemAllocZ (pIter->cbSize);
@@ -2410,5 +2569,5 @@
                                 Log(("VMMDevReq_HGCMConnect\n"));
 
-                                requestHeader->header.rc = vmmdevHGCMConnectSaved (pVMMDevState, pHGCMConnect, &fHGCMCalled, pIter);
+                                requestHeader->header.rc = vmmdevHGCMConnectSaved (pVMMDevState, pHGCMConnect, pIter->GCPhys, &fHGCMCalled, pIter, &pCmd);
                             }
                             break;
@@ -2432,5 +2591,5 @@
 
                                 Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
-                                requestHeader->header.rc = vmmdevHGCMDisconnectSaved (pVMMDevState, pHGCMDisconnect, &fHGCMCalled, pIter);
+                                requestHeader->header.rc = vmmdevHGCMDisconnectSaved (pVMMDevState, pHGCMDisconnect, pIter->GCPhys, &fHGCMCalled, pIter, &pCmd);
                             }
                             break;
@@ -2462,5 +2621,5 @@
                                 bool f64Bits = false;
 #endif /* VBOX_WITH_64_BITS_GUESTS */
-                                requestHeader->header.rc = vmmdevHGCMCallSaved (pVMMDevState, pHGCMCall, requestHeader->header.size, f64Bits, &fHGCMCalled, pIter);
+                                requestHeader->header.rc = vmmdevHGCMCallSaved (pVMMDevState, pHGCMCall, pIter->GCPhys, requestHeader->header.size, f64Bits, &fHGCMCalled, pIter, &pCmd);
                             }
                             break;
@@ -2565,5 +2724,5 @@
             if (pIter->enmCmdType == VBOXHGCMCMDTYPE_LOADSTATE)
             {
-                /* Old saved state. Remove the LOADSTATE command. */
+                /* Old saved state. */
 
                 /* Write back the request */
@@ -2571,13 +2730,4 @@
                 RTMemFree(requestHeader);
                 requestHeader = NULL;
-
-                vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
-
-                if (pIter->paLinPtrs != NULL)
-                {
-                     RTMemFree(pIter->paLinPtrs);
-                }
-
-                RTMemFree(pIter);
             }
             else
@@ -2598,12 +2748,16 @@
                 {
                    /* HGCM was not called. Deallocate the current command and then notify guest. */
-                   vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
-
-                   if (pIter->paLinPtrs != NULL)
+                   if (pCmd)
                    {
-                        RTMemFree(pIter->paLinPtrs);
+                       vmmdevHGCMRemoveCommand (pVMMDevState, pCmd);
+
+                       if (pCmd->paLinPtrs != NULL)
+                       {
+                           RTMemFree(pCmd->paLinPtrs);
+                       }
+
+                       RTMemFree(pCmd);
+                       pCmd = NULL;
                    }
-
-                   RTMemFree(pIter);
 
                    VMMDevNotifyGuest (pVMMDevState, VMMDEV_EVENT_HGCM);
@@ -2611,4 +2765,12 @@
             }
 
+            /* Deallocate the saved command structure. */
+            if (pIter->paLinPtrs != NULL)
+            {
+                RTMemFree(pIter->paLinPtrs);
+            }
+
+            RTMemFree(pIter);
+
             pIter = pNext;
         }
