Search code examples
c++memory-leaksmsxmlmsxml6msxml4

MSXML Memory Leak


I have to deal with a legacy application that uses MSXML to write measurement data to a simple XML file. Basicly, this is what's happening:

MSXML2::IXMLDOMDocument2Ptr pXmlDocument;
HRESULT comResult = CXMLUtil::createXMLDocument(pXmlDocument);
// ... check HRESULT ...
MSXML2::IXMLDOMNodePtr pXmlMainNode = pXmlDocument.GetInterfacePtr();
MSXML2::IXMLDOMNodePtr pXmlSubNode = CXMLUtil::AppendNewElement(pXmlDocument, pXmlMainNode, RootTag, "");
// ... create further nodes ...
MSXML2::IXMLDOMNodePtr pXmlTmpNode = CXMLUtil::AppendNewElement(
pXmlDocument,
pXmlDataSetNode,
measDataTag,
measdata,
numberOfDataItems );
// ... append further items ...

After each item, pXmlTmpNode.Release() is called. At the end, all other nodes as well as pXmlDocument are Released.

createXMLDocument is defined as follows:

HRESULT CXMLUtil::createXMLDocument(MSXML2::IXMLDOMDocument2Ptr &pXmlDocument) {
    MSXML2::IXMLDOMDocument2 *xmlDocument = 0;
    HRESULT comError = CoCreateInstance(__uuidof(MSXML2::DOMDocument),NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&xmlDocument));
    if (comError) return comError;
    xmlDocument->put_async(VARIANT_FALSE);
    xmlDocument->put_validateOnParse(VARIANT_FALSE);
    xmlDocument->put_resolveExternals(VARIANT_FALSE);
    xmlDocument->put_preserveWhiteSpace(VARIANT_TRUE);
    MSXML2::IXMLDOMDocument2Ptr ptr(xmlDocument);
    pXmlDocument = ptr;
    return comError;
}

For appending new elements (i.e. unsiged char arrays), this function is applied:

MSXML2::IXMLDOMNodePtr CXMLUtil::AppendNewElement(MSXML2::IXMLDOMDocument2Ptr pXMLDom, MSXML2::IXMLDOMNodePtr pParent, CComBSTR strElementName, unsigned char* pData, long nData) {
    MSXML2::IXMLDOMNodePtr pData1 = pXMLDom->createElement(BSTR(strElementName));
    pData1->put_dataType(CComBSTR(_T("bin.base64")));
    SAFEARRAY* psa = SafeArrayCreateVector( VT_UI1, 0L, nData);
    psa->pvData = pData;
    VARIANT var;
    VariantInit(&var);
    var.parray = psa;
    var.vt = (VT_ARRAY | VT_UI1 );
    pData1->nodeTypedValue = var;
    pParent->appendChild(pData1);
    SafeArrayDestroy(psa);
    return pData1;
}

Regardless of wether #import <msxml4.dll> or #import <msxml6.dll> is used, there seems to be a leak of memory. Since measdata etc. can be huge, that's a pretty big problem. Is there something I can do to make the code work? Thanks, Matthew


Solution

  • MSXML2::IXMLDOMDocument2 *xmlDocument = 0;
    HRESULT comError = CoCreateInstance(__uuidof(MSXML2::DOMDocument),
        NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&xmlDocument));
    ...
    MSXML2::IXMLDOMDocument2Ptr ptr(xmlDocument);
    pXmlDocument = ptr;
    

    This code leaks xmlDocument. ptr(xmlDocument) does an extra AddRef, but there is no Release for xmlDocument going out of scope. You use smart ptrs everywhere, no reason not to use one here as well, maybe something like this:

    MSXML2::IXMLDOMDocument2Ptr xmlDocument;
    HRESULT comError = CoCreateInstance(__uuidof(MSXML2::DOMDocument),
        NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&xmlDocument));
    ...
    pXmlDocument = xmlDocument;