2009-12-14 11 views
10

Valgrind signale une fuite de mémoire lors de l'affectation d'une valeur à une chaîne.Valgrind signale une fuite de mémoire lors de l'affectation d'une valeur à une chaîne

J'ai utilisé le code simple suivant pour tester une fuite de mémoire signalée par 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); 
} 

Je Compile en utilisant cette commande:

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

Et quand je lance Valgrind il signale une fuite de mémoire lorsque je tente d'attribuer une valeur à une chaîne. J'utilise ce test simple pour étudier une fuite de mémoire dans le vrai programme, et il semble que l'utilisation de la chaîne puisse causer un problème.

Par 0x8048A6F: principal (t3.c: 23) est la ligne: string test = "XXXXXXXXX"; Quelqu'un peut-il donner un indice sur un comportement aussi étrange?

[[email protected] 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 
[[email protected] C]$ 

Répondre

43

Parce que vous appelez exit(0), de sorte que la destructor chaîne ne soit jamais invoqué. Utilisez simplement return 0.

Pour élaborer, le constructeur de std::string alloue la mémoire heap pour stocker la chaîne, en s'appuyant sur le destructeur pour libérer cette mémoire. Si vous déclarez un objet chaîne sur la pile, le destructeur sera automatiquement appelé lorsque l'objet chaîne sortira de sa portée, libérant ainsi la mémoire. Mais exit est vraiment un mécanisme C; il quitte immédiatement le programme sans effectuer de déroulement de pile, ce qui signifie que les destructeurs C++ pour les objets de pile locaux ne seront pas appelés.

3

Si vous allouez cinq chaînes, obtenez-vous cinq fois la fuite de mémoire, ou est-ce toujours la même quantité? Si c'est la même quantité, alors vous n'avez probablement pas de fuite du tout. Certaines bibliothèques allouent de la mémoire pour la comptabilité interne/efficacité/et cetera qui ne sont pas libérées avant que valgrind arrête de chercher. Ceux-ci sont détectés comme des fuites de mémoire car votre programme a provoqué l'allocation mais n'a jamais causé de désallocation. Si c'est cinq fois le montant, votre implémentation de chaîne peut être en faute. Je suis d'accord avec Charles Salvia si ... essayez à nouveau avec return 0; au lieu de exit(0); et voir si cela change quelque chose.

3

Dans l'un de mes cours d'informatique, on nous a dit que Valgrind fournissait des informations sur les chaînes dont nous ne devrions pas nous inquiéter. Voici le fichier de suppression qu'ils nous ont donné des chaînes: https://sites.google.com/site/complingfiles/files/string.supp

+0

Le lien mentionné ici ne fonctionne malheureusement plus. – Riot

+0

Oui, l'école a changé cette classe en Java. Je vais voir si je peux le déterrer n'importe où. –

+1

@Riot: trouvé le fichier et posté un nouveau lien. –

2

Malgré l'absence exit(0) à la fin du programme, j'ai eu le même problème avec les faux positifs avec std::string. J'étais en liaison statique avec libstdc++. Le basculement de l'option de liaison vers partagée et la compilation avec GLIBCXX_FORCE_NEW ont supprimé les avertissements.

+0

Merci, merci, merci, merci! –

+0

Il semble que la compilation avec le drapeau 'GLIBCXX_FORCE_NEW' ne fasse rien. D'après le document [libstdC++ docs for mt_allocator] (https://gcc.gnu.org/onlinedocs/libstdc++/manual/mt_allocator_impl.html), il s'agit d'une variable d'environnement. "Si la variable d'environnement GLIBCXX_FORCE_NEW est définie, elle définit le booléen _S_force_new sur true, puis retourne.". Donc, faites simplement quelque chose comme 'export GLIBCXX_FORCE_NEW = 1;' et exécutez ensuite valgrind. Cela a résolu beaucoup de problèmes avec std :: string donnant des faux positifs. – BobTuckerman