Ошибка сегментации

Ошибка сегментации (англ. Segmentation fault, сокр. segfault, жарг. сегфолт) — ошибка программного обеспечения, возникающая при попытке обращения к недоступным для записи участкам памяти либо при попытке изменить память запрещённым способом. В системах на основе процессоров Motorola 68000 эти ошибки, как правило, известны как ошибки адреса или шины.

В 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++ не прослеживает такую ошибку при компоновке, что при запуске скомпилированной программы может вызвать ошибку сегментации.

См. также

Примечания

  1. NTSTATUS (англ.).

Ссылки

This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.