2011-07-17 12 views
12

Mój program przechodzi w błędy segmentacji i nie mogę znaleźć przyczyny. Najgorsze jest to, że dana funkcja nie zawsze prowadzi do uszkodzenia.Błąd segmentacji w malloc_consolidate (malloc.c), że valgrind nie wykrywa

GDB potwierdza błąd i daje ten ślad:

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 

Method GetS klasy Adres przekłada numer (uint32_t m_address) na ciąg znaków i zwraca go. Kod (bardzo prosty) jest następujący:

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

Poza tym, jak widać w backtrace, m_address jest poprawnie zdefiniowany.

Teraz próbowałem uruchomić mój program przy użyciu valgrind. Program nie ulega awarii, prawdopodobnie ze względu na fakt, że valgrind zastępuje między innymi funkcje malloc().

Podsumowanie błędu nie wykazuje wyciek pamięci:

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 

Wszystko possibly lost odnieść się do śladów czynności tak:

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) 

I nie sądzę, że to jest związane z błędem. Jednak dany kod można znaleźć following this link.

Mam na myśli błąd w libstdc++. Jaka byłaby jednak taka szansa? Zaktualizowałem również taką bibliotekę. Oto wersje aktualnie zainstalowane w moim systemie.

$ 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) 

Teraz chodzi o to, że nie jestem pewien, która wersja g++ używa i czy istnieje jakiś sposób, aby wymusić zastosowanie konkretnej wersji.

Zastanawiam się nad modyfikacją GetS. Ale to jedyna metoda, jaką znam. Czy sugerujesz jakąś alternatywę?

Ostatecznie, rozważam nawet zastąpienie std::string prostszym char*. Może trochę drastyczny, ale nie odłożyłbym go na bok.

Każda myśl w wartości?

Dziękuję wszystkim z góry.

Best, Jir

+4

Po pierwsze, proponuję, abyś spróbował uruchomić ze zmienną środowiskową 'MALLOC_CHECK_' ustawioną na 3, która może spowodować, że' malloc' przerwie pracę wcześniej, jeśli zdarzy ci się, że przekroczy część jego struktur zarządzania, jednocześnie czyniąc valgrind nieświadomym tego . Proponuję ci również zobaczyć, czy masz jakieś opcje supremacji valgrind, które mogą ukrywać problem. – Hasturkun

+2

Zrobiłem szybką recenzję twojego kodu: Poniższe klasy nie przestrzegają 'Rule of Three':' BaseStation', 'MobileTerminal' , 'Network',' Simulator', 'UserGenerator' Może to być przyczyną przycinania pamięci z powodu podwójnego usunięcia. –

+0

@Hasturkun: spróbuję to sprawdzić. Przydatna wskazówka! @Martin: dzięki za komentarz! Przejrzę te części. – Jir

Odpowiedz

24

Ok. To NIE problem:

Myślę błędu w libstdC++

Problem polega na tym, że nadpisałeś jakiś bufor pamięci i uszkodzony jeden z obiektów wykorzystywanych przez menedżera pamięci. Najtrudniej będzie go znaleźć. Valgrind nie podaje informacji o pisaniu po zakończeniu przydzielonej pamięci.

nie rób tego:

Ostatecznie jestem nawet biorąc pod uwagę, aby zastąpić std :: string z prostszej char *. Może trochę drastyczne, ale nie odłożyłbym tego na bok.

Masz już dość problemów z zarządzaniem pamięcią. To po prostu doda więcej problemów. Jest absolutnie niepoprawny kod std :: string lub procedury zarządzania pamięcią. Są intensywnie testowane i używane. Gdyby coś było nie tak, ludzie na całym świecie zaczęliby krzyczeć (to byłyby wielkie wieści).

Czytanie kodu w http://mercurial.intuxication.org/hg/lte_sim/file/c2ef6e0b6d41/src/ wydaje się, że nadal utknąłeś w stylu pisania kodu C (C with Classes). Więc masz moc C++ do zautomatyzowania (wysadzenie twojego kodu), ale nadal masz wszystkie problemy związane z C.

Musisz ponownie spojrzeć na swój kod pod względem własności. Mijamy rzeczy za dużo za pomocą wskaźnika. W rezultacie trudno jest śledzić własność wskaźnika (a więc kto jest odpowiedzialny za usunięcie go).

Myślę, że najlepiej postawić na znalezienie błędu, to napisać testy jednostkowe dla każdej klasy. Następnie uruchom testy jednostkowe za pomocą mielenia walcowego. Wiem, że to jest ból (ale powinieneś był to zrobić od początku, teraz masz ból za jednym zamachem).

+0

Skąd mogę wiedzieć, czego nie wiem, jeśli nie wiem, że istnieje? :) Żarty na bok, dzięki za wskazówki. Dzięki takim komentarzom mogę dowiedzieć się czegoś więcej. Przyjrzę się temu. Dzięki! – Jir