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 dzwonisz free
, wie takie rzeczy, jak ilość pamięci do zwolnienia. Te informacje są zwykle przechowywane tuż przed zwróceniem lokalizacji pamięci przez malloc
. 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ęcie size
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 alokacji p1
, p2
oraz p3
:
+------+----------------+------+--------------------+------+----------+
+ size | | size | | size | +
+------+----------------+------+--------------------+------+----------+
^- p1 ^- p2 ^- p3
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 danychp2
, że zaczyna nadpisywanie co jest w p3
„s size
dziedzinie. Kiedy teraz wykonasz następne wywołanie malloc
, 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ł nadpisany size
, 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 zatem malloc
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!