为什么我在使用 CComSafeArray<BSTR> 时会泄漏内存?
Why do I leak memory when using CComSafeArray<BSTR>?
我有一个内存泄漏,我已将其缩小到以下代码。怎么回事?
CComSafeArray<BSTR> sa(5);
sa[0] = SysAllocString("constant");
CComSafeArray::~CComSafeArray
calls SafeArrayDestroy
(via CComSafeArray::Destroy()
, see below), which should then call SysFreeString
所有成员。因此,这里不应该有泄漏。怎么回事?
HRESULT Destroy()
{
HRESULT hRes = S_OK;
if (m_psa != NULL)
{
hRes = Unlock();
if (SUCCEEDED(hRes))
{
hRes = SafeArrayDestroy(m_psa);
if (SUCCEEDED(hRes))
m_psa = NULL;
}
}
return hRes;
}
简答:
不是在 CComSafeArray<BSTR>
、CComSafeArray<BSTR>::operator[]
和 CComSafeArray<BSTR>::GetAt(T)
return 中保存指针的副本,而是一个 CComBSTR
对象,它采用BSTR
。这导致 BSTR
泄漏。
长答案:
经过几个小时的无果而终,在尝试编译一个更简单的版本以试图缩小漏洞时出现编译错误,暴露了它:
CComSafeArray<BSTR> sa(5);
sa[0] = nullptr;
这不会编译,因为在幕后 CComSafeArray<BSTR>::operator[]
return 是一个 CComBSTR
对象,并且 nullptr
可以匹配 CComBSTR::operator=(LPCSTR)
和 CComBSTR::operator=(LPCOLESTR)
.砰,编译错误。
一旦我发现 CComBSTR
在幕后参与,它就明白了。 CComBSTR::operator=
takes a copy of the BSTR
instead of saving the pointer(我如何阅读代码,给定正常行为)或取得所有权,导致未释放的临时文件泄漏 BSTR
。
typename _ATL_AutomationType<T>::_typewrapper& GetAt(_In_ LONG lIndex) { ... }
...
// specialization for BSTR so GetT doesn't return &BSTR
template <>
struct _ATL_AutomationType<BSTR>
{
typedef CComBSTR _typewrapper ;
enum { type = VT_BSTR };
static void* GetT(_In_ const BSTR& t) throw()
{
return t;
}
};
我有一个内存泄漏,我已将其缩小到以下代码。怎么回事?
CComSafeArray<BSTR> sa(5);
sa[0] = SysAllocString("constant");
CComSafeArray::~CComSafeArray
calls SafeArrayDestroy
(via CComSafeArray::Destroy()
, see below), which should then call SysFreeString
所有成员。因此,这里不应该有泄漏。怎么回事?
HRESULT Destroy()
{
HRESULT hRes = S_OK;
if (m_psa != NULL)
{
hRes = Unlock();
if (SUCCEEDED(hRes))
{
hRes = SafeArrayDestroy(m_psa);
if (SUCCEEDED(hRes))
m_psa = NULL;
}
}
return hRes;
}
简答:
不是在 CComSafeArray<BSTR>
、CComSafeArray<BSTR>::operator[]
和 CComSafeArray<BSTR>::GetAt(T)
return 中保存指针的副本,而是一个 CComBSTR
对象,它采用BSTR
。这导致 BSTR
泄漏。
长答案:
经过几个小时的无果而终,在尝试编译一个更简单的版本以试图缩小漏洞时出现编译错误,暴露了它:
CComSafeArray<BSTR> sa(5);
sa[0] = nullptr;
这不会编译,因为在幕后 CComSafeArray<BSTR>::operator[]
return 是一个 CComBSTR
对象,并且 nullptr
可以匹配 CComBSTR::operator=(LPCSTR)
和 CComBSTR::operator=(LPCOLESTR)
.砰,编译错误。
一旦我发现 CComBSTR
在幕后参与,它就明白了。 CComBSTR::operator=
takes a copy of the BSTR
instead of saving the pointer(我如何阅读代码,给定正常行为)或取得所有权,导致未释放的临时文件泄漏 BSTR
。
typename _ATL_AutomationType<T>::_typewrapper& GetAt(_In_ LONG lIndex) { ... }
...
// specialization for BSTR so GetT doesn't return &BSTR
template <>
struct _ATL_AutomationType<BSTR>
{
typedef CComBSTR _typewrapper ;
enum { type = VT_BSTR };
static void* GetT(_In_ const BSTR& t) throw()
{
return t;
}
};