Indiana University Indiana University Indiana University

na tej stronie:

  • przegląd
  • przykłady typowych segfaults
  • Znajdź odniesienia do tablic zewnętrznych
  • Sprawdź limity powłoki
  • użyj debuggery do diagnozowania segfaults

przegląd

błąd segmentacji (znany również jako segfault) jest częstym stanem powodującym awarię programów; często są one powiązane z plikiem o nazwie core. Segfaults są spowodowane przez program próbujący odczytać lub zapisać nielegalną lokalizację pamięci.

pamięć programu jest podzielona na różne segmenty: segment tekstowy dla instrukcji programu, segment danych dla zmiennych i tablic zdefiniowanych w czasie kompilacji, segment stosu dla zmiennych tymczasowych (lub automatycznych) zdefiniowanych w podprogramach i funkcjach oraz segment sterty dla zmiennych przydzielonych podczas wykonywania przez funkcje, takie jakmalloc (w C) iallocate (w Fortran). Aby uzyskać więcej informacji, zobacz informacje o segmentach programu.

funkcja segfault występuje, gdy odwołanie do zmiennej wypada poza segment, w którym znajduje się ta zmienna, lub gdy próbuje się zapisać do lokalizacji, która znajduje się w segmencie tylko do odczytu. W praktyce, segfaults są prawie zawsze spowodowane próbą odczytania lub zapisania nieistniejącego elementu tablicy, nieprawidłowym zdefiniowaniem wskaźnika przed jego użyciem lub (w programach C) przypadkowym użyciem wartości zmiennej jako adresu (patrz przykład scanf poniżej).

przykłady typowych segfaults

  • na przykład wywołaniememset(), jak pokazano poniżej, spowodowałoby segfault programu:
    memset((char *)0x0, 1, 100);
  • następujące trzy przypadki ilustrują najczęstsze typy segfaults związanych z tablicą:

    Przypadek A

    /* "Array out of bounds" error valid indices for array foo are 0, 1, ... 999 */ int foo; for (int i = 0; i <= 1000 ; i++) foo = i;

    sprawa b

    /* Illegal memory access if value of n is not in the range 0, 1, ... 999 */ int n; int foo; for (int i = 0; i < n ; i++) foo = i;

    sprawa C

    /* Illegal memory access because no memory is allocated for foo2 */ float *foo, *foo2; foo = (float*)malloc(1000); foo2 = 1.0;

    • w przypadku a, tablicafoo jest zdefiniowany dlaindex = 0,1, 2, ... 999. Jednak w ostatniej iteracji pętli for program próbuje uzyskać dostęp do foo. Spowoduje to uszkodzenie segfault, jeśli ta lokalizacja pamięci znajduje się poza segmentem pamięci, w którym znajduje się foo. Nawet jeśli nie powoduje segfault, nadal jest to błąd.
    • w przypadku B Liczba całkowita n może być dowolną wartością losową. Podobnie jak w przypadku A, jeśli nie znajduje się w zakresie 0, 1, ... 999, może to spowodować segfault. Czy tak, czy nie, jest to z pewnością błąd.
    • w przypadku C alokacja pamięci dla zmiennejfoo2 została pominięta, więcfoo2 będzie wskazywać na losową lokalizację w pamięci. Dostęp do foo2 prawdopodobnie spowoduje segfault.
  • Innym częstym błędem programowania, który prowadzi do segfaults jest nadzór w użyciu wskaźników. Na przykład, funkcja C scanf() oczekuje adresu zmiennej jako drugiego parametru; dlatego poniższe czynniki prawdopodobnie spowodują awarię programu z funkcją segfault:
    int foo = 0; scanf("%d", foo); /* Note missing & sign ; correct usage would have been &foo */

    zmienna foo może być zdefiniowana w lokalizacji pamięci 1000, ale powyższe wywołanie funkcji spróbuje odczytać dane całkowite do lokalizacji pamięci 0 zgodnie z definicją foo.

  • funkcja segfault występuje, gdy program próbuje operować na lokalizacji pamięci w sposób, który nie jest dozwolony (na przykład próba napisania lokalizacji tylko do odczytu skutkowałaby funkcją segfault).
  • Segfaults może również wystąpić, gdy program kończy się na stosie. Może to nie być błąd w twoim programie, ale może być spowodowane ustawieniem przez powłokę limitu rozmiaru stosu zbyt małego.

Znajdź nieobowiązkowe odwołania do tablic

Większość kompilatorów Fortran ma opcję, która wstawia kod do sprawdzania granic wszystkich odwołań do tablic w czasie wykonywania. Jeśli dostęp wykracza poza zakres indeksu zdefiniowany dla tablicy, program zatrzyma się i powie, gdzie to nastąpi. W przypadku większości kompilatorów Fortran opcja to -C lub -check, po którym następuje słowo kluczowe. Zapoznaj się z instrukcją obsługi kompilatora, aby uzyskać dokładną opcję. Używaj sprawdzania granic tylko podczas debugowania, ponieważ spowolni to twój program. Niektóre kompilatory C mają również opcję sprawdzania granic.

Sprawdź limity powłoki

jak wspomniano w ostatnim przykładzie powyżej, niektóre problemy z funkcją segfault nie są spowodowane błędami w programie, ale są spowodowane zbyt niskim limitem pamięci systemowej. Zazwyczaj to ograniczenie rozmiaru stosu powoduje tego rodzaju problem. Aby sprawdzić limity pamięci, użyj polecenia ulimit w poleceniu bash lub ksh lub polecenia limit w poleceniu csh div>lub tcsh. Spróbuj ustawić rozmiar stosu wyższy, a następnie ponownie uruchom program, aby sprawdzić, czy funkcja segfault zniknie.

użyj debuggerów do diagnozowania segfaults

Jeśli nie możesz znaleźć problemu w inny sposób, możesz spróbować debuggera. Na przykład, możesz użyć dobrze znanego debugera GNU GDB, aby zobaczyć ślad pliku core wyrzucanego przez twój program; ilekroć programy segfault, Zwykle zrzucają zawartość (swoją część) pamięci w momencie awarii do pliku core. Uruchom debugger za pomocą polecenia gdb core, a następnie użyj polecenia backtrace, aby zobaczyć, gdzie znajdował się program, gdy uległ awarii. Ta prosta sztuczka pozwoli Ci skupić się na tej części kodu.

Jeśli użycie backtracew pliku core G nie znajdzie problemu, może być konieczne uruchomienie programu pod kontrolą debuggera, a następnie przejście przez kod jednej funkcji lub jednej linii kodu źródłowego naraz. Aby to zrobić, musisz skompilować swój kod bez optymalizacji i z flagą-g, więc informacje o liniach kodu źródłowego zostaną osadzone w pliku wykonywalnym. Aby dowiedzieć się więcej, zobacz przykład użycia GDB w Emacsie do debugowania programu C Orc++.

powiązane dokumenty

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *