Память Xerces-C++

У меня возникли проблемы с пониманием управления памятью Xerces-C++.

Если у меня есть этот (пример) XML-файл "config.xml":

<?xml version="1.0" encoding="UTF-8"?>
<settings>
    <port>
        <reference>Ref1</reference>
        <label>1PPS A</label>
        <enabled>true</enabled>
    </port>
</settings>

и этот код:

#include <xercesc/dom/DOM.hpp>

XERCES_CPP_NAMESPACE_USE

DOMElement *nextChildElement(const DOMElement *parent)
{
    DOMNode *node = (DOMNode *)parent->getFirstChild();
    while (node)
    {
        if (node->getNodeType() == DOMNode::ELEMENT_NODE)
            return (DOMElement *)node;
        node = node->getNextSibling();
    }
    return nullptr;
}

int main(int argc, char **argv)
{
    XMLPlatformUtils::Initialize();

    XMLCh tempStr[100];
    XMLString::transcode("LS", tempStr, 99);
    DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
    DOMLSParser *parser = ((DOMImplementationLS*)impl)->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, 0);
    DOMDocument *doc = impl->createDocument(0, 0, 0);

    doc = parser->parseURI("config.xml");

    DOMElement *el = doc->getDocumentElement(); // <settings>
    el = nextChildElement(el);                  //   <port>
    el = nextChildElement(el);                  //     <reference>Ref1</reference>

    // Heap blows up here
    while (1) {
        char *cstr = XMLString::transcode(el->getTextContent());
        XMLString::release(&cstr); // cstr is "Ref1"
    }

    // and/or here
    while (1) {
        XMLCh *xstr = XMLString::replicate(el->getTextContent());
        char *cstr = XMLString::transcode(xstr); // cstr is "Ref1"
        XMLString::release(&cstr);
        XMLString::release(&xstr);
    }
}

Почему память программы (кучи) взрывается в while (1) циклах. Любой цикл приводит к одной и той же проблеме с памятью:

использует диагностику памяти

Примечание. Я использую Visual Studio 2017 и протестировал его в следующих конфигурациях (все с одинаковыми результатами):

  • xerces-c-3.2.1, статическая библиотека, x64
  • xerces-c-3.2.1, динамическая (dll), x64
  • xerces-c-3.1.2, статическая библиотека, x64

person Blair Fonville    schedule 05.04.2018    source источник


Ответы (1)


Проблема в том, что функция const XMLCh *getTextConent() выделяет память в куче Document (используя свой MemoryManager), и нет никаких условий, позволяющих вызывающей стороне освобождать память или помечать ее для повторного использования. Таким образом, как только возвращаемый указатель удаляется из стека вызывающего объекта, память по существу теряется до тех пор, пока весь документ не будет освобожден, и в это время MemoryManager удаляет все выделения кучи.

Решение состоит в том, чтобы не использовать getTextContent(), а вместо этого использовать getNodeValue(), который возвращает указатель на данные, а не перераспределяет их из внутренней кучи.

Согласно это (не)отчет об ошибке

Кроме того, getTextContent все равно не работает. Он глючит, так как все вылезает и фактически бесполезен. Вы не можете прочитать DOM таким образом, или вы получите неточные данные при различных обстоятельствах, если есть несмежные узлы Text (а если их нет, вам все равно не нужно их использовать, поскольку значение прямого узла будет всем, что вам нужно).

Итак, рабочая версия кода примера OP может выглядеть так:

#include <xercesc/dom/DOM.hpp>
#include <string>

XERCES_CPP_NAMESPACE_USE

DOMElement *nextChildElement(const DOMElement *parent)
{
    DOMNode *node = (DOMNode *)parent->getFirstChild();
    while (node)
    {
        if (node->getNodeType() == DOMNode::ELEMENT_NODE)
            return (DOMElement *)node;
        node = node->getNextSibling();
    }
    return nullptr;
}

std::string readTextNode(const DOMElement *el)
{
    std::string sstr;
    DOMNode *node = el->getFirstChild();
    if (node->getNodeType() == DOMNode::TEXT_NODE) {
        char *cstr = XMLString::transcode(node->getNodeValue());
        sstr = cstr;
        XMLString::release(&cstr);
    }
    return sstr;
}

int main(int argc, char **argv)
{
    XMLPlatformUtils::Initialize();

    XMLCh tempStr[100];
    XMLString::transcode("LS", tempStr, 99);
    DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
    DOMLSParser *parser = ((DOMImplementationLS*)impl)->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, 0);
    DOMDocument *doc = impl->createDocument(0, 0, 0);

    doc = parser->parseURI("config.xml");

    DOMElement *el = doc->getDocumentElement(); // <settings>
    el = nextChildElement(el);                  //   <port>
    el = nextChildElement(el);                  //     <reference>Ref1</reference>

    // No memory leak
    std::string nodestr;
    while (1) {
        nodestr = readTextNode(el); // nodestr is "Ref1"
    }
}
person Blair Fonville    schedule 06.04.2018