Valgrind reports memory leak when assigning a value to a string
Solution 1
Because you call exit(0)
, so the string destructor is never invoked. Just use return 0
.
To elaborate, the constructor of std::string
allocates heap memory to store the string, relying on the destructor to deallocate that memory. If you declare a string object on the stack, the destructor will automatically be invoked when the string object goes out of scope, thus freeing the memory. But exit
is really a C mechanism; it immediately exits the program without performing stack-unwinding meaning that C++ destructors for local stack objects will not be called.
Solution 2
If you allocate five strings, do you get five times the memory leak, or is it still the same amount? If it's the same amount, then you probably don't have a leak at all. Some libraries allocate memory for internal bookkeeping/efficiency/et cetera that doesn't get released until after valgrind stops looking. These get picked up as memory leaks because your program caused the allocation but never caused a deallocation. If it's five times the amount, then your implementation of string may be at fault. I agree with Charles Salvia though... try again with return 0;
instead of exit(0);
and see if that changes anything.
Solution 3
In one of my computer science classes we were told that Valgrind outputs information about strings that we shouldn't worry about. Here's the suppression file that they gave us for strings: https://sites.google.com/site/complingfiles/files/string.supp
Solution 4
Despite having no exit(0)
at the end of program I had similar problem with false positives with std::string
. I was statically linking with libstdc++
. Switching linking option to shared and compiling with GLIBCXX_FORCE_NEW
suppressed the warnings.
enzo1959
Updated on June 06, 2022Comments
-
enzo1959 almost 2 years
Valgrind reports a memory leak when assigning a value to a string.
I used the following simple code to test an memory leak reported by Valgrind.
/****************************************** * FILE: t3.c * Compiled using : g++ -g t3.c -o t3 * * $ g++ -v * Reading specs from /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/specs * Configured with: ./configure --prefix=/usr --infodir=/share/info --mandir=/share/man * --enable-languages=c,c++ --with-system-zlib --program-suffix=-3.4 --enable-threads=posix * Thread model: posix * gcc version 3.4.6 ******************************************/ #include <iostream> #include <string> using namespace std; /************************************************************** **************************************************************/ int main(int argc, char *argv[]) { string test = "XXXXXXXXX"; cout << "this is a test " << test << endl; exit(0); }
I compile using this command:
$ g++ -g t3.c -o t3
And when I run Valgrind it reports a memory leak when I try to assign a value to a string. I'm using this simple test to investigate some memory leak in the real program, and it seems that using string can cause some sort of problem.
By 0x8048A6F: main (t3.c:23) is the line : string test = "XXXXXXXXX"; Can someone give some hint on such strange behaviour?
[enzo@P0101222 C]$ valgrind --leak-check=full ./t3 ==3910== Memcheck, a memory error detector. ==3910== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al. ==3910== Using LibVEX rev 1732, a library for dynamic binary translation. ==3910== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP. ==3910== Using valgrind-3.2.3, a dynamic binary instrumentation framework. ==3910== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al. ==3910== For more details, rerun with: -v ==3910== this is a test XXXXXXXXX ==3910== ==3910== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 25 from 1) ==3910== malloc/free: in use at exit: 102 bytes in 3 blocks. ==3910== malloc/free: 4 allocs, 1 frees, 126 bytes allocated. ==3910== For counts of detected errors, rerun with: -v ==3910== searching for pointers to 3 not-freed blocks. ==3910== checked 194,136 bytes. ==3910== ==3910== 16 bytes in 1 blocks are definitely lost in loss record 1 of 3 ==3910== at 0x4017846: malloc (m_replacemalloc/vg_replace_malloc.c:149) ==3910== by 0x4018E05: realloc (m_replacemalloc/vg_replace_malloc.c:306) ==3910== by 0x41B441A: argz_append (in /lib/libc-2.2.5.so) ==3910== by 0x41593B9: __newlocale (in /lib/libc-2.2.5.so) ==3910== by 0x40E010B: std::locale::facet::_S_create_c_locale(__locale_struct*&, char const*, __locale_struct*) (c++locale.cc:99) ==3910== by 0x407EF6F: std::locale::facet::_S_initialize_once() (../../.././libstdc++-v3/src/locale.cc:172) ==3910== by 0x407EFB4: std::locale::facet::_S_get_c_locale() (../../.././libstdc++-v3/src/locale.cc:185) ==3910== by 0x407A422: std::ctype<char>::ctype(unsigned short const*, bool, unsigned) (/usr3/BUILD/gcc/gcc-3.4.6/i686-pc-linux-gnu/libstdc++-v3/include/i686-pc-linux-gnu/bits/ctype_noninline.h:104) ==3910== by 0x40801D5: std::locale::_Impl::_Impl(unsigned) (/usr3/BUILD/gcc/gcc-3.4.6/libstdc++-v3/libsupc++/new:92) ==3910== by 0x4080EED: std::locale::_S_initialize_once() (/usr3/BUILD/gcc/gcc-3.4.6/libstdc++-v3/libsupc++/new:92) ==3910== by 0x4080F84: std::locale::_S_initialize() (../../.././libstdc++-v3/src/locale_init.cc:155) ==3910== by 0x4080FE7: std::locale::locale() (../../.././libstdc++-v3/src/locale_init.cc:102) ==3910== ==3910== ==3910== 22 bytes in 1 blocks are possibly lost in loss record 2 of 3 ==3910== at 0x4017C38: operator new(unsigned) (m_replacemalloc/vg_replace_malloc.c:163) ==3910== by 0x40BF2C4: std::string::_Rep::_S_create(unsigned, unsigned, std::allocator<char> const&) (/usr3/BUILD/gcc/gcc-3.4.6/i686-pc-linux-gnu/libstdc++-v3/include/ext/new_allocator.h:81) ==3910== by 0x40C1CE4: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (/usr3/BUILD/gcc/gcc-3.4.6/i686-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.tcc:150) ==3910== by 0x40C1E15: std::string::string(char const*, std::allocator<char> const&) (/usr3/BUILD/gcc/gcc-3.4.6/i686-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.h:1386) ==3910== **by 0x8048A6F: main (t3.c:23)** ==3910== ==3910== LEAK SUMMARY: ==3910== definitely lost: 16 bytes in 1 blocks. ==3910== **possibly lost: 22 bytes in 1 blocks.** ==3910== still reachable: 64 bytes in 1 blocks. ==3910== suppressed: 0 bytes in 0 blocks. ==3910== Reachable blocks (those to which a pointer was found) are not shown. ==3910== To see them, rerun with: --leak-check=full --show-reachable=yes [enzo@P0101222 C]$
-
Nate Glenn about 11 yearsYeah, the school switched that class to java. I'll see if I can dig it up anywhere.
-
Nate Glenn over 10 years@Riot: found the file and posted a new link.
-
BobTuckerman almost 8 yearsIt appears that compiling with the
GLIBCXX_FORCE_NEW
flag doesn't actually do anything. According to the libstdc++ docs for mt_allocator, it's an environment variable. " If the GLIBCXX_FORCE_NEW environment variable is set, it sets the bool _S_force_new to true and then returns.". So, simply do something likeexport GLIBCXX_FORCE_NEW=1;
and then run valgrind. This resolved a lot of issues I had with std::string giving false positives.