$ ./broken
Electric Fence 2.2.0 Copyright (C) 1987 - 1999 Bruce Perens.
1: 12345
Segmentation fault (core dumped)
Ошибка сегментации (дамп ядра сброшен)
Хотя Electric Fence непосредственно не указывает на место, где произошла ошибка, проблема становится намного очевидней. Можно легко и точно определить проблемный участок, запустив программу под управлением отладчика, например gdb
. Для того чтоб gdb
смог точно указать на проблему, соберите программу с отладочной информацией, указав для gcc
флажок -g
, затем запустите gdb
и зададите имя исполняемого файла, который нужно отладить. Когда программы уничтожается, gdb
точно показывает, в какой строке произошел сбой.
Вот как выглядит описанная процедура.
$ gcc -ggdb -Wall -о broken broken.с -lefence
$ gdb broken
...
(gdb) run
Starting program: /usr/src/lad/code/broken
Electric Fence 2.2.0 Copyright (C) 1987 - 1999 Bruce Perens.
1: 12345
Program received signal SIGSEGV, Segmentation fault.
Программа получила сигнал SIGSEGV, ошибка сегментации.
0х007948с6 in strcpy() from /lib/tls/libc.so.6
(gdb) where
#0 0x007948c6 in strcpy() from /lib/tls/libc.so.6
#1 0x08048566 in broken() at broken.c:21
#2 0x08048638 in main() at broken.c:47
(gdb)
Благодаря Electric Fence и gdb
, становится понятно, что в строке 21 файла broken.с
имеется ошибка, связанная со вторым вызовом strcpy()
.
7.5.2. Выравнивание памяти
Хотя инструмент Electric Fence очень помог в обнаружении второй проблемы в коде, а именно — вызова strcpy()
, переполнившего буфер, первое переполнение буфера найдено не было.
Проблему в этом случае нужно решать с помощью выравнивания памяти. Большинство современных компьютеров требуют, чтобы многобайтные объекты начинались с определенных смещений в оперативной памяти. Например, процессоры Alpha требуют, чтобы 8-байтовый тип — длинное целое ( long
) — начинался с адреса, кратного 8. Это значит, что длинное целое может располагаться по адресу 0x1000 или 0x1008, но не 0x1005 [11] Большинство традиционных систем Unix передают ошибку шины ( SIGBUS ) процессу, который пытается использовать невыровненные данные. Ядро Linux обрабатывает доступ к невыровненным данным так, чтобы процесс мог нормально продолжать работу, хотя за это приходится платить существенным снижением производительности.
.
На основе этих соглашений реализации malloc()
обычно возвращают память, первый байт которой выровнен в соответствии с размером слова процессора (4 байта для 32-разрядных и 8 байтов на 64-разрядных процессоров). По умолчанию Electric Fence пытается эмулировать такое поведение, предлагая функцию malloc()
, возвращающую только адреса, кратные sizeof(int)
.
В большинстве программ подобное выравнивание не критично, то есть распределение памяти происходит инкрементным образом на основе размера машинного слова либо в виде простых символьных строк, для которых требования по выравниванию не предусмотрены (поскольку каждый элемент занимает всего 1 байт).
В случае с нашей тестовой программой первый вызов malloc()
распределил пять байт.
Для того чтобы Electric Fence удовлетворял своим ограничениям по выравниванию, он трактует этот вызов как запрос восьми байт, с дополнительными тремя доступными байтами. В этом случае небольшие переполнения буфера, распространяющиеся на эту область, не перехватываются.
В связи с тем, что выравнивание malloc()
обычно можно игнорировать, а выравнивание может способствовать незаметному переполнению буфера, Electric Fence предоставляет возможность управление выравниванием через переменную окружения ЕF_ALIGNMENT
. Если эта переменная установлена, все результаты malloc()
выравниваются в соответствии с ее значением. Например, если переменная установлена в значение 5, все результаты malloc()
будут рассматриваться как кратные 5 (тем не менее, это значение не особенно полезно). Для отключения выравнивания памяти перед запуском программы установите ЕF_ALIGNMENT
в 1
. В среде Linux некорректно выровненный доступ в любом случае исправляются в ядре, несмотря на то, что в результате скорость выполнения программы может существенно снизиться. Программа будет функционировать корректно, если только в ней не присутствуют небольшие переполнения буфера.
Ниже приведен пример поведения тестовой программы, скомпонованной с Electric Fence, после установки ЕF_ALIGNMENT
в 1
.
$ export EF_ALIGNMENT=1
$ gdb broken
...
(gdb) run
Читать дальше