Błąd: wolny (): nieprawidłowy następny rozmiar (szybko):


91

Co to za dziwny błąd, który otrzymuję? Kompiluję C ++ przy użyciu g ++ na Ubuntu 10.10. Wyskakuje losowo, kiedy uruchamiam plik wykonywalny (może 2 razy w ciągu 8 godzin, przy 10 kompilacjach na godzinę). Jeśli jednak wyczyszczę i skompiluję ponownie, w większości przypadków znika.

*** glibc detected *** ./emailQueue.app: free(): invalid next size (fast): 0x0000000001c40270 ***
======= Backtrace: =========
/lib/libc.so.6(+0x774b6)[0x7f490d95e4b6]
/lib/libc.so.6(cfree+0x73)[0x7f490d964c83]
./emailQueue.app[0x401f47]
/lib/libc.so.6(__libc_start_main+0xfe)[0x7f490d905d8e]
./emailQueue.app[0x401cc9]
======= Memory map: ========
00400000-0040d000 r-xp 00000000 08:01 1311132                            /home/server/Projects/email/emailQueue.app
0060d000-0060e000 r--p 0000d000 08:01 1311132                            /home/server/Projects/email/emailQueue.app
0060e000-0060f000 rw-p 0000e000 08:01 1311132                            /home/server/Projects/email/emailQueue.app
01c40000-01c82000 rw-p 00000000 00:00 0                                  [heap]
7f4908000000-7f4908021000 rw-p 00000000 00:00 0 
7f4908021000-7f490c000000 ---p 00000000 00:00 0 
7f490ce52000-7f490ce5e000 r-xp 00000000 08:01 1051251                    /lib/libnss_files-2.12.1.so
7f490ce5e000-7f490d05d000 ---p 0000c000 08:01 1051251                    /lib/libnss_files-2.12.1.so
7f490d05d000-7f490d05e000 r--p 0000b000 08:01 1051251                    /lib/libnss_files-2.12.1.so
7f490d05e000-7f490d05f000 rw-p 0000c000 08:01 1051251                    /lib/libnss_files-2.12.1.so
7f490d05f000-7f490d075000 r-xp 00000000 08:01 1048770                    /lib/libz.so.1.2.3.4
7f490d075000-7f490d275000 ---p 00016000 08:01 1048770                    /lib/libz.so.1.2.3.4
7f490d275000-7f490d276000 r--p 00016000 08:01 1048770                    /lib/libz.so.1.2.3.4
7f490d276000-7f490d277000 rw-p 00017000 08:01 1048770                    /lib/libz.so.1.2.3.4
7f490d277000-7f490d28e000 r-xp 00000000 08:01 1051248                    /lib/libnsl-2.12.1.so
7f490d28e000-7f490d48d000 ---p 00017000 08:01 1051248                    /lib/libnsl-2.12.1.so
7f490d48d000-7f490d48e000 r--p 00016000 08:01 1051248                    /lib/libnsl-2.12.1.so
7f490d48e000-7f490d48f000 rw-p 00017000 08:01 1051248                    /lib/libnsl-2.12.1.so
7f490d48f000-7f490d491000 rw-p 00000000 00:00 0 
7f490d491000-7f490d49a000 r-xp 00000000 08:01 1051244                    /lib/libcrypt-2.12.1.so
7f490d49a000-7f490d69a000 ---p 00009000 08:01 1051244                    /lib/libcrypt-2.12.1.so
7f490d69a000-7f490d69b000 r--p 00009000 08:01 1051244                    /lib/libcrypt-2.12.1.so
7f490d69b000-7f490d69c000 rw-p 0000a000 08:01 1051244                    /lib/libcrypt-2.12.1.so
7f490d69c000-7f490d6ca000 rw-p 00000000 00:00 0 
7f490d6ca000-7f490d6e2000 r-xp 00000000 08:01 1051256                    /lib/libpthread-2.12.1.so
7f490d6e2000-7f490d8e1000 ---p 00018000 08:01 1051256                    /lib/libpthread-2.12.1.so
7f490d8e1000-7f490d8e2000 r--p 00017000 08:01 1051256                    /lib/libpthread-2.12.1.so
7f490d8e2000-7f490d8e3000 rw-p 00018000 08:01 1051256                    /lib/libpthread-2.12.1.so
7f490d8e3000-7f490d8e7000 rw-p 00000000 00:00 0 
7f490d8e7000-7f490da61000 r-xp 00000000 08:01 1048743                    /lib/libc-2.12.1.so
7f490da61000-7f490dc60000 ---p 0017a000 08:01 1048743                    /lib/libc-2.12.1.so
7f490dc60000-7f490dc64000 r--p 00179000 08:01 1048743                    /lib/libc-2.12.1.so
7f490dc64000-7f490dc65000 rw-p 0017d000 08:01 1048743                    /lib/libc-2.12.1.so
7f490dc65000-7f490dc6a000 rw-p 00000000 00:00 0 
7f490dc6a000-7f490dc7f000 r-xp 00000000 08:01 1048655                    /lib/libgcc_s.so.1
7f490dc7f000-7f490de7e000 ---p 00015000 08:01 1048655                    /lib/libgcc_s.so.1
7f490de7e000-7f490de7f000 r--p 00014000 08:01 1048655                    /lib/libgcc_s.so.1
7f490de7f000-7f490de80000 rw-p 00015000 08:01 1048655                    /lib/libgcc_s.so.1
7f490de80000-7f490df02000 r-xp 00000000 08:01 1051246                    /lib/libm-2.12.1.so
7f490df02000-7f490e101000 ---p 00082000 08:01 1051246                    /lib/libm-2.12.1.so
7f490e101000-7f490e102000 r--p 00081000 08:01 1051246                    /lib/libm-2.12.1.so
7f490e102000-7f490e103000 rw-p 00082000 08:01 1051246                    /lib/libm-2.12.1.so
7f490e103000-7f490e1eb000 r-xp 00000000 08:01 4853329                    /usr/lib/libstdc++.so.6.0.14
7f490e1eb000-7f490e3ea000 ---p 000e8000 08:01 4853329                    /usr/lib/libstdc++.so.6.0.14
7f490e3ea000-7f490e3f2000 r--p 000e7000 08:01 4853329                    /usr/lib/libstdc++.so.6.0.14
7f490e3f2000-7f490e3f4000 rw-p 000ef000 08:01 4853329                    /usr/lib/libstdc++.so.6.0.14
7f490e3f4000-7f490e409000 rw-p 00000000 00:00 0 
7f490e409000-7f490e5c7000 r-xp 00000000 08:01 4851315                    /usr/lib/libmysqlclient.so.16.0.0
7f490e5c7000-7f490e7c7000 ---p 001be000 08:01 4851315                    /usr/lib/libmysqlclient.so.16.0.0
7f490e7c7000-7f490e7cc000 r--p 001be000 08:01 4851315                    /usr/lib/libmysqlclient.so.16.0.0
7f490e7cc000-7f490e816000 rw-p 001c3000 08:01 4851315                    /usr/lib/libmysqlclient.so.16.0.0
7f490e816000-7f490e817000 rw-p 00000000 00:00 0 
7f490e817000-7f490e837000 r-xp 00000000 08:01 1048597                    /lib/ld-2.12.1.so
7f490ea15000-7f490ea1c000 rw-p 00000000 00:00 0 
7f490ea33000-7f490ea37000 rw-p 00000000 00:00 0 
7f490ea37000-7f490ea38000 r--p 00020000 08:01 1048597                    /lib/ld-2.12.1.so
7f490ea38000-7f490ea39000 rw-p 00021000 08:01 1048597                    /lib/ld-2.12.1.so
7f490ea39000-7f490ea3a000 rw-p 00000000 00:00 0 
7fffb85b9000-7fffb85da000 rw-p 00000000 00:00 0                          [stack]
7fffb85ff000-7fffb8600000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted

1
Brakujący średnik spowodował ten błąd.
atzol

Odpowiedzi:


108

Oznacza to, że wystąpił błąd pamięci. Być może próbujesz freeznaleźć wskaźnik, który nie został przydzielony przez malloc(lub deleteobiekt, który nie został utworzony przez new) lub możesz próbować free/ deletetakiego obiektu więcej niż raz. Możesz przepełniać bufor lub w inny sposób zapisywać do pamięci, do której nie powinieneś pisać, powodując uszkodzenie sterty.

Dowolna liczba błędów programistycznych może powodować ten problem. Musisz użyć debuggera, pobrać ślad i zobaczyć, co robi twój program, gdy wystąpi błąd. Jeśli to się nie powiedzie i stwierdzisz, że uszkodziłeś stertę w jakimś poprzednim momencie, możesz być narażony na bolesne debugowanie (może nie być zbyt bolesne, jeśli projekt jest na tyle mały, że możesz zająć się nim kawałek po kawałku).


37
Narzędzia takie jak valgrind są bardzo pomocne w znajdowaniu źródła tego typu błędów. Po prostu upewnij się, że kompilujesz z symbolami debugowania.
Daniel Gallagher,

3
FYI: Miałem to po zmianie rozmiaru std :: vector <> i nie był wystarczająco duży.
Adam27X

1
Naprawdę? Wystąpił problem z funkcją free (), gdy wektor nie był wystarczająco duży. Przynajmniej przeczytaj najpierw pytanie.
Gyan

22

Napotkałem ten sam problem, mimo że nie dokonałem żadnej dynamicznej alokacji pamięci w moim programie, ale uzyskiwałem dostęp do indeksu wektora bez przydzielania dla niego pamięci. Tak więc, jeśli w tym samym przypadku, lepiej przydzielić trochę pamięci za pomocą, resize()a następnie uzyskać dostęp do elementów wektora.


7

Potrzebujemy kodu, ale zwykle pojawia się on, gdy próbujesz odczytać free()pamięć ze wskaźnika, który nie jest przydzielony. Dzieje się tak często, gdy uwalniasz się podwójnie.


6

Jeśli próbujesz przydzielić miejsce na tablicę wskaźników, takich jak

char** my_array_of_strings;  // or some array of pointers such as int** or even void**

wtedy będziesz musiał wziąć pod uwagę rozmiar słowa (8 bajtów w systemie 64-bitowym, 4 bajty w systemie 32-bitowym) podczas przydzielania miejsca na n wskaźników. Rozmiar wskaźnika jest taki sam, jak rozmiar słowa.

Więc chociaż możesz chcieć przeznaczyć miejsce na n wskaźników, w rzeczywistości będziesz potrzebować n razy 8 lub 4 (odpowiednio dla systemów 64-bitowych lub 32-bitowych)

Aby uniknąć przepełnienia przydzielonej pamięci dla n elementów po 8 bajtów:

my_array_of_strings = (char**) malloc( n * 8 );  // for 64-bit systems
my_array_of_strings = (char**) malloc( n * 4 );  // for 32-bit systems

To zwróci blok n wskaźników, z których każdy składa się z 8 bajtów (lub 4 bajty, jeśli używasz systemu 32-bitowego)

Zauważyłem, że Linux pozwoli ci użyć wszystkich n wskaźników, gdy nie skompensowałeś rozmiaru słowa, ale kiedy spróbujesz zwolnić tę pamięć, zdaje sobie sprawę z błędu i podaje ten raczej paskudny błąd. I to jest zły, kiedy przepełnisz przydzieloną pamięć, wiele problemów z bezpieczeństwem czeka.


3
Możemy uczynić ten sam kod ogólny dla dowolnego systemu, zamiast zakodować na stałe 4 lub 8 bajtów za pomocą sizeof(char*).
Ben G.

Nie używanie sizeofoperatora podczas korzystania z malloc jest tak naprawdę po prostu pytaniem o kłopoty. IIRC standard gwarantuje rozmiar znaku, ale prawie wszystko inne zależy od ISA, więc naprawdę najlepiej używać go sizeofwszędzie.
ajxs

1

Spotkałem się z taką sytuacją, w której kod obchodził api STL i zapisywał do tablicy niebezpiecznie, gdy ktoś zmienił jej rozmiar. Dodanie asertu tutaj złapało to:

void Logo::add(const QVector3D &v, const QVector3D &n)
{
 GLfloat *p = m_data.data() + m_count;
 *p++ = v.x();
 *p++ = v.y();
 *p++ = v.z();
 *p++ = n.x();
 *p++ = n.y();
 *p++ = n.z();
 m_count += 6;
 Q_ASSERT( m_count <= m_data.size() );
}

1

Napotkałem podobny błąd. To był błąd popełniony w pośpiechu. Tablica liczb całkowitych bez deklarowania rozmiaru int a [], a następnie próba uzyskania do niej dostępu. Kompilator C ++ powinien łatwo wykryć taki błąd, gdyby był w main. Jednak ponieważ ta konkretna tablica int została zadeklarowana wewnątrz obiektu, była tworzona w tym samym czasie, co mój obiekt (tworzonych było wiele obiektów), a kompilator generował błąd free (): nieprawidłowy następny rozmiar (normalny). Pomyślałem o 2 wyjaśnieniach tego (proszę mnie oświecić, jeśli ktoś wie więcej): 1.) Spowodowało to przypisanie do niej jakiejś pamięci losowej, ale ponieważ nie było to dostępne, zwalniało całą inną pamięć sterty, którą po prostu próbowałem znaleźć ten int. 2.) Pamięć wymagana przez niego była praktycznie nieskończona dla programu i przypisanie jej zwalniało całą inną pamięć.

Prosty:

    int* a;
    class foo{ 
    foo(){
       for(i=0;i<n;i++)
           a=new int[i];
     }

Rozwiązać problem. Jednak próba debugowania tego problemu zajęła dużo czasu, ponieważ kompilator nie mógł „naprawdę” znaleźć błędu.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.