How do I solve memory leaks that are reported to reside in STL string?
Asked Answered
P

1

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 >
Paralysis answered 10/7, 2011 at 21:17 Comment(9)
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.Hali
Do you do any dynamic memory allocation yourself?Glycerol
What compiler is used (and its version)? What standard library implementation is used?Penrose
@MartinhoFernandes: Are you 100% that it's not in Poco? I've added more information.Paralysis
@Marlon: Yes, except for the AutoPtr in deserialize I do; I've added more information.Paralysis
@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.Paralysis
Removed any namespace stuff, OurExecutable renamed to Node for clarification.Paralysis
@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.Dimercaprol
@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.Paralysis
D
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.

Delegate answered 11/7, 2011 at 2:32 Comment(2)
Glad you didn't made this a comment. Apparently the actual problem seemed to be far away from the source... :/Paralysis
Lesson learned: Don't necessarily look at the source, also see where it gets stored and what happens with it.Paralysis

© 2022 - 2024 — McMap. All rights reserved.