Bug in _com_ptr_t::QueryStdInterfaces

Just thought I’d bring people’s attention to a bug in the COM support classes that ship with Visual Studio 2005/VC8.

It’s a fairly unusual edge case (at least, if you’re not being passed VARIANTs from a script language), where the _variant_t helper class attempts to extract a standard COM interface (IUnknown or IDispatch) from a VARIANT that’s being passed “byref”, e.g. has a type or’ed with VT_BYREF.

In this case the code in comip.h uses VariantCopy to “derefence” the pointer – convert it from, say, VT_DISPATCH|VT_BYREF to VT_DISPATCH – but if this succeeds, it then proceeds to use the wrong local variable, varSrc, rather than varDest that it’s just converted. The effect is that it causes an access violation.

Here’s the code snippet in question:

// Try to extract either IDispatch* or an IUnknown* from

// the VARIANT

//

HRESULT QueryStdInterfaces(const _variant_t& varSrc) throw()

{

if (V_VT(&varSrc) == VT_DISPATCH) {

return _QueryInterface(V_DISPATCH(&varSrc));

}

 

if (V_VT(&varSrc) == VT_UNKNOWN) {

return _QueryInterface(V_UNKNOWN(&varSrc));

}

 

// We have something other than an IUnknown or an IDispatch.

// Can we convert it to either one of these?

// Try IDispatch first

//

VARIANT varDest;

VariantInit(&varDest);

 

HRESULT hr = VariantChangeType(&varDest, const_cast(static_cast<const VARIANT*>(&varSrc)), 0, VT_DISPATCH);

if (SUCCEEDED(hr)) {

hr = _QueryInterface(V_DISPATCH(&varSrc)); // Should be &varDest

}

 

if (hr == E_NOINTERFACE) {

// That failed … so try IUnknown

//

VariantInit(&varDest);

hr = VariantChangeType(&varDest, const_cast(static_cast<const VARIANT*>(&varSrc)), 0, VT_UNKNOWN);

if (SUCCEEDED(hr)) {

hr = _QueryInterface(V_UNKNOWN(&varSrc)); // Should be &varDest

}

}

 

VariantClear(&varDest);

return hr;

}

Looks like it’s the same in Visual Studio 2005 SP1, but Microsoft are aware of the problem, and hopefully there’ll be a patch soon.

Hope this saves you some time!