Что такое ошибка сегментации (segmentation fault)?
Ошибка сегментации (segmentation fault, segfault) это аварийное завершение программы, когда она пытается прочитать или записать память, к которой у неё нет доступа, например адрес 0 через нулевой указатель. Операционная система останавливает программу сигналом SIGSEGV.
Обновлено 24 сентября 2026 г.
Программа на C выводит первую строку, а потом останавливается с сообщением, которого никто не писал:
#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
Этот вывод получен в bash на macOS, где 64030 это идентификатор процесса, а 11 номер сигнала. В Linux то же падение обычно выглядит как Segmentation fault (core dumped). В любом случае программа так и не вывела оценку. В score хранится адрес 0, а *score просит процессор прочитать память по этому адресу, чего не разрешено делать ни одной программе.
Как возникает ошибка сегментации
Каждая программа работает в своём виртуальном адресном пространстве, огромном диапазоне адресов, который операционная система заполняет по частям. Она отображает в этот диапазон код программы, её глобальные переменные, стек и кучу блоками, которые называются страницами (4 КБ на большинстве систем Linux на x86, 16 КБ на Mac с процессорами Apple). Большинство адресов остаются неотображёнными, и адрес 0 всегда среди них, чтобы ошибки с нулевыми указателями ловились.
- Программа выполняет инструкцию, которая читает или записывает адрес. Здесь это чтение
*score, адрес 0. - Блок управления памятью процессора ищет адрес в таблице страниц. Страница не отображена, или программа пытается записать в страницу, доступную только для чтения.
- Процессор останавливает инструкцию и передаёт управление ядру через страничное прерывание (page fault).
- Ядро проверяет, могло ли обращение быть допустимым, например если стеку нужно вырасти. Оно недопустимо, поэтому ядро отправляет процессу сигнал 11,
SIGSEGV. - Действие по умолчанию для
SIGSEGVэто завершить процесс и, если система разрешает, сохранить дамп памяти (core dump). Затем оболочка выводит сообщение и устанавливает код выхода 139, то есть 128 плюс номер сигнала.
Значит, об ошибке сегментации не сообщает компилятор, и это не исключение, которое выбрасывает язык. Это аппаратура и ядро защищают память, так что это ошибка времени выполнения самого резкого вида. Windows обрабатывает то же событие как нарушение доступа, код исключения 0xC0000005.
Частые причины ошибок сегментации
C и C++ позволяют программе вычислить любой адрес и использовать его, поэтому все причины сводятся к использованию недопустимого адреса.
- Разыменование нулевого указателя.
int *p = NULL; *p = 5;Сюда же приводит функция, которая при неудаче возвращаетNULL, напримерmallocилиfopen, если её результат не проверен. - Индекс далеко за концом массива. C не проверяет границы, поэтому
arr[1000000]это просто адрес на миллион элементов дальше. - Использование памяти после
free. Указатель всё ещё хранит старый адрес, но память тебе больше не принадлежит. - Неинициализированный указатель.
int *p; *p = 5;записывает по тому мусорному значению, которое случайно оказалось вp. - Переполнение стека. Рекурсивная функция без условия остановки добавляет кадры стека, пока не выйдет за его конец. Пример ниже упал на macOS с
Segmentation fault: 11и кодом выхода 139. - Запись в строковый литерал.
char *name = "coddy"; name[0] = 'C';пытается изменить память, доступную только для чтения. В Linux это segfault. На macOS та же программа остановилась сBus error: 10, родственным сигналом.
#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;
}
Небольшая ошибка часто вообще не приводит к падению, и от этого она опаснее. Этот цикл читает один элемент за концом массива из трёх элементов:
#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;
}
Скомпилированная Clang на Mac, программа вывела Total: 256. Правильная сумма 255. scores[3] оказались следующие 4 байта стека, которые принадлежали программе, поэтому ошибки не было, и мусорное значение тихо прибавилось. Операционная система останавливает только обращения к памяти, которая программе вообще не принадлежит.
Исправление обеих ошибок одно и то же: знай, сколько элементов есть, и проверяй указатель, прежде чем по нему переходить.
Best: 95
No scores, nothing to read
Что означает «core dumped»
Дамп памяти (core dump) это файл с копией памяти программы в момент падения. Отладчик может открыть его позже и показать, где именно находилась программа и что хранилось в её переменных: gdb ./app core. Во многих дистрибутивах Linux эти файлы собирает systemd-coredump, и coredumpctl list их показывает. Когда дампы памяти отключены, например через ulimit -c 0, сообщение будет просто Segmentation fault, без слов в скобках.
Как найти строку, на которой программа упала
Строка, на которой программа падает, часто не та, где находится баг. Указатель может стать недействительным в одной функции и использоваться в другой гораздо позже. Эти инструменты показывают и то и другое.
Отладчик. Скомпилируй с отладочной информацией и запусти программу в отладчике. Когда она остановится, bt (backtrace) выведет цепочку вызовов функций с именами файлов и номерами строк. В Linux отладчиком обычно служит gdb; на macOS это lldb, где bt работает так же.
gcc -g app.c -o app
gdb ./app
(gdb) run
(gdb) bt
AddressSanitizer. Скомпилируй с -fsanitize=address (его поддерживают и GCC, и Clang) и запусти программу как обычно. Вместо голого segfault он выведет отчёт, в котором назван вид ошибки, например heap-use-after-free или stack-buffer-overflow, со строкой, где произошло обращение, и строкой, где была выделена память. Он ловит и тихое чтение на один элемент за концом из примера выше, которое само по себе никогда не приводит к падению.
Valgrind. В Linux valgrind ./app запускает неизменённую программу и сообщает о каждом недопустимом чтении или записи, например Invalid read of size 4.
Ошибки сегментации в других языках
Python, Java и JavaScript проверяют каждый индекс и каждую ссылку перед использованием, поэтому те же ошибки превращаются в исключения с понятными сообщениями: IndexError или AttributeError в Python, ArrayIndexOutOfBoundsException или NullPointerException в Java, TypeError в JavaScript. Их можно перехватить с помощью обработки исключений. Segfault так обработать нельзя: это сигнал, и блок catch в C++ его не видит.
Программы на Python всё равно могут упасть с segfault, когда под ними ломается код на C. Эта строка просит ctypes прочитать адрес 0:
import ctypes
ctypes.string_at(0)
При запуске с python3 -X faulthandler Python 3.12 вывел Fatal Python error: Segmentation fault, а за этим строки Python, которые выполнялись. То же падение случается, когда в расширении на C или в нативной библиотеке есть ошибка работы с памятью. Rust идёт другим путём: его компилятор отвергает большую часть кода, который мог бы обратиться к недопустимой памяти, ещё до сборки программы.
Что читать дальше
Руководство по C об ошибках сегментации разбирает каждую причину на минимальной программе с исправлением. Чтобы не допускать этих ошибок с самого начала, прочитай про указатели, нулевые указатели и стек и кучу, а затем потренируйся в курсе C. О том, как сообщается об ошибках в языках, которые проверяют память за тебя, рассказано на странице про ошибку времени выполнения.
Часто задаваемые вопросы
Как исправить ошибку сегментации?
-g и запусти программу под gdb или lldb, а после падения набери bt, или скомпилируй с -fsanitize=address, чтобы получить подробный отчёт. Затем исправь указатель или индекс, который использует эта строка: проверяй указатели на NULL, держи индексы массивов меньше длины, не используй память после free и следи, чтобы рекурсия заканчивалась.Ошибка сегментации это утечка памяти?
free, например использование указателя после освобождения, могут вызвать segfault, а забытый free приводит к утечкам.Почему она называется ошибкой сегментации?
SIGSEGV, осталось. В Windows то же событие называется нарушением доступа (access violation).Может ли в Python возникнуть segmentation fault?
ctypes. Запуск python -X faulthandler script.py выводит строки Python, которые выполнялись в момент падения.Что означает код выхода 139?
SIGSEGV, ошибкой сегментации. Командные оболочки сообщают о смерти от сигнала как 128 плюс номер сигнала, а 128 + 11 = 139. В Docker и Kubernetes контейнер, завершившийся с кодом 139, получил segfault в своём основном процессе.