Implementuję algorytm wielomianowy dziel i zwyciężaj, więc mogę porównać go z implementacją OpenCL, ale nie mogę zabrać się malloc
do pracy. Kiedy uruchamiam program, przydziela on kilka rzeczy, sprawdza niektóre rzeczy, a następnie wysyła size/2
do algorytmu. Następnie, kiedy malloc
ponownie trafiam na linię, wypluwa to:
malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
Aborted
Przedmiotowa linia to:
int *mult(int size, int *a, int *b) {
int *out,i, j, *tmp1, *tmp2, *tmp3, *tmpa1, *tmpa2, *tmpb1, *tmpb2,d, *res1, *res2;
fprintf(stdout, "size: %d\n", size);
out = (int *)malloc(sizeof(int) * size * 2);
}
Sprawdziłem rozmiar za pomocą a fprintf
i jest to dodatnia liczba całkowita (zwykle w tym momencie 50). Próbowałem również zadzwonić malloc
ze zwykłego numeru i nadal otrzymuję błąd. Zastanawiam się, co się dzieje, i nic z Google, które znalazłem do tej pory, nie jest pomocne.
Jakieś pomysły, co się dzieje? Próbuję wymyślić, jak skompilować nowsze GCC na wypadek, gdyby był to błąd kompilatora, ale naprawdę w to wątpię.
Odpowiedzi:
99,9% prawdopodobieństwa, że masz uszkodzoną pamięć (przepełniony lub niedostateczny bufor, zapisany do wskaźnika po jego zwolnieniu, dwukrotnie wywołany wolny na tym samym wskaźniku itp.)
Uruchom swój kod pod Valgrind, aby zobaczyć, gdzie twój program zrobił coś nieprawidłowego.
źródło
Aby lepiej zrozumieć, dlaczego tak się dzieje, chciałbym nieco rozwinąć odpowiedź @ r-samuel-klatchko.
Kiedy dzwonisz
malloc
, to, co się naprawdę dzieje, jest nieco bardziej skomplikowane niż zwykłe udostępnianie kawałka pamięci do zabawy. Pod maskąmalloc
przechowuje również pewne informacje porządkowe dotyczące pamięci, którą Ci przekazał (co najważniejsze, jej rozmiaru), dzięki czemu kiedy dzwoniszfree
, wie takie rzeczy, jak ilość pamięci do zwolnienia. Te informacje są zwykle przechowywane tuż przed zwróceniem lokalizacji pamięci przezmalloc
. Bardziej wyczerpujące informacje można znaleźć w Internecie ™ , ale (bardzo) podstawowa idea jest taka:+------+-------------------------------------------------+ + size | malloc'd memory + +------+-------------------------------------------------+ ^-- location in pointer returned by malloc
Opierając się na tym (i znacznie upraszczając), kiedy dzwonisz
malloc
, musi uzyskać wskaźnik do następnej dostępnej części pamięci. Jednym z bardzo prostych sposobów jest przyjrzenie się poprzedniej części pamięci, którą oddał, i przesunięciesize
bajtów dalej w dół (lub w górę) pamięci. Dzięki tej realizacji, możesz skończyć z pamięci poszukuje czegoś takiego po alokacjip1
,p2
orazp3
:Więc co powoduje twój błąd?
Cóż, wyobraź sobie, że twój kod błędnie zapisuje więcej niż ilość przydzielonej pamięci (albo dlatego, że przydzieliłeś mniej niż potrzebujesz, tak jak był twój problem, albo ponieważ gdzieś w kodzie używasz niewłaściwych warunków brzegowych). Powiedz, że Twój kod zapisuje tak dużo danych
p2
, że zaczyna nadpisywanie co jest wp3
„ssize
dziedzinie. Kiedy teraz wykonasz następne wywołaniemalloc
, sprawdzi ostatnią lokalizację pamięci, którą zwrócił, spojrzy na pole rozmiaru, przejdzie do,p3 + size
a następnie rozpocznie alokację pamięci z tego miejsca. Ponieważ jednak kod został nadpisanysize
, ta lokalizacja pamięci nie jest już po poprzednio przydzielonej pamięci.Nie trzeba dodawać, że może to siać spustoszenie! Dlatego też implementatorzy
malloc
wprowadzili szereg „asercji” lub sprawdzeń, które próbują wykonać kilka sprawdzeń poczytalności, aby złapać to (i inne problemy), jeśli mają się wydarzyć. W twoim konkretnym przypadku te twierdzenia są naruszane, a zatemmalloc
przerywają, informując cię, że twój kod miał zrobić coś, czego naprawdę nie powinien robić.Jak już wspomniano, jest to znaczne uproszczenie, ale wystarczy to zilustrować. Implementacja glibc
malloc
obejmuje ponad 5 tys. Linii i przeprowadzono wiele badań nad tym, jak zbudować dobre mechanizmy dynamicznej alokacji pamięci, więc uwzględnienie tego wszystkiego w odpowiedzi SO nie jest możliwe. Miejmy nadzieję, że dało ci to trochę poglądu na to, co naprawdę powoduje problem!źródło
Moje alternatywne rozwiązanie do korzystania z Valgrind:
Jestem bardzo szczęśliwy, ponieważ właśnie pomogłem mojemu przyjacielowi zdebugować program. Jego program miał dokładnie ten problem (
malloc()
powodujący przerwanie), z tym samym komunikatem o błędzie z GDB.Skompilowałem jego program przy użyciu Address Sanitizer z
gcc -Wall -g3 -fsanitize=address -o new new.c ^^^^^^^^^^^^^^^^^^
A potem uciekł
gdb new
. Kiedy program zostanie zakończony przezSIGABRT
spowodowany w kolejnymmalloc()
, drukowanych jest wiele przydatnych informacji:================================================================= ==407==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6060000000b4 at pc 0x7ffffe49ed1a bp 0x7ffffffedc20 sp 0x7ffffffed3c8 WRITE of size 104 at 0x6060000000b4 thread T0 #0 0x7ffffe49ed19 (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x5ed19) #1 0x8001dab in CreatHT2 /home/wsl/Desktop/hash/new.c:59 #2 0x80031cf in main /home/wsl/Desktop/hash/new.c:209 #3 0x7ffffe061b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96) #4 0x8001679 in _start (/mnt/d/Desktop/hash/new+0x1679) 0x6060000000b4 is located 0 bytes to the right of 52-byte region [0x606000000080,0x6060000000b4) allocated by thread T0 here: #0 0x7ffffe51eb50 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb50) #1 0x8001d56 in CreatHT2 /home/wsl/Desktop/hash/new.c:55 #2 0x80031cf in main /home/wsl/Desktop/hash/new.c:209 #3 0x7ffffe061b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
Przyjrzyjmy się wynikowi, zwłaszcza śladowi stosu:
Pierwsza część mówi, że w miejscu jest nieprawidłowa operacja zapisu
new.c:59
. Ta linia brzmimemset(len,0,sizeof(int*)*p); ^^^^^^^^^^^^
Druga część mówi, że pamięć, w której nastąpił zły zapis, jest tworzona w
new.c:55
. Ta linia brzmiif(!(len=(int*)malloc(sizeof(int)*p))){ ^^^^^^^^^^^
Otóż to. Zajęło mi tylko mniej niż pół minuty, aby zlokalizować błąd, który mylił mojego przyjaciela przez kilka godzin. Udało mu się zlokalizować awarię, ale to kolejna
malloc()
wywołanie, które się nie powiodło, bez możliwości wykrycia tego błędu w poprzednim kodzie.Podsumowując: wypróbuj
-fsanitize=address
GCC lub Clang. Może być bardzo pomocny podczas debugowania problemów z pamięcią.źródło
Prawdopodobnie gdzieś przekraczasz przydzieloną pamięć. to bazowy SW nie odbiera go, dopóki nie zadzwonisz do malloc
Może być pobita wartość strażnika, która została złapana przez malloc.
edit ... dodał to do pomocy przy sprawdzaniu granic
http://www.lrde.epita.fr/~akim/ccmp/doc/bounds-checking.html
źródło
Otrzymałem następującą wiadomość, podobną do Twojej:
Podczas korzystania z malloc popełniłem błąd przed wywołaniem metody. Błędnie nadpisano znak mnożenia „*” znakiem „+” podczas aktualizacji współczynnika po operatorze sizeof () - przy dodawaniu pola do tablicy bez znaku.
Oto kod odpowiedzialny za błąd w moim przypadku:
Później w innej metodzie ponownie użyłem malloc i wyświetlił się komunikat o błędzie pokazany powyżej. Rozmowa była (dość prosta):
Pomyśl o użyciu znaku '+' - przy pierwszym wywołaniu, które doprowadziło do błędnego rachunku w połączeniu z natychmiastową inicjalizacją tablicy po (nadpisaniu pamięci, która nie została przydzielona do tablicy), wprowadziło pewne zamieszanie do mapy pamięci malloc. Dlatego drugie połączenie poszło nie tak.
źródło
Otrzymaliśmy ten błąd, ponieważ zapomnieliśmy pomnożyć przez sizeof (int). Zwróć uwagę, że argument funkcji malloc (..) to liczba bajtów, a nie liczba słów maszynowych czy cokolwiek innego.
źródło
Mam ten sam problem, użyłem malloc nad n ponownie w pętli do dodawania nowych danych ciągu char *. napotkałem ten sam problem, ale po zwolnieniu przydzielonej pamięci
void free()
problem został rozwiązanyźródło
Portowałem jedną aplikację z Visual C na gcc przez Linuksa i miałem ten sam problem
Przeniosłem ten sam kod do dystrybucji Suse (na innym komputerze) i nie mam żadnego problemu.
Podejrzewam, że problemy nie występują w naszych programach, ale we własnej bibliotece libc.
źródło