What are the most frequently encountered causes for COM memory leaks? I have read that passing the address of an initialized CComBSTR to a function as an [out] parameter causes leak. I'm looking to enumerate other common programming mistakes like this.
Forgetting to call Release() when you should. Use CComPtr<>, CComVARIANT<> and CComBSTR to help you.
Failing to use RAII wrapper types for COM objects. In particular not using CComPtr<>
, CComBSTR
and CComVARIANT<>
. These objects help prevent leaks by removing the responsibility of releasing the underlying resource from the developer. The wrapping object enforces the release of resources in it's destructor.
Another cause of leaks or accidental frees I've seen is a result of the implicit conversion from CComPtr<T>
to T*
. This is useful for passing wrapped objects as arguments. But it can cause problems because it allows for the implicit conversion between a RAII object and a raw pointer. For example
CComPtr<IFoo> GetAFoo(); // Imagine if this creates the object
...
IFoo* pFoo = GetAFoo();
pFoo->SomeCall();
The call to SomeCall will likely fail in this scenario because the object pFoo is dead at this point. Why? The value was returned with a ref count of 1 from GetAFoo, assigned to pFoo and then decremented to 0 and deleted because the temporary value fell out of scope.
There're two main reasons: not using RAII (smart pointers) and misusing RAII.
If you use raw pointers - IInterface* or BSTR you risk forgetting to call IInterface::Release() or SysFreeString() and that will cause a leak. If you use smart pointers incorrectly you also risk memory leaks. One way to do it is the one you mention - passing an initialized CComBSTR::operator &() as an [out] parameter. There are other ways such as passing CComPtr::operator&() or CCOmQIPtr::operator&() of an initialized smart pointer as an [out] parameter with ATLASSERTs disabled. Or creating any graph-like structure with a loop and releasing it entirely so that the object in the loop each hold smart pointers to each other and prevent releasing.