2011-07-17 11 views
12

Mi programa entra en fallas de segmentación y no puedo encontrar la causa. La peor parte es que la función en cuestión no siempre conduce a segfault.Error de segmentación en malloc_consolidate (malloc.c) que valgrind no detecta

BGF confirma el error y produce este trazado inverso:

Program received signal SIGSEGV, Segmentation fault. 
0xb7da6d6e in malloc_consolidate (av=<value optimized out>) at malloc.c:5169 
5169 malloc.c: No such file or directory. 
    in malloc.c 
(gdb) bt 
#0 0xb7da6d6e in malloc_consolidate (av=<value optimized out>) at malloc.c:5169 
#1 0xb7da9035 in _int_malloc (av=<value optimized out>, bytes=<value optimized out>) at malloc.c:4373 
#2 0xb7dab4ac in __libc_malloc (bytes=525) at malloc.c:3660 
#3 0xb7f8dc15 in operator new(unsigned int)() from /usr/lib/i386-linux-gnu/libstdc++.so.6 
#4 0xb7f72db5 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep::_S_create(unsigned int, unsigned int, std::allocator<char> const&)() 
    from /usr/lib/i386-linux-gnu/libstdc++.so.6 
#5 0xb7f740bf in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep::_M_clone(std::allocator<char> const&, unsigned int)() 
    from /usr/lib/i386-linux-gnu/libstdc++.so.6 
#6 0xb7f741f1 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::reserve(unsigned int)() from /usr/lib/i386-linux-gnu/libstdc++.so.6 
#7 0xb7f6bfec in std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::overflow(int)() from /usr/lib/i386-linux-gnu/libstdc++.so.6 
#8 0xb7f70e1c in std::basic_streambuf<char, std::char_traits<char> >::xsputn(char const*, int)() from /usr/lib/i386-linux-gnu/libstdc++.so.6 
#9 0xb7f5b498 in std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<unsigned long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, unsigned long) const() from /usr/lib/i386-linux-gnu/libstdc++.so.6 
#10 0xb7f5b753 in std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, unsigned long) const() from /usr/lib/i386-linux-gnu/libstdc++.so.6 
#11 0xb7f676ac in std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<unsigned long>(unsigned long)() 
    from /usr/lib/i386-linux-gnu/libstdc++.so.6 
#12 0xb7f67833 in std::basic_ostream<char, std::char_traits<char> >::operator<<(unsigned int)() from /usr/lib/i386-linux-gnu/libstdc++.so.6 
#13 0x08049c42 in sim::Address::GetS (this=0xbfffec40) at address.cc:27 
#14 0x0806a499 in sim::UserGenerator::ProcessEvent (this=0x80a1af0, e=...) at user-generator.cc:59 
#15 0x0806694b in sim::Simulator::CommunicateEvent (this=0x809f970, e=...) at simulator.cc:144 
#16 0x0806685d in sim::Simulator::ProcessNextEvent (this=0x809f970) at simulator.cc:133 
#17 0x08065d76 in sim::Simulator::Run (seed=0) at simulator.cc:53 
#18 0x0807ce85 in main (argc=1, argv=0xbffff454) at main.cc:75 
(gdb) f 13 
#13 0x08049c42 in sim::Address::GetS (this=0xbfffec40) at address.cc:27 
27 oss << m_address; 
(gdb) p this->m_address 
$1 = 1 

Método de la clase GetS Dirección traduce un número (uint32_t m_address) en una cadena y lo devuelve. El código (muy simple) es la siguiente:

std::string 
Address::GetS() const 
{ 
    std::ostringstream oss; 
    oss << m_address; 
    return oss.str(); 
} 

Además, como se puede ver en la traza, m_address se define correctamente.

Ahora, he intentado ejecutar mi programa usando valgrind. El programa no falla, probablemente debido a que valgrind reemplaza malloc() entre otras funciones.

El resumen de errores no muestra ninguna fuga de memoria:

LEAK SUMMARY: 
    definitely lost: 0 bytes in 0 blocks 
    indirectly lost: 0 bytes in 0 blocks 
    possibly lost: 4,367 bytes in 196 blocks 
    still reachable: 9,160 bytes in 198 blocks 
     suppressed: 0 bytes in 0 blocks 

Todo possibly lost se refieren a trazas de esta manera:

80 bytes in 5 blocks are possibly lost in loss record 3 of 26 
    at 0x4024B64: operator new(unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
    by 0x40DBDB4: std::string::_Rep::_S_create(unsigned int, unsigned int, std::allocator<char> const&) (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16) 
    by 0x40DE077: 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.16) 
    by 0x40DE1E5: 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.16) 
    by 0x806AF62: sim::UserGenerator::CreateUser(unsigned int) (user-generator.cc:152) 

No creo que esto está relacionado con el error. Sin embargo, el código en cuestión se puede encontrar following this link.

Estoy pensando en un error en libstdc++. Sin embargo, ¿qué tan probable sería eso? También he actualizado dicha biblioteca. Aquí están las versiones actualmente instaladas en mi sistema.

$ dpkg -l | grep libstdc 
ii libstdc++5   1:3.3.6-23 The GNU Standard C++ Library v3 
ii libstdc++6   4.6.1-1  GNU Standard C++ Library v3 
ii libstdc++6-4.1-dev 4.1.2-27 The GNU Standard C++ Library v3 (development files) 
ii libstdc++6-4.3-dev 4.3.5-4  The GNU Standard C++ Library v3 (development files) 
ii libstdc++6-4.4-dev 4.4.6-6  GNU Standard C++ Library v3 (development files) 
ii libstdc++6-4.5-dev 4.5.3-3  The GNU Standard C++ Library v3 (development files) 
ii libstdc++6-4.6-dev 4.6.1-1  GNU Standard C++ Library v3 (development files) 

Ahora la cuestión es que no estoy seguro de qué versión g++ usos, y si hay algún medio para hacer cumplir el uso de una versión particular.

Lo que estoy reflexionando es modificar GetS. Pero este es el único método que conozco. ¿Sugiere alguna alternativa?

Finalmente, incluso estoy considerando reemplazar std::string con char* más simple. Tal vez un poco drástico, pero no lo dejaría de lado.

¿Alguna idea en cuanto al mérito?

Gracias a todos de antemano.

mejor, Jir

+4

Primero, sugiero que intente ejecutar con la variable de entorno 'MALLOC_CHECK_' establecida en 3, lo que puede hacer que' malloc' aborte antes si sobrepasa alguna parte de sus estructuras de administración, mientras que de algún modo hace que valgrind desconozca esto . También te sugiero que veas si tienes alguna opción de supresión de valgrind que pueda estar ocultando el problema. – Hasturkun

+2

Hice una revisión rápida de tu código: Las siguientes clases no obedecen a la 'Regla de los Tres': 'BaseStation',' MobileTerminal' , 'Network',' Simulator', 'UserGenerator' Esto puede ser la causa de la eliminación de memoria debido a una eliminación doble. –

+0

@Hasturkun: intentaremos verificarlo. Consejo útil! @Martin: gracias por el comentario! Revisaré esas partes. – Jir

Respuesta

24

Ok. Esta es NO el problema:

Me refiero a un error en libstdC++

El problema es que ha sobrescrito algunos búfer de memoria y corrompido una de las estructuras utilizadas por el administrador de memoria. La parte difícil va a ser encontrarlo. No valgrind le dará información sobre la escritura más allá del final de una pieza de memoria asignada.

No haga esto:

Con el tiempo, incluso estoy pensando en reemplazar std :: string con carbón más simple *. Tal vez un poco drástico, pero no lo dejaría de lado.

Ya tiene suficientes problemas con la gestión de la memoria. Esto solo agregará más problemas. Hay absolutamente NADA mal con std :: cadena o las rutinas de gestión de memoria. Son fuertemente probados y usados. Si hubiera algo mal, la gente de todo el mundo comenzaría a gritar (sería una gran noticia).

Al leer su código en http://mercurial.intuxication.org/hg/lte_sim/file/c2ef6e0b6d41/src/ parece que todavía está atascado en un estilo C de código de escritura (C with Classes). Así que tiene el poder de C++ para automatizar (la voladura de su código) pero aún tiene todos los problemas asociados con C.

Debe revisar su código en términos de propiedad. Usted pasa cosas por puntero demasiado. Como resultado, es difícil seguir la propiedad del puntero (y, por lo tanto, quién es el responsable de eliminarlo).

Creo que la mejor apuesta para encontrar el error es escribir pruebas unitarias para cada clase. Luego ejecute las pruebas unitarias a través de val-grind. Sé que es un dolor (pero deberías haberlo hecho para empezar, ahora tienes el dolor, todo de una vez).

+0

¿Cómo puedo saber lo que no sé si no sé si existe? :) Bromas aparte, gracias por los consejos. Es gracias a comentarios como este que puedo aprender algo más. Lo miraré. ¡Gracias! – Jir

Cuestiones relacionadas