11 Stimmen

Valgrind meldet ein Speicherleck bei der Zuweisung eines Wertes zu einer Zeichenkette

Valgrind meldet ein Speicherleck bei der Zuweisung eines Wertes zu einer Zeichenkette.

Ich habe den folgenden einfachen Code verwendet, um ein von Valgrind gemeldetes Speicherleck zu testen.

/******************************************
* 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);
}

Ich kompiliere mit diesem Befehl:

$ g++ -g t3.c -o t3

Und wenn ich Valgrind ausführen meldet es ein Speicherleck, wenn ich versuche, einen Wert zu einer Zeichenfolge zuweisen. Ich benutze diesen einfachen Test, um ein Speicherleck im echten Programm zu untersuchen, und es scheint, dass die Verwendung von String eine Art von Problem verursachen kann.

Bei 0x8048A6F: main (t3.c:23) ist die Zeile: string test = "XXXXXXXXX"; Kann jemand einen Hinweis auf dieses seltsame Verhalten geben?

[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]$

46voto

Charles Salvia Punkte 50361

Weil Sie anrufen exit(0) , so dass der String-Destruktor nie aufgerufen wird. Verwenden Sie einfach return 0 .

Zur Erläuterung: Der Konstruktor von std::string weist Heap-Speicher zu, um die Zeichenfolge zu speichern, und verlässt sich darauf, dass der Destruktor diesen Speicher wieder freigibt. Wenn Sie ein String-Objekt auf dem Stack deklarieren, wird der Destruktor automatisch aufgerufen, wenn das String-Objekt den Gültigkeitsbereich verlässt, wodurch der Speicher freigegeben wird. Aber exit ist eigentlich ein C-Mechanismus; er beendet das Programm sofort, ohne Stack-Unwinding durchzuführen, was bedeutet, dass C++-Destruktoren für lokale Stack-Objekte nicht aufgerufen werden.

3voto

Bill Punkte 13799

Wenn Sie fünf Zeichenfolgen zuweisen, erhalten Sie dann das fünffache Speicherleck oder ist es immer noch die gleiche Menge? Wenn es die gleiche Menge ist, dann haben Sie wahrscheinlich gar kein Leck. Einige Bibliotheken weisen Speicher für interne Buchhaltung/Effizienz/et cetera zu, der nicht freigegeben wird, bis valgrind aufhört zu suchen. Diese werden als Speicherlecks erkannt, weil Ihr Programm die Zuweisung verursacht hat, aber nie eine Freigabe verursacht hat. Wenn es sich um die fünffache Menge handelt, kann Ihre Implementierung von string fehlerhaft sein. Ich stimme Charles Salvia jedoch zu... versuchen Sie es erneut mit return 0; anstelle von exit(0); und sehen Sie, ob sich dadurch etwas ändert.

3voto

stx Punkte 123

Obwohl sie keine exit(0) am Ende des Programms hatte ich ein ähnliches Problem mit falsch positiven Ergebnissen bei std::string . Ich habe statisch verlinkt mit libstdc++ . Umschalten der Linking-Option auf Shared und Kompilieren mit GLIBCXX_FORCE_NEW die Warnungen unterdrückt.

0 Stimmen

Es scheint, dass das Kompilieren mit dem GLIBCXX_FORCE_NEW Flagge tut eigentlich nichts. Laut der libstdc++-Dokumente für mt_allocator ist es eine Umgebungsvariable. "Wenn die Umgebungsvariable GLIBCXX_FORCE_NEW gesetzt ist, setzt es den bool _S_force_new auf true und kehrt dann zurück.". Also, machen Sie einfach etwas wie export GLIBCXX_FORCE_NEW=1; und führen Sie dann valgrind aus. Dies löste eine Menge Probleme, die ich mit std::string hatte, die falsch-positive Ergebnisse liefern.

2voto

Nate Glenn Punkte 6074

In einem meiner Informatikkurse wurde uns gesagt, dass Valgrind Informationen über Strings ausgibt, um die wir uns nicht kümmern sollten. Hier ist die Unterdrückungsdatei, die sie uns für Strings gegeben haben: https://sites.google.com/site/complingfiles/files/string.supp

0 Stimmen

Ja, die Schule hat die Klasse auf Java umgestellt. Ich werde sehen, ob ich es irgendwo ausgraben kann.

1 Stimmen

@Riot: Ich habe die Datei gefunden und einen neuen Link gepostet.

1 Stimmen

Der Link funktioniert nicht mehr, bitte posten Sie ihn auf github gist, wenn möglich.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X