0

inside my MFC (VC2010 SP1) project, I'm widely using a third party library to write some data in a database. This library is quite old (I've found it compiled for VS2005) and uses _variant_t to handle data.

In a particular case anyway I get a strange behaviour, I'll try to explain it:

// .h
struct myData
{
   blastuff
   CString strMyCode;
};

class MyClass
{
    protected:
        myData m_Foo;
};

// .cpp
// In OnInitDialog:
//...
      TrdPartRecordset   *pRS;

      //...
      pRS->GetFieldValue( _T("MyDBColumn"), m_Foo.strMyCode );

Now, I do my job and when user press OK, it's time to save to database and here start the problems:

 // In OnOK
      TrdPartRecordset   *pRS;
      //...
      pRS->SetFieldValue( _T("MyDBColumn"), m_Foo.strMyCode );

Problem: if I do not modify m_Foo.strMyCode, I don't have any problem. What if I modify it? Well, if m_Foo.strMyCode does NOT contain ANY number, still have no problem. Instead, when I have a number, I get a nasty error:

Unhandled exception at 0x77772d37 in Mosaico.exe: 0xC0000005: Access violation reading location 0x9d7077b7.

which is an attempt to read a deleted location. I've checked m_Foo in the watch and it's correct and valid, so I've digged into library source code:

BOOL TrdPartyRecordset::SetFieldValue(LPCTSTR lpFieldName, CString strValue)
{
      _variant_t vtFld;

  if(!strValue.IsEmpty())
    vtFld.vt = VT_BSTR;
  else
     vtFld.vt = VT_NULL;

  vtFld.bstrVal = strValue.AllocSysString();

  BOOL bret =  PutFieldValue(lpFieldName, vtFld);
  SysFreeString(vtFld.bstrVal);
  return bret;
}

What it happens is that vtFld is valid until SysFreeString and it get destroyed after it (I can see it proceding step-by-step with debugger), but ONLY WHEN I HAVE NUMBERS INTO strValue. This doesn't happen when strValue is pure alphabetical.

I've searched around the Internet and found that this kind of error happens when you double release a resource and so I've commented out SysFreeString and boom goes the dynamite: no more crashes.

Anyway is a better programmer than me so I guess that if he put that SysFreeString he had his reasons, moreover, this is the only part of my program where this mechanism crashes.

My question is: do I lose memory commenting out that SysFreeString? Another one: do you have better solutions?

IssamTP
  • 2,408
  • 1
  • 25
  • 48

1 Answers1

1

The reason is simple: The memory is freed twice!

_variant_t has a destructor. Set the type to VT_BSTR. You also see the pojnter and type to VT_BSTR

After the function you call, you free the memory again and the destructor does the same.

The code should look like this:

_variant_t vtFld;
if(!strValue.IsEmpty())
    vtFld = strValue;
else
    vtFld.vt = VT_NULL;
return PutFieldValue(lpFieldName, vtFld);
xMRi
  • 14,982
  • 3
  • 26
  • 59
  • Well, this will probably be the correct answer and what I'll do, but let me ask you another question: why this stuff works correctly elsewhere? And why it crashes only with numbers? – IssamTP Apr 02 '14 at 09:45
  • 1
    This code will only work if you use a VARIANT type. But never with _variant_t. Never! The destructor will always call VariantClear and this will call SysFreeString for a second time. Remember that VariantClear is save for alls types that do not allocate/free Memory, or do not influence an IUnkown Interface. – xMRi Apr 02 '14 at 20:18
  • Ok! Thanks! I'm asking because I've never seen so weird behaviours. – IssamTP Apr 03 '14 at 06:45