Ошибка сегментации
Ошибка сегментации (англ. Segmentation fault, сокр. segfault, жарг. сегфолт) — ошибка программного обеспечения, возникающая при попытке обращения к недоступным для записи участкам памяти либо при попытке изменить память запрещённым способом. В системах на основе процессоров Motorola 6800 эти ошибки, как правило, известны как ошибки адреса или шины.
В UNIX-подобных операционных системах процесс, обращающийся к недействительным участкам памяти, получает сигнал SIGSEGV. В Microsoft Windows процесс, получающий доступ к недействительным участкам памяти, создаёт исключение STATUS_ACCESS_VIOLATION (определение для кода 0xC0000005[1]) и, как правило, предлагает запустить отладчик приложения и показывает пользователю окно с предложением отправить отчёт об ошибке в Microsoft.
Пример
Вот пример кода ANSI C, который приводит к ошибке сегментации из-за присутствия квалификатора типа const
:
const char * s = "hello world";
* (char *) s = 'H';
Когда программа, содержащая этот код, скомпилирована, строка "hello world"
размещена в секции программы с бинарной пометкой «только для чтения». При запуске операционная система помещает её с другими строками и константами в сегмент памяти, предназначенный только для чтения. После запуска переменная s
указывает на адрес начала строки, а попытка присвоить значение символьной константы 'H'
через переменную в памяти приводит к ошибке сегментации.
Компиляция и запуск таких программ на OpenBSD 4.0 вызывает следующую ошибку выполнения:
$ gcc segfault.c -g -o segfault
$ ./segfault
Segmentation fault
Вывод отладчика gdb:
Program received signal SIGSEGV, Segmentation fault.
0x1c0005c2 in main () at segfault.c:6
6 *s = 'H';
В отличие от этого, GCC 4.1.1 на GNU/Linux возвращает ошибку ещё во время компиляции:
$ gcc segfault.c -g -o segfault
segfault.c: In function 'main':
segfault.c:4: error: assignment of read-only location
Условия, при которых происходят нарушения сегментации, и способы их проявления зависят от операционной системы.
Этот пример кода создаёт нулевой указатель и пытается присвоить значение по несуществующему адресу. Это вызывает ошибки сегментации во время выполнения программы на многих системах.
int * ptr = (int *) 0;
*ptr = 1;
Ещё один способ вызвать ошибку сегментации заключается в том, чтобы вызвать функцию main()
рекурсивно, что приведёт к переполнению стека:
int main()
{
main();
}
Обычно ошибка сегментации происходит потому, что:
- указатель нулевой,
- указатель указывает на произвольный участок памяти (возможно потому, что не был инициализирован),
- указатель указывает на удалённый участок памяти.
Например,
char * p1 = NULL; /* инициализирован как нулевой; это допускается, но на многих системах он не может быть разыменован */
char * p2; /* вообще не инициализирован (указывает на произвольный адрес в памяти) */
char * p3 = (char *) malloc(20); /* хорошо, участок памяти выделен */
free(p3); /* но теперь его больше нет */
Теперь разыменование любого из этих указателей может вызвать ошибку сегментации.
Или при использовании массивов, если случайно указать в качестве размера массива неинициализированную переменную:
int main()
{
const int nmax = 10;
int i, n, a[n];
}
Компилятор G++ не прослеживает такую ошибку при компоновке, что при запуске скомпилированной программы может вызвать ошибку сегментации.
См. также
Примечания
- ↑ NTSTATUS (англ.). Дата обращения: 27 января 2022. Архивировано 27 января 2022 года.
Ссылки
- http://www.faqs.org/qa/qa-673.html (англ.) Архивная копия от 28 марта 2008 на Wayback Machine
- http://c-faq.com/null/null1.html Архивировано 26 февраля 2013 года.
- http://c-faq.com/null/varieties.html Архивная копия от 18 августа 2011 на Wayback Machine