2009-12-14 20 views
10

Valgrind informa una pérdida de memoria al asignar un valor a una cadena.Valgrind informa pérdida de memoria al asignar un valor a una cadena

Utilicé el siguiente código simple para probar una fuga de memoria informada por 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); 
} 

puedo compilar usando este comando:

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

Y cuando corro Valgrind se reporta una pérdida de memoria cuando trato de asignar un valor a una cadena. Estoy usando esta prueba simple para investigar alguna fuga de memoria en el programa real, y parece que usar una cadena puede causar algún tipo de problema.

Por 0x8048A6F: main (t3.c: 23) es la línea: string test = "XXXXXXXXX"; ¿Puede alguien dar alguna pista sobre un comportamiento tan extraño?

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

Respuesta

43

Debido a que llaman exit(0), por lo que el destructor cadena no se invoca. Simplemente use return 0.

Para elaborar, el constructor de std::string asigna memoria de montón para almacenar la cadena, confiando en el destructor para desasignar esa memoria. Si declara un objeto de cadena en la pila, el destructor se invocará automáticamente cuando el objeto de cadena quede fuera del alcance, liberando así la memoria. Pero exit es realmente un mecanismo C; inmediatamente sale del programa sin realizar el desenrollado de la pila, lo que significa que no se invocarán los destructores de C++ para los objetos de la pila local.

3

Si asigna cinco cadenas, ¿obtiene cinco veces la pérdida de memoria, o sigue siendo la misma cantidad? Si es la misma cantidad, entonces probablemente no tenga una fuga en absoluto. Algunas bibliotecas asignan memoria para contabilidad interna/eficiencia/etcétera que no se libera hasta que valgrind deja de buscar. Estos se recogen como pérdidas de memoria porque su programa causó la asignación pero nunca causó una desasignación. Si es cinco veces la cantidad, entonces la implementación de la cadena puede ser la culpa. Estoy de acuerdo con Charles Salvia ... inténtalo de nuevo con return 0; en lugar de exit(0); y mira si eso cambia algo.

3

En una de mis clases de informática me dijeron que Valgrind genera información sobre cadenas de las que no deberíamos preocuparnos. Aquí está el archivo de supresión que nos dieron para cuerdas: https://sites.google.com/site/complingfiles/files/string.supp

+0

Desafortunadamente, el enlace mencionado aquí ya no funciona. – Riot

+0

Sí, la escuela cambió esa clase a Java. Veré si puedo desenterrarlo en cualquier lugar. –

+1

@Riot: encontró el archivo y publicó un nuevo enlace. –

2

pesar de no tener exit(0) al final del programa que tenía un problema similar con los falsos positivos con std::string. Estaba vinculando estáticamente con libstdc++. Cambiar la opción de vinculación a compartida y compilar con GLIBCXX_FORCE_NEW suprimió las advertencias.

+0

Gracias, gracias, gracias, gracias! –

+0

Parece que compilar con el indicador 'GLIBCXX_FORCE_NEW' en realidad no hace nada. De acuerdo con los [documentos de libstdC++ para mt_allocator] (https://gcc.gnu.org/onlinedocs/libstdc++/manual/mt_allocator_impl.html), se trata de una variable de entorno. "Si se establece la variable de entorno GLIBCXX_FORCE_NEW, establece el bool _S_force_new en true y luego regresa". Por lo tanto, simplemente haga algo como 'export GLIBCXX_FORCE_NEW = 1;' y luego ejecute valgrind. Esto resolvió muchos problemas que tuve con std :: string dando falsos positivos. – BobTuckerman

Cuestiones relacionadas