Как определить точку переполнения стека
-
09-09-2019 - |
Вопрос
У меня следующая проблема с моей программой на языке Си:Где-то происходит переполнение стека.Несмотря на компиляцию без оптимизации и с символами отладчика, программа завершается с этим выводом (внутри или вне gdb в Linux).:
Программа завершилась сигналом SIGSEGV, ошибка сегментации.Программа больше не существует.
Единственный способ, которым я мог обнаружить, что это на самом деле переполнение стека, - запустить программу через valgrind.Есть ли какой-нибудь способ, которым я могу каким-то образом заставить операционную систему сбросить трассировку стека вызовов, что помогло бы мне обнаружить проблему?
К сожалению, gdb также не позволяет мне легко подключаться к программе.
Решение
Если вы разрешите системе выгружать файлы ядра, вы можете проанализировать их с помощью GDB:
$ ulimit -c unlimited # bash sentence to allow for infinite sized cores
$ ./stack_overflow
Segmentation fault (core dumped)
$ gdb -c core stack_overflow
gdb> bt
#0 0x0000000000400570 in f ()
#1 0x0000000000400570 in f ()
#2 0x0000000000400570 in f ()
...
Несколько раз я видел плохо сгенерированный основной файл с неправильной трассировкой стека, но в большинстве случаев bt выдает кучу рекурсивных вызовов одного и того же метода.
Файл ядра может иметь другое имя, которое может включать идентификатор процесса. Это зависит от конфигурации ядра по умолчанию в вашей текущей системе, но им можно управлять с помощью (запускать от имени пользователя root или с помощью sudo):
$ sysctl kernel.core_uses_pid=1
Другие советы
С GCC вы можете попробовать это:
-fstack-protector
Выполните дополнительный код для проверки переполнения буфера, например атак на разрушение стека.Это делается путем добавления защитной переменной к функциям с уязвимыми объектами.Сюда входят функции, вызывающие alloca, и функции с буферами размером более 8 байт.Охранники инициализируются при входе в функцию, а затем проверяются при выходе из функции.Если проверка защиты не удалась, выводится сообщение об ошибке и программа завершается.
-fstack-protector-all
Аналогично -fstack-protector, за исключением того, что все функции защищены.
http://gcc.gnu.org/onlinedocs/gcc-4.3.3/gcc/Optimize-Options.html#Optimize-Options
Когда программа умирает с помощью SIGSEGV, она обычно сбрасывает ядро в Unix.Не могли бы вы загрузить это ядро в отладчик и проверить состояние стека?