Question

I am getting a memory leak with getline, and I am not sure why or how to stop it.

Here is the report from valgrind:

==26681==
==26681== HEAP SUMMARY:
==26681==     in use at exit: 1,756 bytes in 73 blocks
==26681==   total heap usage: 223 allocs, 150 frees, 15,523 bytes allocated
==26681==
==26681== 28 bytes in 1 blocks are possibly lost in loss record 1 of 4
==26681==    at 0x4A075BC: operator new(unsigned long) (vg_replace_malloc.c:298)
==26681==    by 0x4CCC4B8: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (new_allocator.h:94)
==26681==    by 0x4CCD227: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned long) (basic_string.tcc:631)
==26681==    by 0x4CCD30F: std::string::reserve(unsigned long) (basic_string.tcc:512)
==26681==    by 0x4CCD5D4: std::string::append(char const*, unsigned long) (basic_string.tcc:310)
==26681==    by 0x4C86384: std::basic_istream<char, std::char_traits<char> >& std::getline<char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char) (istream.cc:397)
==26681==    by 0x4026ED: main (test.cpp:210)
==26681==
==26681== LEAK SUMMARY:
==26681==    definitely lost: 0 bytes in 0 blocks
==26681==    indirectly lost: 0 bytes in 0 blocks
==26681==      possibly lost: 28 bytes in 1 blocks
==26681==    still reachable: 1,728 bytes in 72 blocks
==26681==         suppressed: 0 bytes in 0 blocks
==26681== Reachable blocks (those to which a pointer was found) are not shown.
==26681== To see them, rerun with: --leak-check=full --show-reachable=yes
==26681==
==26681== For counts of detected and suppressed errors, rerun with: -v
==26681== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)

Here is line 210 of test.cpp

bool pending = getline(inputfile, line);

Some more lines:

string line;

bool pending = getline(inputfile, line);
int round = readOption(inputfile);
int num  = readOption(inputfile);

I think it has something to do with when getline fails, and because line is a string it somehow never deallocates that memory. How do I prevent this?

readOption also uses getline but I think it has no memory leaks because string line is defined locally and then goes out of scope, effectively cleaning the memory?

Edit 1:

I have "solved" the issue by making a dummy function :

bool getnewline(ifstream &inputfile) {
    string line;
    return getline(inputfile, line);
}

However it seems stupid to do this, I am not sure why valgrind is complaining if there is no leak. I am still after a better/clean solution to this issue.

Was it helpful?

Solution

When you exit a C++ program by calling the exit() function, the object destructors are not run. This can result in Valgrind reporting memory leaks.

OTHER TIPS

I know this is almost a year old but I came upon this answer looking specifically for a getline() memory leak issue and want to give minimum instructions on how I was able to reproduce this specific issue, as I think it just comes from defining a std::string variable and not exiting cleanly from the program.

Given the following:

leaky.cpp:

#include <iostream>
int main(int argc, char ** argv) {
    std::string x = "x";
    exit(1);
    return 0;
}

Compile string:

g++ -g -Wall -Wpedantic --std=gnu++11 leaky.cpp -o leaky

Valgrind invocation:

valgrind --tool=memcheck --leak-check=full ./leaky

Doing this will reveal that there is indeed a leak:

==4434== Memcheck, a memory error detector
==4434== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4434== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==4434== Command: ./leaky
==4434== 
==4434== 
==4434== HEAP SUMMARY:
==4434==     in use at exit: 16 bytes in 1 blocks
==4434==   total heap usage: 1 allocs, 0 frees, 16 bytes allocated
==4434== 
==4434== 16 bytes in 1 blocks are possibly lost in loss record 1 of 1
==4434==    at 0x402A6DC: operator new(unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4434==    by 0x40F8213: std::string::_Rep::_S_create(unsigned int, unsigned int, std::allocator<char> const&) (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.19)
==4434==    by 0x40FA125: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.19)
==4434==    by 0x40FA7AF: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.19)
==4434==    by 0x804875E: main (leaky.cpp:3)
==4434== 
==4434== LEAK SUMMARY:
==4434==    definitely lost: 0 bytes in 0 blocks
==4434==    indirectly lost: 0 bytes in 0 blocks
==4434==      possibly lost: 16 bytes in 1 blocks
==4434==    still reachable: 0 bytes in 0 blocks
==4434==         suppressed: 0 bytes in 0 blocks
==4434== 
==4434== For counts of detected and suppressed errors, rerun with: -v
==4434== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

And of course to try to include an answer to the question, exit(1) forces the program to quit without invoking any destructors, as far as I know--I've only been using C++ for a month and a half, so I'm not really an expert.

Perhaps the C++ class in question is doing something with pointers that suggests possibly leaky behavior to Valgrind.

I get diagnostics about this in a project in which I allocate some arrays, but then I adjust the pointer to the third element so that indices [-2] and [-1] are used to store some meta-information. There is no leak because I restore the pointer and free the arrays correctly.

Valgrind sees that the objects are referenced, however, that they are not referenced "nicely" via pointers to their base address, but only via interior pointers. It looks like a possible leak since no pointer exists for freeing the object.

A situation like this could happen in leaky programs: programs that, say, allocate a big object, give pieces of it (via pointers) to other modules, and then leak the big object. Interior pointers do suggest a leak.

It could be that getline is chummy with the representation of basic::string<> and does something of that sort. When you copy the object, the new object doesn't do anything funny: it just references the string data by its base address. The old object is gone, and it freed the data.

Just a hypothesis.

By the way, in that aforementioned program, I fixed things for Valgrind by retaining an extra pointer to the base address in the vector objects managing those arrays. This extra pointer is only present when the software is built for Valgrind debugging (along with other features, like use of the Valgrind client request API).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top