Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where is the memory leak in this C++?

I have been told be a couple of tools that the following code is leaking memory, but we can't for the life of us see where:

HRESULT CDatabaseValues::GetCStringField(ADODB::_RecordsetPtr& aRecordset, CString& strFieldValue,
                                         const char* strFieldName, const bool& bNullAllowed)
{
    HRESULT hr = E_FAIL;

    try
    {
        COleVariant olevar;
        olevar = aRecordset->Fields->GetItem(_bstr_t(strFieldName))->Value;
        if (olevar.vt == VT_BSTR && olevar.vt != VT_EMPTY)
        {
            strFieldValue = olevar.bstrVal;
            hr = true;
        }
        else if ((olevar.vt == VT_NULL || olevar.vt == VT_EMPTY) && bNullAllowed)
        {
            //ok, but still did not retrieve a field
            hr = S_OK;
            strFieldValue = "";
        }
    }
    catch(Exception^ error)
    {
        hr = E_FAIL;
        MLogger::Write(error);
    }
    return hr;
}

We assume it is something to do with the olevar variant as the size of the leak matches the size of the string being returned from the recordset.

I have tried olevar.detach() and olevar.clear(), both had no effect, so if this is the cause, how do I release the memory that is presumably allocated in GetItem. And if this is not the cause, what is?

EDIT

I read the article suggested by Ray and also the comments associated with it and then tried:

HRESULT CDatabaseValues::GetCStringField(ADODB::_RecordsetPtr& aRecordset, CString& strFieldValue,
                                         const char* strFieldName, const bool& bNullAllowed)
{
    HRESULT hr = E_FAIL;

    try
    {
        COleVariant* olevar = new COleVariant();
        _bstr_t* fieldName = new _bstr_t(strFieldName);
        *olevar = aRecordset->Fields->GetItem(*fieldName)->Value;
        if (olevar->vt == VT_BSTR && olevar->vt != VT_EMPTY)
        {
            strFieldValue = olevar->bstrVal;
            hr = true;
        }
        else if ((olevar->vt == VT_NULL || olevar->vt == VT_EMPTY) && bNullAllowed)
        {
            //ok, but still did not retrieve a field
            hr = S_OK;
            strFieldValue = "";
        }
        delete olevar;
        delete fieldName;
    }
    catch(Exception^ error)
    {
        hr = E_FAIL;
        MLogger::Write(error);
    }
    return hr;
}

Main differences being the olevariant and bstr are now explicitly created and destroyed.

This has roughly halved the volume of leak, but there is still something in here that is leaking.

Solution?

Looking at the advice from Ray about using Detach, I came up with this:

HRESULT CDatabaseValues::GetCStringField(ADODB::_RecordsetPtr& aRecordset, CString& strFieldValue,
                                         const char* strFieldName, const bool& bNullAllowed)
{
    HRESULT hr = E_FAIL;

    try
    {
        COleVariant olevar;
        _bstr_t fieldName = strFieldName;
        olevar = aRecordset->Fields->GetItem(fieldName)->Value;

        if (olevar.vt == VT_BSTR && olevar.vt != VT_EMPTY)
        {
            BSTR fieldValue = olevar.Detach().bstrVal;
            strFieldValue = fieldValue;
            ::SysFreeString(fieldValue);
            hr = true;
        }
        else if ((olevar.vt == VT_NULL || olevar.vt == VT_EMPTY) && bNullAllowed)
        {
            //ok, but still did not retrieve a field
            hr = S_OK;
            strFieldValue = "";
        }
        ::SysFreeString(fieldName);
    }
    catch(Exception^ error)
    {
        hr = E_FAIL;
        MLogger::Write(error);
    }
    return hr;
}

According to the tool (GlowCode) this is no longer leaking, but I am worried about using SysFreeString on fieldValue after it has been assigned to the CString. It appears to run, but I know that is no indication of being memory corruption free!

like image 665
Colin Desmond Avatar asked Mar 01 '23 11:03

Colin Desmond


1 Answers

You have to release memory allocated for BSTR.

See article

Oh, and you have to do a detach before assigning bstr value of VARIANT to CString

strFieldValue = olevar.detach().bstrVal;

and then ensure your CString object gets properly destroyed in time.

like image 63
Ray Avatar answered Mar 11 '23 02:03

Ray