Linux программирование в примерах - Арнольд Роббинс
Шрифт:
Интервал:
Закладка:
$ cc -g ch15-badmem1.c -о ch15-badmem1 /* Компилировать как обычно */
$ ef ch15-badmem1 -b /* Запустить с использованием ef, создает дамп ядра */
Electric Fence 2.2.0 Copyright (С) 1987-1999 Bruce Perens <[email protected]>
p = <not 30 bytes>
/usr/bin/ef: line 20: 28005 Segmentation fault (core dumped)
( export LD_PRELOAD=libefence.so.0.0; exec $* )
$ ef ch15-badmem1 -f /* Запустить с использованием ef, снова создает дамп ядра */
Electric Fence 2.2.0 Copyright (С) 1987-1999 Bruce Perens <[email protected]>
p = <not 30 bytes>
/usr/bin/ef: line 20: 28007 Segmentation fault (core dumped)
( export LD_PRELOAD=libefence.so.0.0; exec $* )
$ ls -l core* /* Linux создает для нас разные файлы core */
-rw------- 1 arnold devel 217088 Aug 28 15:40 core.28005
-rw------- 1 arnold devel 212992 Aug 28 15:40 core.28007
GNU/Linux создает файлы core, которые включают в свое имя ID процесса. В данном случае такое поведение полезно, поскольку мы можем отдельно отлаживать каждый файл core:
$ gdb ch15-badmem1 core.28005 /* От опции -b */
GNU gdb 5.3
...
Core was generated by 'ch15-badmem1 -b'.
Program terminated with signal 11, Segmentation fault.
...
#0 0x08048466 in main (argc=2, argv=0xbffff8c4) at ch15-badmem1.c:18
18 p[42] = 'a'; /* touch outside the bounds */
(gdb) quit
$ gdb ch15-badmem1 core.28007 /* От опции -f */
GNU gdb 5.3
...
Core was generated by 'ch15-badmem1 -f'.
Program terminated with signal 11, Segmentation fault.
...
#0 0x08048498 in main (argc=2, argv=0xbffff8c4) at ch15-badmem1.с:21
21 p[0] = 'b';
Справочная страница efence(3) описывает несколько переменных окружения, которые должны быть установлены, чтобы настроить поведение Electric Fence. Следующие три наиболее примечательны.
EF_PROTECT_BELOW
Установка этой переменной в 1 заставляет Electric Fence проверять «недоборы» (underruns) вместо «переборов» (overruns) при выходе за пределы отведенной памяти. «Перебор», т.е. доступ к памяти в области за выделенной, был продемонстрирован ранее. «Недобор» является доступом к памяти, расположенной перед выделенной областью памяти.
EF_PROTECT_FREE
Установка этой переменной в 1 предотвращает повторное использование Electric Fence памяти, которая была корректно освобождена. Это полезно, когда вы думаете, что программа может получать доступ к освобожденной памяти; если освобожденная память впоследствии была выделена заново, доступ к ней через предыдущий висячий указатель остался бы в противном случае незамеченным.
EF_ALLOW_MALLOC_0
При наличии ненулевого значения Electric Fence допускает вызовы 'malloc(0)'. Такие вызовы в стандартном С технически действительны, но могут представлять программную ошибку. Соответственно Electric Fence по умолчанию их запрещает.
Вдобавок к переменным окружения Electric Fence предоставляет глобальные переменные с такими же названиями. Вы можете изменить их значения из отладчика, так что можно динамически изменять поведение программы, которая уже начала выполнение. Подробности см. в efence(3).
15.5.2.3. Отладка Malloc: dmalloc
Библиотека dmalloc предоставляет большое число опций отладки. Ее автором является Грей Ватсон (Gray Watson), есть также и свой веб-сайт.[180] Как и в случае с Electric Fence, она может быть уже установленной на вашей системе, или же вы можете ее извлечь и построить самостоятельно.
Библиотека dmalloc проверяет наличие в переменной окружения DMALLOC_OPTIONS управляющей информации. Например, она может выглядеть следующим образом:
$ echo $DMALLOC_OPTIONS
debug=0x4e40503,inter=100,log=dm-log
Компонент 'debug' этой переменной содержит набор битовых флагов, которыми для большинства людей почти невозможно непосредственно управлять. Поэтому документация описывает двухэтапный процесс для облегчения их использования.
Первый шаг заключается в определении функции оболочки с названием dmalloc, которая вызывает программу драйвера dmalloc:
$ dmalloc() {
> eval 'command dmalloc -b $*' /* Команда 'command' обходит функции оболочки */
> }
После того, как это сделано, вы можете передать функции опции для установки файла журнала (-1), указать число итераций, после которых dmalloc должна проверить свои внутренние структуры данных (-1), и указать уровень отладки или другой тэг ('low').
$ dmalloc -1 dm-log -i 100 low
Как и Electric Fence, библиотека dmalloc может быть скомпонована с приложением статически или связана динамически при помощи LD_PRELOAD. Последнее демонстрирует следующий пример:
$ LD_PRELOAD=libdmalloc.so ch15-badmem1 -b /* Запустить с проверкой */
p = <not 30 bytes> /* Показан нормальный вывод */
ЗАМЕЧАНИЕ. Не используйте 'export LD_PRELOAD=libdmalloc.so'! Если вы это сделаете, каждая программа, которую вы запустите, такая как ls, будет выполняться со включенной проверкой malloc(). Ваша система быстро станет непригодной. Если вы сделали это случайно, можете использовать 'unset LD_PRELOAD', чтобы восстановить обычное поведение.
Результаты записываются в файл dm-log следующим образом:
$ cat dm-log
1062078174: 1: Dmalloc version '4.8.1' from 'http://dmalloc.com/'
1062078174: 1: flags = 0x4e40503, logfile 'dm-log'
1062078174: 1: interval = 100, addr = 0, seen # = 0
1062078174: 1: starting time = 1062078174
1062078174: 1: free bucket count/bits: 63/6
1062078174: 1: basic-block 4096 bytes, alignment 8 bytes, heap grows up
1062078174: 1: heap: 0x804a000 to 0x804d000, size 12288 bytes (3 blocks)
1062078174: 1: heap checked 0
1062078174: 1: alloc calls: malloc 1, calloc 0, realloc 0, free 0
1062078174: 1: alloc calls: recalloc 0, memalign 0, valloc 0
1062078174: 1: total memory allocated: 30 bytes (1 pnts)
1062078174: 1: max in use at one time: 30 bytes (1 pnts)
1062078174: 1: max alloced with 1 call: 30 bytes
1062078174: 1: max alloc rounding loss: 34 bytes (53%)
1062078174: 1: max memory space wasted: 3998 bytes (98%)
1062078174: 1: final user memory space: basic 0, divided 1, 4062 bytes
1062078174: 1: final admin overhead: basic 1, divided 1, 8192 bytes (66%)
1062078174: 1: final external space: 0 bytes (0 blocks)
1062078174: 1: top 10 allocations:
1062078174: 1: total-size count in-use-size count source
1062078174: 1: 30 1 30 1 ra=0x8048412
1062078174: 1: 30 1 30 1 Total of 1
1062078174: 1: dumping not-freed pointers changed since 0:
1062078174: 1: not freed: '0x804c008|s1' (30 bytes) from 'ra=0x8048412'
1062078174: 1: total-size count source
1062078174: 1: 30 1 ra=0x8048412 /* Выделение здесь */
1062078174: 1: 30 1 Total of 1
1062078174: 1: unknown memory: 1 pointer, 30 bytes
1062078174: 1: ending time = 1062078174, elapsed since start = 0:00:00
Вывод содержит много статистических данных, которые нам пока не интересны. Интересна строка, в которой указывается не освобожденная память, с адресом возврата, указывающим на выделившую память функцию ('ra=0х8048412'). Документация dmalloc объясняет, как получить расположение в исходном коде этого адреса с использованием GDB.
$ gdb ch15-badmem1 /* Запустить GDB */
GNU gdb 5.3
...
(gdb) x 0x8048412 /* Проверить адрес */
0x8048412 <main+26>: 0х8910с483
(gdb) info line *(0x8048412) /* Получить сведения о строке */
Line 11 of "ch15-badmem1.с" starts at address 0x8048408 <main+16>
and ends at 0x8048418 <main+32>.
Это трудно, но выполнимо, если нет другого выбора. Однако, если вы включите в свою программу заголовочный файл "dmalloc.h" (после всех остальных операторов #include), вы можете получить сведения из исходного кода непосредственно в отчете.
...
1062080258: 1: top 10 allocations:
1062080258: 1: total-size count in-use-size count source
1062080258: 1: 30 1 30 1 ch15-badmem2.c:13
1062080258: 1: 30 1 30 1 Total of 1
1062080258: 1: dumping not-freed pointers changed since 0:
1062080258: 1: not freed: '0x804c008|s1' (30 bytes) from 'ch15-badmem2.c:13'
1062080258: 1: total-size count source
1062080258: 1: 30 1 ch15-badmem2.с:13
1062080258: 1: 30 1 Total of 1
...
(Файл ch15-badmem2.c является аналогичным ch15-badmem1.с, за исключением того, что он включает "dmalloc.h", поэтому мы не стали беспокоиться с его отображением).
Отдельные возможности отладки включаются или выключаются посредством использования лексем (tokens) — специально распознаваемых идентификаторов — и опций -р для добавления лексем (свойств) или -m для их удаления. Имеются предопределенные комбинации, 'low', 'med' и 'high'. Чем являются эти комбинации, вы можете увидеть с помощью 'dmalloc -Lv'.
$ dmalloc low /* Установить low */
$ dmalloc -Lv /* Показать установки */
Debug Malloc Utility: http://dmalloc.com/