I'm analyzing a handle leak and memory leak in a Outlook plugin.
I put my analysis step here, as I hardly have any c++ knowledge (Last time I used c++ is 7 years ago).
After searching from Google, I used WinDbg's !htrace -diff command to find the handle leak. Also, I used umdh to get the memory difference.
By comparing the 2 results I found there are many same call stacks that seem contribute both:
Here is handle diff informantion:
0x77ce55f4: ntdll!NtCreateEvent+0x0000000c
0x75d978a6: KERNELBASE!CreateEventExW+0x0000006e
0x75d97926: KERNELBASE!CreateEventExA+0x00000035
0x75d97965: KERNELBASE!CreateEventA+0x00000027
0x6740738b: olmapi32!HrLogAndRunFnOnThreadEx+0x000002c4
0x67407295: olmapi32!HrLogAndRunFnOnThreadEx+0x000001ce
0x674075cf: olmapi32!HrLogAndRunFnOnThreadEx+0x00000508
0x6740758e: olmapi32!HrLogAndRunFnOnThreadEx+0x000004c7
0x6741cfb2: olmapi32!REFTRACK_WrapObject+0x00000b30
0x6741cf37: olmapi32!REFTRACK_WrapObject+0x00000ab5
0x6741ce55: olmapi32!REFTRACK_WrapObject+0x000009d3
0x67421ed2: olmapi32!HrAsyncWrapObject+0x0000005a
Here is memory diff information
ntdll!EtwSetMark+23ED
ntdll!RtlInitializeCriticalSectionEx+12B
ntdll!RtlInitializeCriticalSection+12
olmapi32!MSProviderInit+D9
olmapi32!MSProviderInit+1D
olmapi32!REFTRACK_AddRefEx+113
olmapi32!REFTRACK_WrapObject+CDE
olmapi32!REFTRACK_WrapObject+BF1
olmapi32!REFTRACK_WrapObject+AC9
olmapi32!REFTRACK_WrapObject+9D3
olmapi32!HrAsyncWrapObject+5A
olmapi32!FBadEntryList+BF
OUTLOOK!FOutlookIsDeepSyncing+D045
OUTLOOK!FOutlookIsDeepSyncing+CD1D
OUTLOOK!FOutlookIsDeepSyncing+CA93
OUTLOOK!FAllowStoreToSend+1A543
OUTLOOK!GetCurrentDate+9733B
OUTLOOK!HrEnsureIMManager+49BC
OUTLOOK!HrEnsureIMManager+3C75
OUTLOOK!GetMsoInst+2E76
OUTLOOK!GetMsoInst+5BCB
OUTLOOK!GetMsoInst+5C7A
OUTLOOK!HrFindAContact+1893F
DCO!OOM::Items::add+102 (C:\XXX\item.cpp, 67)
....
Finally, in item.cpp line 67, I find
Item Items::add( const std::wstring& type ) const
{
IDispatchPtr pIItem = NULL;
HRESULT hr = getImpl()->Add( CComVariant(type.c_str()), &pIItem ); <<< Line 67
if ( FAILED(hr) )
throw Exception( hr, this, L"_Items::Add" );
return Item( pIItem );
}
I googled some more and have known that getImpl() is something with SmartPointer. And CComVariant is something that used to wrap object. I searched some memory leak sample on CComVariant but this seems not the same case.
Is there any idea that this code will cause handle/memory leak? Or any suggestion how I can do more research?
Thanks in advance.
After 2 weeks investigation, I think I have found the root cause, just as WhozCraig suspected, the root cause is unmatched AddRef() and Release().
The error code is very simple:
_variant_t vtUnk = dispatch_adapter::get(getImpl(), L"MAPIOBJECT");
CComPtr<IUnknown> pIUnk((IUnknown*)vtUnk);
To investigate this problem, I looked into some source code, the first is _variant_t
// Extracts a VT_UNKNOWN into an IUnknown*
//
inline _variant_t::operator IUnknown*() const
{
if (V_VT(this) == VT_UNKNOWN) {
if (V_UNKNOWN(this) != NULL) {
V_UNKNOWN(this)->AddRef(); // Here Added Ref
}
return V_UNKNOWN(this);
}
_variant_t varDest;
varDest.ChangeType(VT_UNKNOWN, this);
if (V_UNKNOWN(&varDest) != NULL) {
V_UNKNOWN(&varDest)->AddRef(); // Here Added Ref
}
return V_UNKNOWN(&varDest);
}
Then, if we look into CComPtr
's constructor, we find:
CComPtr( T* lp) {if((p=lp)!=NULL) p->AddRef();}; // Here Add Ref Again.
Twice AddRef() and only once Release(), that is why a handle/memory leak happen.
To fix this, we can use CComPtr.Attach()
instead of CComPtr
's constructor.
User contributions licensed under CC BY-SA 3.0