Разработка приложений в среде Linux. Второе издание
Шрифт:
Компоновка нашей тестовой программы с
mcheck
дает следующие результаты: $ gcc -ggdb -о broken broken.с -lmcheck
$ ./broken
1: 12345
memory clobbered past end of allocated block
память разрушена после конца распределенного блока
Вследствие того, что
mcheck
всего лишь выдает сообщения об ошибках и завершает работу, найти ошибку невозможно. Для точного обнаружения ошибки потребуется запустить программу внутри gdb
и заставить mcheck
вызывать abort
при обнаружении ошибки. Можно просто вызвать mcheck
gdb
или поместить mcheck(1)
в первой строке вашей программы (веред вызовом malloc
). (Следует отметить, что mcheck
можно вызвать в gdb
без необходимости компоновки программы с библиотекой mcheck
.) $ rm -f broken; make broken
$ gdb broken
...
(gdb) break main
Breakpoint 1 at 0x80483f4: file broken.c, line 14.
Точка прерывания 1 по адресу 0x80483f4: файл broken, с, строка 14.
(gdb) command 1
Type commands for when Breakpoint 1 is hit, one per line.
End with a line saying just "end".
Наберите команды, которые выполнятся при достижении точки прерывания 1, по одной в строке.
Завершите строкой, содержащей только "end".
> call mcheck(&abort)
> continue
> end (gdb) run
Starting program: /usr/src/lad/code/broken
Запуск программы: /usr/src/lad/code/broken
Breakpoint 1, main at broken.с: 14
47 return broken;
$1 = 0
1: 12345
Program received signal SIGABRT, Aborted.
Программа получила сигнал SIGABRT, прервана.
0x00e12c32 in _dl_sysinfo_int80 from /lib/ld-linux.so.2
(gdb) where
#00x00el2c32 in _dl_sysinfo_int80 from /lib/ld-linux.so.2
#1 0x0072c969 in raise from /lib/tls/libc.so.6
#2 0x0072e322 in abort from /lib/tls/libc.so.6
#3 0x007792c4 in freehook from /lib/tls/libc.so.6
#4 0x00774fa5 in free from /lib/tls/libc.so.6
#5 0x0804842b in broken at broken.c:17
#6 0x08048520 in main at broken.с:47
Важной частью этого кода является обнаруженная ошибка в строке 17 файла
broken.с
. Видно, что ошибка была обнаружена во время первого вызова free, который указал на наличие проблемы в области памяти dyn
. (freehook
представляет собой ловушку, с помощью которой mcheck
выполняет проверки.) Библиотека
mcheck
не может помочь в обнаружении переполнения или недогрузки буфера в локальных или глобальных переменных, а только в областях памяти, распределенных с помощью malloc
. 7.2.2. Использование
mtrace
для отслеживания распределений памяти Один из простых способов нахождения всех утечек памяти в программе предусматривает регистрацию всех вызовов
malloc
и free
. По окончании программы очень легко сопоставить блоки, распределенные через malloc
, с точками, где они были освобождены с помощью free
или сообщить об ошибке, если для какого-то блока free
не вызывалась. В отличие от
mcheck
, в mtrace
нет соответствующей библиотеки для компоновки. Это не проблема, поскольку трассировку можно осуществлять в gdb
. Однако для включения трассировки с помощью mtrace
должна быть установлена переменная окружения MALLOC_TRACE
в допустимое имя файла; это может быть либо имя существующего файла, в который процесс может вести запись, либо имя нового файла, который процесс создаст и будет в него записывать. $ MALLOC_TRACE=mtrace.log gdb broken
...
(gdb) breakmain
Breakpoint 1 at 0x80483f4: filebroken.c, line 14.
(gdb) command 1
Type commands for when Breakpoint 1 is hit, one per line.
End with a line saying just "end".
>call mtrace
>continue
>end
(gdb) run
Starting program: /usr/src/lad/code/broken
Breakpoint 1, main at broken.с:47
47 return broken;
$1 = 0
1: 12345
2: 12345678
3: 12345678
4: 12345
5: 12345
6: 12345
7: 12345
Program exited normally.
Программа завершена нормально.
(gdb) quit
$ ls -l mtrace.log
– rw-rw-r-- 1 ewt ewt 220 Dec 27 23:41 mtrace.log
$ mtrace ./broken mtrace.log
Memory not freed:
He освобождена память:
– ---------------------
Address Size Caller
Адрес Размер Место вызова
0x09211378 0x5 at /usr/src/lad/code/broken.с:20
Обратите внимание, что программа
mtrace
точно обнаружила утечку памяти. Также она может найти факт освобождения с помощью free
памяти, которая ранее не распределялась, если этот факт будет зафиксирован в журнальном файле, но на практике так не происходит, поскольку в этом случае программа немедленно аварийно завершается. 7.3. Поиск утечек памяти с помощью
mpr
Возможности
mtrace
в glibc
достаточно неплохие, но профилировщик распределения памяти mpr
в некоторых аспектах более прост в использовании и содержит более совершенные сценарии для обработки выходных журнальных файлов. Первый шаг в применении
mpr
(после сборки кода с включенной отладочной информацией [10] ) состоит в установке переменной окружения MPRFI
, которая указывает mpr
, с какой командой связывать журнал (если переменная не установлена, журнал не генерируется). Для небольших программ MPRFI
устанавливается подобно cat >mpr.log
. Для программ покрупнее MPRFI
можно существенно сэкономить пространство за счет сжатия журнального файла во время его записи, установив MPRFI
в gzip -1 >mpr.log.gz
.10
Для большей переносимости многие из средств
mpr
анализа журнала используют gdb
для связывания адреса с соответствующим местом в исходном коде. Чтобы это работало, программа должна содержать отладочную информацию. Поделиться с друзьями: