7

For a school project, we have to send big files across the network., we must use Poco::XML for our data.

After our files are send over the network, it appears that the memory does not free.

Here is an example for a file of ~9 Mb on the receiving part:

valgrind --leak-check=full --show-reachable=yes -v ourExecutable parms returns:

 12,880,736 bytes in 37 blocks are definitely lost in loss record 101 of 101
    at 0x4C2747E: operator new(unsigned long) (vg_replace_malloc.c:261)
    by 0x5A3AC88: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/gcc/x86_64-pc-linux-gnu/4.4.4/libstdc++.so.6.0.13)
    by 0x5A3BC4A: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned long) (in /usr/lib64/gcc/x86_64-pc-linux-gnu/4.4.4/libstdc++.so.6.0.13)
    by 0x5A3C1BB: std::string::reserve(unsigned long) (in /usr/lib64/gcc/x86_64-pc-linux-gnu/4.4.4/libstdc++.so.6.0.13)
    by 0x5A3C68E: std::string::append(std::string const&) (in /usr/lib64/gcc/x86_64-pc-linux-gnu/4.4.4/libstdc++.so.6.0.13)
    by 0x5202359: Poco::XML::Element::innerText() const (in /home/tomwij/IGS/trunk/Project/external/lib/libPocoXML.so.8)
    by 0x4145BF: NodeProtocol::getChildNodeStrValue(Poco::XML::Element*, std::string) (NodeProtocol.cpp:82)
    by 0x41544F: NodeProtocol::deserialize(std::string const&) (NodeProtocol.cpp:200)
    by 0x40B088: Node::handleClientPacket(PriorityElement*) (Node.cpp:760)
    by 0x40A04C: Node::handlePackets() (Node.cpp:574)
    by 0x4078EA: Node::run() (Node.cpp:162)
    by 0x40772D: Node::activate() (Node.cpp:138)

 LEAK SUMMARY:
    definitely lost: 12,888,036 bytes in 190 blocks
    indirectly lost: 644,979 bytes in 1,355 blocks
      possibly lost: 10,089 bytes in 27 blocks
    still reachable: 306,020 bytes in 43 blocks
         suppressed: 0 bytes in 0 blocks

The function which is right before Poco is

const string NodeProtocol::getChildNodeStrValue(Element * elem, string child)
{
    Element*  tempNode = elem->getChildElement(child);
    XMLString result(tempNode->innerText());
    string ret = string(fromXMLString(result));
    result.clear();
    return ret;
}

which calls

XMLString Element::innerText() const
{
    XMLString result;
    Node* pChild = firstChild();
    while (pChild)
    {
        result.append(pChild->innerText());
        pChild = pChild->nextSibling();
    }
    return result;
}

(Note that XMLString is std::string)

Why is the append of STL string leaking memory?

If I just assign instead of using the copy constructors it gives the same problem.


EDIT:

I'm using the latest stable GNU GCC 4.4.4 on Gentoo x64 (linux-2.6.34-gentoo-r12).

More functions from the call stack (stripped irrelevant big chunks of code / if structures):

Command * NodeProtocol::deserialize(const string & msg)
{
    DOMParser xmlParser;

    // Get the root node.
    AutoPtr<Document> doc = xmlParser.parseString(msg);
    AutoPtr<Element> rootElement = doc->documentElement();

    string root = fromXMLString(rootElement->nodeName());
    string name = getChildNodeStrValue(rootElement, "name");
    string data = getChildNodeStrValue(rootElement, "data");
    return new PutCommand(name, data);
}

and

void Node::handleClientPacket(PriorityElement * prio)
{
        Command * command = NodeProtocol::deserialize(prio->fPacket);

        // CUT: Access some properties of command, let the command execute.

        delete command;
}

and

void Node::handlePackets()
{
    PriorityElement * prio = fQueue->top();
    fQueue->pop();

    if (prio->fSource == kCLIENT)
        handleClientPacket(prio);
    else if (prio->fSource == kNODE)
        handleNodePacket(prio);

    delete prio;
}

where fQueue is:

priority_queue< PriorityElement*,  vector<PriorityElement*>, ComparisonFunction >
Tamara Wijsman
  • 12,198
  • 8
  • 53
  • 82
  • 2
    You didn't show the code of the `OurExecutable::handleClientPacket` function, or any above it in the call stack. None of the functions whose code you posted show any dynamic allocation. So the leak can't be there. – R. Martinho Fernandes Jul 10 '11 at 21:31
  • Do you do any dynamic memory allocation yourself? – Marlon Jul 10 '11 at 21:31
  • What compiler is used (and its version)? What standard library implementation is used? – Serge Dundich Jul 10 '11 at 21:41
  • @MartinhoFernandes: Are you 100% that it's not in Poco? I've added more information. – Tamara Wijsman Jul 10 '11 at 22:25
  • @Marlon: Yes, except for the AutoPtr in `deserialize` I do; I've added more information. – Tamara Wijsman Jul 10 '11 at 22:25
  • @SergeDundick: Added that information in the question right after `EDIT:`, how do I see the STL version? This also happens on `gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)`, my co-developer's PC. – Tamara Wijsman Jul 10 '11 at 22:27
  • Removed any namespace stuff, `OurExecutable` renamed to `Node` for clarification. – Tamara Wijsman Jul 10 '11 at 22:45
  • @TomWij: one piece of advice --> try to use smart pointers (`boost::scoped_ptr` would do nicely here, if you don't want boost, just grab the file or recreate it). If there is any exception in your code, it'll leak too. – Matthieu M. Jul 11 '11 at 06:14
  • @Matthieu: Yeah, on the chat we talked about preferring `value > reference > pointer` and using `shared_ptr` or `unique_ptr` when necessary. Unless the library wants you to use something different. – Tamara Wijsman Jul 11 '11 at 11:25

1 Answers1

9

I would make this a comment, but apparently I don't have the rep. Have you remembered to make the destructor for Command virtual? If name or data are fields of PutCommand rather than Command and the Command destructor is not virtual, they may not be freed properly when you delete command in handleClientPacket.

Hugh
  • 8,872
  • 2
  • 37
  • 42