Что означает ошибка Stack overflow / SIGSEGV (11)
В Linux эта проблема проявляется как сигнал SIGSEGV с сообщением Segmentation fault (core dumped) или Stack smashing detected. Ошибка возникает, когда процесс исчерпывает выделенную ему область памяти стека. По умолчанию в большинстве дистрибутивов лимит жёстко зафиксирован на уровне 8 МБ. Если программа пытается записать данные за пределы этого участка, ядро Linux аварийно завершает процесс, чтобы предотвратить повреждение соседних областей памяти или сбой всей системы.
Причины возникновения
- Бесконечная или слишком глубокая рекурсия. Функция вызывает саму себя без корректного условия выхода, быстро заполняя стек кадрами вызовов.
- Объявление крупных локальных массивов. Попытка создать массив размером в несколько мегабайт внутри функции (например,
double matrix[1000][1000]) мгновенно резервирует место в стеке и вызывает сбой. - Некорректная настройка потоков. При создании потоков через
pthread_createможно вручную задать слишком маленький размер стека, который не подходит для вашей бизнес-логики. - Переполнение буфера. Запись данных за границы выделенной переменной активирует защиту компилятора (stack canary) и принудительно останавливает выполнение приложения.
Способы решения
Способ 1: Временное увеличение лимита через ulimit
Если вам нужно срочно запустить программу для тестирования или обработки данных, проще всего снять ограничение только для текущей сессии терминала.
- Проверьте текущий лимит в килобайтах:
ulimit -s
- Увеличьте лимит до 16 МБ или снимите его полностью:
ulimit -s 16384
# или полностью снять ограничение для сессии
ulimit -s unlimited
- Запустите вашу программу в том же окне терминала. Изменения действуют до закрытия сессии и не влияют на другие запущенные сервисы.
💡 Совет: Значение
unlimitedснимает жёсткое ограничение оболочки, но процесс всё равно ограничен физической оперативной памятью и параметромvm.max_map_countядра.
Способ 2: Постоянное изменение лимита через PAM
Чтобы изменения сохранялись после перезагрузки и применялись автоматически при входе, отредактируйте глобальную конфигурацию лимитов.
- Откройте файл конфигурации с правами суперпользователя:
sudo nano /etc/security/limits.conf
- Добавьте в конец файла строки (замените
usernameна ваше имя или используйте*для всех пользователей):
username soft stack 32768
username hard stack 32768
- Сохраните файл, полностью выйдите из системы и войдите снова. Проверьте применение изменений командой
ulimit -s.
Способ 3: Поиск и исправление проблемного кода с GDB
Увеличение стека — лишь временная мера. Если ошибка вызвана архитектурными недочётами программы, её необходимо найти и исправить на уровне исходного кода.
- Скомпилируйте проект с отладочными символами:
gcc -g -O0 -o my_app main.c
- Запустите отладчик и выполните программу:
gdb ./my_app
(gdb) run
- При падении введите
bt(backtrace) для просмотра полного стека вызовов:
(gdb) bt
- Найдите повторяющуюся функцию или укажите на строку в вашем коде. Измените логику: замените рекурсию на итеративный цикл, а крупные локальные массивы перенесите в кучу через
malloc()илиstd::vector. Скомпилируйте заново и протестируйте.
Профилактика
Регулярная проверка кода на предмет утечек и аномалий экономит часы отладки. Всегда компилируйте проекты с включёнными флагами безопасности: -fstack-protector-strong и -Wall -Wextra. Для многопоточных приложений явно задавайте размер стека через pthread_attr_setstacksize(), а не полагайтесь на системный дефолт. Если работаете с большими структурами данных, размещайте их в динамической памяти (куче) или используйте static для глобального доступа. Настройте статический анализ в CI/CD пайплайне с помощью инструментов вроде Valgrind или AddressSanitizer, чтобы отлавливать переполнения до выкатки в продакшен.