Отладка stack smashing с помощью valgrind

Материал из База знаний Etersoft
Перейти к навигацииПерейти к поиску

При запуске программы в консоль выводится ошибка:

*** stack smashing detected ***

Причин может быть несколько. Одна из них — переполнение буфера, в результате чего переписывается адрес возврата из функции.
Воспроизвести проблему можно, например, с помощью следующей программы:

  #include <string.h>
void foo (char *bar) { char c[12]; memcpy(c, bar, strlen(bar)); }
int main (int argc, char **argv) { foo(argv[1]); }


Если в качестве аргумента передать программе строку длиной более чем 11 символов, получим сообщение о битом стеке.

Чтобы отладить такую ошибку с помощью valgrind, необходимо собрать программу с отладочной информацией (использовать параметр -g):

gcc -g sample.c -o sample

Запускаем valgrind с параметром -v (режим подробного вывода):

valgrind -v ./sample 111111111111111111111111111222222222222222222222222222222

В полученном трейсе есть примерно такие строчки:

*** stack smashing detected ***: ./sample terminated
--8300-- REDIR: 0x9e3310 (malloc) redirected to 0x4008070 (malloc)
--8300-- REDIR: 0x9e2b80 (calloc) redirected to 0x4005f90 (calloc)
--8300-- Reading syms from /lib/libgcc_s.so.1 (0xc85000)
--8300-- object doesn't have a symbol table
==8300== Invalid read of size 2
==8300== at 0xC9BC46: (within /lib/libgcc_s.so.1)
==8300== by 0xC9C2B0: _Unwind_Backtrace (in /lib/libgcc_s.so.1)
==8300== by 0xA50384: backtrace (in /lib/libc-2.10.1.so)
==8300== by 0x9D96CA: (within /lib/libc-2.10.1.so)
==8300== by 0xA535EF: __fortify_fail (in /lib/libc-2.10.1.so)
==8300== by 0xA535AF: __stack_chk_fail (in /lib/libc-2.10.1.so)
==8300== by 0x80484AC: foo (sample.c:8)
==8300== by 0x32323231: ???
==8300== Address 0x32323232 is not stack'd, malloc'd or (recently) free'd

Здесь приводится точное место, где произошла ошибка:

==8300== by 0x80484AC: foo (sample.c:8)

Т.е. функция foo, строчка 8 файла sample.c.
Следующая строка:

==8300== by 0x32323231: ???

Говорит о том, что 0x32323231 — значение, которое оказалось записанным в адрес возврата в результате переполнения буфера.

Таким образом полученной информации может оказаться достаточно, для определения причины ошибки.

Ссылки