使用cComvariant时,Outlook插件内存泄漏
An Outlook plugin memory leak when using CComVariant
我正在分析Outlook插件中的手柄泄漏和内存泄漏。
我在这里放置了分析步骤,因为我几乎没有任何C 知识(上次使用C 是7年前)。
从Google搜索后,我使用WindBG的!htrace -diff命令查找句柄泄漏。另外,我使用UMDH获得了内存差异。
通过比较两个结果,我发现有许多相同的调用堆栈似乎两者兼而有之:
这里是hander diff信息:
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
这是内存差异信息
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:XXXitem.cpp, 67)
....
最后,在item.cpp行67中,我找到
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 );
}
我更多地搜索了一些,并且知道getimpl()是SmartPointer。ccomvariant是用来包装对象的东西。我在ccomvariant上搜索了一些内存泄漏样本,但这似乎不是同一情况。
是否有任何想法此代码会导致句柄/内存泄漏?或任何建议我如何进行更多研究?
预先感谢。
经过2周的调查,我认为我已经找到了根本原因,就像怀疑Whozcraig一样,根本原因是无与伦比的addRef()和Release()。
错误代码非常简单:
_variant_t vtUnk = dispatch_adapter::get(getImpl(), L"MAPIOBJECT");
CComPtr<IUnknown> pIUnk((IUnknown*)vtUnk);
要调查这个问题,我研究了一些源代码,第一个是_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);
}
然后,如果我们查看CComPtr
的构造函数,我们会发现:
CComPtr( T* lp) {if((p=lp)!=NULL) p->AddRef();}; // Here Add Ref Again.
两次addRef(),仅一次repares(),这就是为什么句柄/内存泄漏发生的原因。
要解决此问题,我们可以使用CComPtr.Attach()
而不是CComPtr
的构造函数。
相关文章:
- 从C++本机插件更新Vector3数组
- 将字符串存储在c++中的稳定内存中
- 使用CMake创建QML插件
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- Win32编译器选项和内存分配
- 当vector是tje全局变量时,c++中vector的内存管理
- 带内存和隔离功能的SQLite
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 迭代时从向量和内存中删除对象
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 为什么示例代码访问IUnknown中已删除的内存
- 如何在C++类内存结构中创建"spacer"?
- 从构造函数抛出异常时如何克服内存泄漏
- 一个 Excel XLL 插件可以有多少内存?
- 使用cComvariant时,Outlook插件内存泄漏
- 如何检查火息插件中的内存泄漏
- 跟踪插件中的内存泄漏,使用_crtBreakAlloc, _CRTDBG_MAP_ALLOC
- 内存管理与c++插件插入到C软件