Книга: Основы программирования в Linux
valgrind
valgrind
Средство valgrind
способно обнаруживать многие из обсуждавшихся нами проблем (упражнение 10.4). Прежде всего, оно умеет находить ошибки доступа, к массиву и утечки памяти. Это средство, возможно, не включено в ваш дистрибутив Linux, но его можно найти на Web-сайте http://valgrind.org.
Для применения valgrind
даже не требуется перекомпиляции программы, и вы можете находить ошибки доступа к памяти в выполняющейся программе. Данное средство заслуживает внимания; оно применяется в основных разработках, включая среду KDE версии 3.
Упражнение 10.4. Средство valgrind
Далее приведена программа checker.c, которая выделяет некоторый объем памяти, читает область памяти и записывает данные за пределами выделенного участка, а затем делает выделенный участок недоступным.
#include <stdio.h>
#include <stdlib.h>
int main() {
char *ptr = (char *)malloc(1024);
char ch;
/* Неинициализированное чтение */
ch = ptr[1024];
/* Запись за пределами блока */
ptr[1024] = 0;
/* Потеря блока */
ptr = 0;
exit(0);
}
Для применения valgrind
вы просто выполняете команду valgrind
, передав ей опции, задающие нужные виды проверок, и далее указав программу для выполнения с ее аргументами (если таковые есть).
При выполнении программы с valgrind
вы увидите множество обнаруженных проблем:
$ valgrind --leak-check=yes -v ./checker
==4780== Memcheck, a memory error detector.
==4780== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==4780== Using LibVEX rev 1732, a library for dynamic binary translation.
==4780== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==4780== Using valgrind-3.2.3, a dynamic binary instrumentation framework.
==4780== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==4780==
--4780-- Command line
--4780-- ./checker
--4780-- Startup, with flags:
--4780-- --leak-check=yes
--4780-- -v
--4780-- Contents of /рroc/version:
--4780-- Linux version 2-6.20.2-2-default (geeko@buildhost) (gcc version 4.1.3 20070218 (prerelease) (SUSE Linux)) #1 SMP Fri Mar 9 21:54:10 UTC 2007
--4780-- Arch and hwcaps: X86, x86-sse1-sse2
--4780-- Page sizes: currently 4096, max supported 4096
--4780-- Valgrind library directory: /usr/lib/valgrind
--4780-- Reading syms from /lib/ld-2.5.so (0x4000000)
--4780-- Reading syms from /home/neil/BLP4e/chapter10/checker (0x8048000)
--4780-- Reading syms from /usr/lib/valgrind/x86-linux/memcheck (0x38000000)
--4780-- object doesn't have a symbol table
--4780-- object doesn't have a dynamic symbol table
--4780-- Reading suppressions file: /usr/lib/valgrind/default.supp
--4780-- REDIR: 0x40158B0 (index) redirected to 0x38027EDB (???)
--4780-- Reading syms from /usr/lib/valgrind/x86-linux/vgpreload_core.so (0x401E000)
--4780-- object doesn't have a symbol table
--4780-- Reading syms from /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so (0x4021000)
--4780-- object doesn't have a symbol table
==4780= WARNING: new redirection conflicts with existing -- ignoring it
--4780-- new: 0x040158B0 (index ) R-> 0x04024490 index
--4780-- REDIR: 0x4015A50 (strlen) redirected to 0x4024540 (strlen)
--4780-- Reading syms from /lib/libc-2.5.so (0x4043000)
--4780-- REDIR: 0x40ADFF0 (rindex) redirected to 0x4024370 (rindex)
--4780-- REDIR: 0x40AAF00 (malloc) redirected to 0x4023700 (malloc)
==4780== Invalid read of size 1
==4780== at 0x804842C: main (checker.с: 10)
==4780== Address 0x4170428 is 0 bytes after a block of size 1,024 alloc'd
==4780== at 0x4023785: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==4780== by 0x8048420: main (checker.c: 6)
=4780=
==4780== Invalid write of size 1
==4780== at 0x804843A: main (checker.с: 13)
==4780== Address 0x4170428 is 0 bytes after a block of size 1,024 alloc'd
==4780== at 0x4 023785: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==4780== by 0x8048420: main (checker.c: 6)
--4780-- REDIR: 0x40A8BB0 (free) redirected to 0x402331A (free)
--4780-- REDIR: 0x40AEE70 (memset) redirected to 0x40248A0 (memset)
==4780==
==4780== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 3 from 1)
==4780==
==4780== 1 errors in context 1 of 2:
==4780== Invalid write of size 1
==4780== at 0x804843A: main (checker.с: 13)
==4780== Address 0x4170428 is 0 bytes after a block of size 1,024 alloc'd
==4780== at 0x4023785: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==4780== by 0x80484 20: main (checker.c: 6)
==4780==
==4780== 1 errors in context 2 of 2:
==4780== Invalid read of size 1
==4780== at 0x804842C: main (checker.c:10)
==4780== Address 0x4170428 is 0-bytes after a block of size 1,024 alloc'd
==4780== at 0x4023785: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==4780== by 0x8048420: main (checker.с: 6)
--4780--
--4780-- supp: 3 dl-hack3
==4780==
==4780== IN SUMMARY: 2 errors from 2 contexts (suppressed: 3 from 1)
==4780==
==4780== malloc/free: in use at exit: 1,024 bytes in 1 blocks.
==4780== malloc/free: 1 allocs, 0 frees, 1,024 bytes allocated.
==4780==
==4780== searching for pointers to 1 not-freed blocks.
==4780== checked 65,444 bytes.
==4780==
==4780==
==4780== 1,024 bytes in 1 blocks are definitely lost in loss record 1 of 1
==4780== at 0x4023785: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==4780== by 0x8048420: main (checker.c: 6)
==4780==
==4780== LEAK SUMMARY:
==4780== definitely lost: 1,024 bytes in 1 blocks.
==4780== possibly lost: 0 bytes in 0 blocks.
==4780== still reachable: 0 bytes in 0 blocks.
==4780== suppressed: 0 bytes in 0 blocks.
--4780-- memcheck: sanity checks: 0 cheap, 1 expensive
--4780-- memcheck: auxmaps: 0 auxmap entries (0k, 0M) in use
--4780-- memcheck: auxmaps: 0 searches, 0 comparisons
--4780-- memcheck: SMs: n_issued = 9 (144k, 0M)
--4780-- memcheck: SMs: n_deissued = 0 (0k, 0M)
--4780-- memcheck: SMs: max_noaccess = 65535 (1048560k, 1023M)
--4780-- memcheck: SMs: max_undefined = 0 (0k, 0M)
--4780-- memcheck: SMs: max_defined = 19 (304k, 0M)
--4780-- memcheck: SMs: max_non_DSМ = 9 (144k, 0M)
--4780-- memcheck: max sec V bit nodes: 0 (0k, 0M)
--4780-- memcheck: set_sec_vbits8 calls: 0 (new: 0, updates: 0)
--4780-- memcheck: max shadow mem size: 448k, 0M
--4780-- translate: fast SP updates identified: 1,456 ( 90.3%)
--4780-- translate: generic_known SP updates identified: 79 ( 4.9%)
--4780-- translate: generic_unknown SP updates identified: 76 ( 4.7%)
--4780-- tt/tc: 3,341 tt lookups requiring 3,360 probes
--4780-- tt/tc: 3,341 fast-cache updates, 3 flushes
--4780-- transtab: new 1,553 (33,037 -> 538,097; ratio 162:10) [0 scs]
--4780-- transtab: dumped 0 (0 -> ??)
--4780-- transtab: discarded 6 (143 -> ??)
--4780-- scheduler: 21,623 jumps (bb entries).
--4780-- scheduler: 0/1,828 major/minor sched events.
--4780-- sanity: 1 cheap, 1 expensive checks.
--4780-- exectx: 30,011 lists, 6 contexts (avq 0 per list)
--4780-- exectx: 6 searches, 0 full compares (0 per 1000)
--4780-- exectx: 0 cmp2, 4 cmp4, 0 cmpAll $
Вы видите, что обнаружены некорректные считывания и записи, и интересующие нас блоки памяти приводятся с указанием места, которое для них отведено. Для прерывания выполнения программы в ошибочном месте можно применить отладчик.
У программы valgrind
есть много опций, включая подавление ошибок определенного типа и обнаружение утечки памяти. Для выявления такой утечки в примере вы должны использовать одну из опций, передаваемых valgrind
. Для контроля утечек памяти после завершения программы следует задать опцию --leak-check=yes
. Список опций можно получить с помощью команды valgrind --help
.
Как это работает
Программа выполняется под контролем средства valgrind, которое перехватывает действия, совершаемые программой, и выполняет множество проверок, включая обращения к памяти. Если обращение относится к выделенному блоку памяти и некорректно, valgrind выводит сообщение. В конце программы выполняется подпрограмма "сбора мусора", которая определяет, есть ли выделенные и неосвобожденные блоки памяти. Об этих потерянных блоках выводится сообщение.