Co to jest segmentation fault?
Segmentation fault (segfault, po polsku naruszenie ochrony pamięci) to awaria, która następuje, gdy program próbuje odczytać lub zapisać pamięć, do której nie ma dostępu, na przykład adres 0 przez wskaźnik null. System operacyjny zatrzymuje program sygnałem SIGSEGV.
Aktualizacja: 24 września 2026
Program w C wypisuje pierwszą linię, a potem zatrzymuje się z komunikatem, którego nikt nie napisał:
#include <stdio.h>
int main(void) {
int *score = NULL;
printf("About to read the score\n");
printf("Score: %d\n", *score);
return 0;
}
About to read the score
bash: line 1: 64030 Segmentation fault: 11 ./seg
To wynik z basha na macOS, gdzie 64030 to identyfikator procesu, a 11 to numer sygnału. Na Linuksie ta sama awaria wygląda zwykle tak: Segmentation fault (core dumped). Tak czy inaczej, program nigdy nie wypisał wyniku. score przechowuje adres 0, a *score każe procesorowi odczytać pamięć pod tym adresem, czego żaden program robić nie może.
Jak dochodzi do segmentation fault
Każdy program działa we własnej wirtualnej przestrzeni adresowej, ogromnym zakresie adresów, który system operacyjny wypełnia kawałek po kawałku. Mapuje w nim kod programu, jego zmienne globalne, stos i stertę, w blokach zwanych stronami (4 KB w większości systemów Linux na x86, 16 KB na Macach z Apple silicon). Większość adresów pozostaje niezmapowana, a adres 0 zawsze do nich należy, żeby błędy ze wskaźnikiem null zostały wychwycone.
- Program wykonuje instrukcję, która odczytuje lub zapisuje adres. Tutaj jest to odczyt
*score, czyli adresu 0. - Jednostka zarządzania pamięcią (MMU) procesora szuka adresu w tablicy stron. Strona nie jest zmapowana albo program próbuje pisać na stronie tylko do odczytu.
- Procesor przerywa instrukcję i przekazuje sterowanie jądru, zgłaszając błąd strony (page fault).
- Jądro sprawdza, czy taki dostęp mógłby być dozwolony, na przykład gdy stos musi urosnąć. Nie jest, więc jądro wysyła do procesu sygnał 11,
SIGSEGV. - Domyślną reakcją na
SIGSEGVjest zakończenie procesu i, jeśli system na to pozwala, zapisanie zrzutu pamięci (core dump). Powłoka wypisuje wtedy komunikat i ustawia status wyjścia na 139, czyli 128 plus numer sygnału.
Segmentation fault nie jest więc zgłaszany przez kompilator ani nie jest wyjątkiem rzucanym przez język. To sprzęt i jądro chronią pamięć, co czyni z niego runtime error najbardziej gwałtownego rodzaju. Windows obsługuje to samo zdarzenie jako naruszenie dostępu (access violation), kod wyjątku 0xC0000005.
Częste przyczyny segmentation fault
C i C++ pozwalają programowi obliczyć dowolny adres i go użyć, więc wszystkie przyczyny sprowadzają się do użycia adresu, który nie jest prawidłowy.
- Dereferencja wskaźnika null.
int *p = NULL; *p = 5;Funkcja, która przy niepowodzeniu zwracaNULL, taka jakmallocczyfopen, prowadzi do tego, gdy nikt nie sprawdzi jej wyniku. - Indeks daleko za końcem tablicy. C nie sprawdza granic, więc
arr[1000000]to po prostu adres o milion elementów dalej. - Użycie pamięci po
free. Wskaźnik wciąż przechowuje stary adres, ale pamięć już do ciebie nie należy. - Niezainicjalizowany wskaźnik.
int *p; *p = 5;zapisuje pod przypadkowy adres, który akurat przechowujep. - Przepełnienie stosu. Funkcja rekurencyjna bez warunku stopu dokłada kolejne ramki stosu, aż wyjdzie poza jego koniec. Poniższy przykład wysypał się na macOS z komunikatem
Segmentation fault: 11i statusem wyjścia 139. - Zapis do literału napisowego.
char *name = "coddy"; name[0] = 'C';próbuje zmienić pamięć tylko do odczytu. Na Linuksie to segfault. Na macOS ten sam program zatrzymał się zBus error: 10, pokrewnym sygnałem.
#include <stdio.h>
int depth(int n) {
return depth(n + 1) + 1; /* never stops calling itself */
}
int main(void) {
printf("%d\n", depth(0));
return 0;
}
Mała pomyłka często w ogóle nie powoduje awarii, przez co jest groźniejsza. Ta pętla czyta jeden element za końcem trzyelementowej tablicy:
#include <stdio.h>
int main(void) {
int scores[3] = {72, 88, 95};
int total = 0;
for (int i = 0; i <= 3; i++) { /* <= reads scores[3] */
total += scores[i];
}
printf("Total: %d\n", total);
return 0;
}
Skompilowany Clangiem na Macu wypisał Total: 256. Poprawna suma to 255. scores[3] to były kolejne 4 bajty stosu, które należały do programu, więc żaden błąd nie wystąpił, a przypadkowa wartość została po cichu dodana. System operacyjny zatrzymuje tylko dostęp do pamięci, która w ogóle nie należy do programu.
Na obie pomyłki pomaga ten sam nawyk: wiedz, ile jest elementów, i sprawdzaj wskaźnik, zanim go użyjesz.
Best: 95
No scores, nothing to read
Co oznacza „core dumped”
Zrzut pamięci (core dump) to plik z kopią pamięci programu z chwili awarii. Debuger może go później otworzyć i pokazać dokładnie, gdzie był program i co zawierały jego zmienne: gdb ./app core. W wielu dystrybucjach Linuksa te pliki zbiera systemd-coredump, a coredumpctl list je wyświetla. Gdy zrzuty pamięci są wyłączone, na przykład przez ulimit -c 0, komunikat brzmi po prostu Segmentation fault, bez słów w nawiasie.
Jak znaleźć linię, w której nastąpiła awaria
Linia, w której program się wysypuje, często nie jest linią z błędem. Wskaźnik może stać się nieprawidłowy w jednej funkcji, a zostać użyty w innej dużo później. Te narzędzia pokazują jedno i drugie.
Debuger. Skompiluj program z informacjami do debugowania i uruchom go w debugerze. Gdy się zatrzyma, bt (backtrace) wypisze łańcuch wywołań funkcji z nazwami plików i numerami linii. Na Linuksie debugerem jest zwykle gdb, a na macOS lldb, w którym bt działa tak samo.
gcc -g app.c -o app
gdb ./app
(gdb) run
(gdb) bt
AddressSanitizer. Skompiluj program z -fsanitize=address (obsługują to zarówno GCC, jak i Clang) i uruchom go normalnie. Zamiast gołego segfaulta dostaniesz raport, który nazywa rodzaj pomyłki, na przykład heap-use-after-free albo stack-buffer-overflow, i podaje linię, która sięgnęła do pamięci, oraz linię, która ją zaalokowała. Wyłapuje też opisany wyżej cichy odczyt o jeden element za końcem, który sam z siebie nigdy nie powoduje awarii.
Valgrind. Na Linuksie valgrind ./app uruchamia niezmieniony program i zgłasza każdy nieprawidłowy odczyt lub zapis, na przykład Invalid read of size 4.
Segmentation fault w innych językach
Python, Java i JavaScript sprawdzają każdy indeks i każde odwołanie przed użyciem, więc te same pomyłki stają się wyjątkami z czytelnymi komunikatami: IndexError lub AttributeError w Pythonie, ArrayIndexOutOfBoundsException lub NullPointerException w Javie, TypeError w JavaScripcie. Można je przechwycić dzięki obsłudze wyjątków. Segfaulta nie da się tak obsłużyć: to sygnał, a blok catch w C++ go nie widzi.
Programy w Pythonie wciąż mogą dostać segfault, gdy pod spodem zawiedzie kod w C. Ta linia prosi ctypes o odczyt adresu 0:
import ctypes
ctypes.string_at(0)
Uruchomiony przez python3 -X faulthandler Python 3.12 wypisał Fatal Python error: Segmentation fault, a po nim linie Pythona, które się wtedy wykonywały. Ta sama awaria zdarza się, gdy rozszerzenie w C albo natywna biblioteka ma błąd pamięci. Rust podchodzi do tego inaczej: jego kompilator odrzuca większość kodu, który mógłby sięgnąć do nieprawidłowej pamięci, zanim program w ogóle zostanie zbudowany.
Co dalej
Przewodnik po C o segmentation fault omawia każdą przyczynę na minimalnym programie i pokazuje poprawkę. Żeby w ogóle unikać tych pomyłek, przeczytaj o wskaźnikach, wskaźnikach null oraz o stosie i stercie, a potem przećwicz to w kursie C. O tym, jak zgłaszane są błędy w językach, które pilnują pamięci za ciebie, przeczytasz na stronie o runtime error.
Najczęściej zadawane pytania
Jak naprawić segmentation fault?
-g i uruchom go w gdb lub lldb, a po awarii wpisz bt, albo skompiluj z -fsanitize=address, żeby dostać szczegółowy raport. Potem popraw wskaźnik lub indeks używany w tej linii: sprawdzaj wskaźniki pod kątem NULL, trzymaj indeksy tablic poniżej długości, nie używaj pamięci po free i upewnij się, że rekurencja się kończy.Czy segmentation fault to wyciek pamięci?
free, takie jak użycie wskaźnika po zwolnieniu pamięci, mogą powodować segfaulty, a zapomniane free powoduje wycieki.Skąd nazwa segmentation fault?
SIGSEGV, została. Windows nazywa to samo zdarzenie naruszeniem dostępu (access violation).Czy w Pythonie może wystąpić segmentation fault?
ctypes. Uruchomienie python -X faulthandler script.py wypisuje linie Pythona, które wykonywały się w chwili awarii.Co oznacza kod wyjścia 139?
SIGSEGV, segmentation fault. Powłoki zgłaszają śmierć od sygnału jako 128 plus numer sygnału, a 128 + 11 = 139. W Dockerze i Kubernetesie kontener, który kończy się kodem 139, miał segfault w głównym procesie.