Reputation: 12237
My leak checker tells me there is 2nd chance exception in this function.
BOOL CADORecordset::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;
}
Now _variant_t
has a type BSTR member (bstrVal
). We know that BSTR needs to be de-allocated using SystemFreeString()
which is what is done in the code above but since this BSTR is member of _variant_t
who has its own destructor which cleans up, who should really clean up the bstrVal
member in this case?
inline _variant_t::~_variant_t() throw()
{
::VariantClear(this);
}
It appears to me that this tries to clean up the memory again which is already cleaned up by SysFreeString()
causing the exception? The documentation says it clears the variant but it is not clear what exactly it clears, does it free up the bstrVal
as well?
If I remove the call SysFreeString(vtFld.bstrVal);
this does remove the 2nd chance exception but I really want to know that's the right thing to do because the documentation doesn't give enough confidence.
Upvotes: 0
Views: 2463
Reputation: 632
variant_t
owns its data and uses the VariantClear()
function for cleanup:
The function clears a VARIANTARG by setting the vt field to VT_EMPTY. The current contents of the VARIANTARG are released first. If the vtfield is VT_BSTR, the string is freed. If the vtfield is VT_DISPATCH, the object is released. If the vt field has the VT_ARRAY bit set, the array is freed.
_variant_t
is a wrapper which takes care of memory management. Similar to _bstr_t
, which manages a BSTR
; they work best together. Instead of manually setting the vt
field and the bstrVal
value, it's better to use the variant_t
constructor or operator=
. _bstr_t
will allocate and pass BSTR
ownership to _variant_t
. I don't remember the details of using it. Just look up the details on MSDN.
Upvotes: 2
Reputation: 596998
_variant_t
automatically cleans up its data when it goes out of scope. You are manually calling SysFreeString()
, but you are not setting bstrVal
to NULL or setting vt
to VT_EMPTY
afterwards. So, when the variant_t
destructor calls VariantClear()
to clean up the data, it tries to free the bstrVal
again and crashes.
So, simply do not call SysFreeString()
manually at all. If you ever need to reset a variant_t
manually, use its Clear()
method instead:
vtFld.Clear();
Upvotes: 5