Błąd segmentacji

Winy segmentacji (w angielskiej winy segmentacji , w skrócie wysypać ) to katastrofa o aplikacji , który próbował uzyskać dostęp do lokalizacji pamięci , która nie została przydzielona.

Uruchomione aplikacje wymagają pamięci RAM przydzielonej przez system operacyjny . Po przypisaniu do aplikacji żadna inna aplikacja nie może mieć dostępu do tej strefy; gwarantuje to niezawodność działania każdej aplikacji przed błędami innych. Tak więc, jeśli aplikacja próbuje uzyskać najmniejszy dostęp do obszaru pamięci, który nie jest jej przydzielony, system operacyjny wykrywa go i natychmiast zatrzymuje jego wykonywanie.

Zdecydowana większość błędów segmentacji nie jest zamierzona (jeśli tak jest, istnieje duża szansa, że ​​ma to charakter przestępczy); wynikają one ze złego projektu lub wykonania aplikacji.

Przykłady

Po uruchomieniu programu system operacyjny przydziela mu pamięć. Jednak zdarza się, że w trakcie wykonywania aplikacja na potrzeby przetwarzania potrzebuje dodatkowej pamięci. Następnie prosi system operacyjny o przydzielenie mu określonej ilości pamięci. W takim przypadku obowiązkiem aplikacji jest użycie tej pamięci i uważanie, aby nie pisać ani nie czytać poza przydzielonym obszarem pamięci.

Cały problem polega na tym, aby wiedzieć, gdzie jesteś, kiedy używasz tej pamięci. I wtedy, jeśli się nie przejmujemy, przepełniamy pamięć i aplikacja się kończy. Nazywa się to przepełnieniem bufora .

Inną przyczyną błędów segmentacji jest zła inicjalizacja wskaźnika . Ten ostatni wskazuje następnie na dowolny obszar pamięci i kiedy jest używany, istnieje duża szansa, że ​​ten ostatni będzie zawierał adres, który nie jest przydzielony aplikacji. I tak jak poprzednio, jest to błąd segmentacji generowany przez system operacyjny.

Aby uniknąć problemów ze wskaźnikami, konieczne jest zainicjowanie ich prawidłowym adresem lub wartością NULL (kod będzie musiał poprawnie go przetworzyć) przed każdym użyciem.

Programy powodujące błąd segmentacji

Oto przykłady programów w C , które mogą powodować taki błąd.

Przykład ze zmienną

#include <stdio.h> #include <stdlib.h> int main() { int *variable_entiere; scanf("%d", variable_entiere); return (EXIT_SUCCESS); }

Scanf funkcja stara się odzyskać liczbę całkowitą ze standardowego wejścia (domyślnie klawiatura ) i zapisuje tę wartość w zmiennej . Aby móc tam przechowywać dane, scanf musi znać adres zmiennej (w naszym przypadku: variable_entiere).

Jednak w naszym przypadku wartość variable_entierenie jest zainicjowana i dlatego ma jakąkolwiek wartość. Funkcja scanf następnie próbuje uzyskać dostęp do obszaru pamięci reprezentowanego przez wartość zawartą w variable_entierei najprawdopodobniej spowoduje błąd segmentacji.

Inny przykład

int main() { int *pointeur, valeur; valeur = 3; *pointeur = valeur * valeur; return (EXIT_SUCCESS); }

Problem polega na tym, że chcemy zapisać wynik operacji valeur * valeuri mieć do niego dostęp za pomocą wskaźnika (nazwanego tutaj pointeur). Jednakże, ponieważ wskaźnik nie przydziela żadnej przestrzeni pamięci innej niż dla siebie samego, nie można mu przypisać wartości, dopóki nie wskaże prawidłowo przydzielonej przestrzeni pamięci (takiej jak zmienna) bez ryzyka spowodowania błędu segmentacji. Ponieważ niezainicjowany wskaźnik wskazuje na losowe miejsce w pamięci.

Jednym z rozwiązań jest utworzenie drugiej zmiennej (nazwanej tutaj resultat), na którą wskazuje wskaźnik:

int main() { int *pointeur, valeur, resultat; pointeur = &resultat; valeur = 3; *pointeur = valeur * valeur; /* maintenant la variable resultat contient 9 */ return (EXIT_SUCCESS); }

Inne rozwiązanie polegałoby na dynamicznej alokacji pamięci, to znaczy zapytaniu systemu operacyjnego pamięci i wskazaniu wskaźnika na tę nową przestrzeń pamięci:

#include <stdlib.h> int main() { int *pointeur, valeur; pointeur = malloc(sizeof(*pointeur)); if (pointeur == NULL) /* La fonction malloc() retourne NULL en cas d'échec. */ return (EXIT_FAILURE); valeur = 3; *pointeur = valeur * valeur; free(pointeur); /* On libère la mémoire. */ return (EXIT_SUCCESS); }

Wartość zwracana

Podczas błędu segmentacji błąd podawany przez powłokę to 139 : koniec procesu spowodowany sygnałem, powłoka dodaje 128do kodu sygnału. SIGSEGVprawidłowy 11, otrzymany błąd to 139.

Uwagi i odniesienia

  1. "  bash (1): GNU Bourne-Again SHell - strona podręcznika Linux  " , na linux.die.net (dostęp 3 września 2019 )
  2. "  signal (7) - strona podręcznika Linux  " , na man7.org (dostęp 3 września 2019 )