﻿id	summary	reporter	owner	description	type	status	component	version	resolution	keywords	cc	guest	host
13722	ConsoleImpl.cpp race condition	a.urakov		"There is possible race condition in ''doMediumChange'' function of ''ConsoleImpl.cpp''. It appears in code
{{{
    /*
     * Call worker in EMT, that's faster and safer than doing everything
     * using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait
     * here to make requests from under the lock in order to serialize them.
     */
    PVMREQ pReq;
    int vrc = VMR3ReqCallU(pUVM, VMCPUID_ANY, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
                           (PFNRT)changeRemovableMedium, 8,
                           this, pUVM, pszDevice, uInstance, enmBus, fUseHostIOCache, aMediumAttachment, fForce);

    /* release the lock before waiting for a result (EMT will call us back!) */
    alock.release();

    if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc))
    {
        vrc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
        AssertRC(vrc);
        if (RT_SUCCESS(vrc))
            vrc = pReq->iStatus;
    }
    VMR3ReqFree(pReq);
}}}
when EMT thread completes request earlier than ''VMR3ReqWait'' (with zero wait time) in ''VMR3ReqQueue'' function is called:
{{{
        /*
         * Notify EMT.
         */
        if (pUVM->pVM)
            VMCPU_FF_SET(pVCpu, VMCPU_FF_REQUEST);
        VMR3NotifyCpuFFU(pUVCpu, fFlags & VMREQFLAGS_POKE ? VMNOTIFYFF_FLAGS_POKE : 0);

        //
        // !!! Request is already completed here !!!
        //

        /*
         * Wait and return.
         */
        if (!(fFlags & VMREQFLAGS_NO_WAIT))
            rc = VMR3ReqWait(pReq, cMillies);
        LogFlow((""VMR3ReqQueue: returns %Rrc\n"", rc));
}}}

In this case ''VMR3ReqWait'' of ''VMR3ReqQueue'' function (and all its callers ''VMR3ReqCallVU'' and ''VMR3ReqCallU'') returns ''VINF_SUCCESS'' instead of ''VERR_TIMEOUT'' and decreases ''pReq->EventSem''. So ''VMR3ReqWait(pReq, RT_INDEFINITE_WAIT)'' of ''doMediumChange'' indefinitely waits.

Possible solution (works for us) is to call ''VMR3ReqWait'' of ''doMediumChange'' only when it was not completed:
{{{
    if (vrc == VERR_TIMEOUT || RT_SUCCESS(vrc))
    {
        if (!RT_SUCCESS(vrc))
            vrc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
        AssertRC(vrc);
        if (RT_SUCCESS(vrc))
            vrc = pReq->iStatus;
    }
}}}

A similar problem exists in ''doCPURemove'', ''doCPUAdd'', ''doStorageDeviceAttach'', ''doStorageDeviceDetach'' etc."	defect	closed	other	VirtualBox 4.3.20	fixed	race condition, ConsoleImpl.cpp		Windows	Linux
