KnigaRead.com/

Нейл Мэтью - Основы программирования в Linux

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Нейл Мэтью, "Основы программирования в Linux" бесплатно, без регистрации.
Перейти на страницу:

Обычно блоки памяти выделяются функцией malloc и присваиваются переменным-указателям. Если переменная-указатель изменяется, и нет других указателей, указывающих на блок памяти, он становится недоступным. Это утечка памяти, вызывающая увеличение размера программы. Если вы потеряете большой объем памяти, скорость работы вашей системы, в конце концов, снизится, и система уйдет за пределы памяти.

Если вы записываете в область, расположенную после конца выделенного блока (или перед началом блока), вы с большой долей вероятности повредите структуры данных, используемые библиотекой malloc, следящей за распределением памяти. В этом случае в какой-то момент времени вызов malloc или даже free приведет к нарушению сегментации, и ваша программа завершится аварийно. Определение точного места возникновения сбоя может оказаться очень трудной задачей, поскольку нарушение могло возникнуть задолго до события, вызвавшего аварийное завершение программы.

Неудивительно, что существуют коммерческие и бесплатные средства, способные помочь в решении проблем этих двух типов. Например, есть много разных версий функций malloc и free, которые содержат дополнительный код для проверки выделения и освобождения блоков памяти и пытаются учесть двойное освобождение блока и другие типы неправильного использования памяти.

ElectricFence

Библиотека ElectricFence была разработана Брюсом Перенсом (Bruce Perens). Она доступна как необязательный компонент в некоторых дистрибутивах Linux, таких как Red Hat (Enterprise и Fedora), SUSE и openSUSE, и может быть легко найдена в Интернете. Это средство пытается применять виртуальную память системы Linux для защиты памяти, используемой функциями malloc и free, и аварийного останова программы в момент повреждения памяти.

Выполните упражнение 10.3.

Упражнение 10.3. Применение библиотеки ElectricFence

Далее приведена программа efence.c, которая выделяет память с помощью функции malloc и пишет данные за концом выделенного блока. Познакомьтесь с ней и посмотрите, что произойдет.

#include <stdio.h>

#include <stdlib.h>


int main() {

 char *ptr = (char *)malloc(1024);

 ptr[0] = 0;

 /* Теперь пишет за пределы блока */

 ptr[1024] = 0;

 exit(0);

}

Когда вы откомпилируете и выполните программу, то не увидите некорректного поведения. Однако вероятно, что область памяти, выделенная malloc, повреждена, и вы, в конце концов, попадете в беду.

$ cc -о efence efence.с

$ ./efence

$

Тем не менее, если вы возьмете ту же самую программу и скомпонуйте ее с библиотекой ElectricFence (libefence.a), то получите немедленный отклик:

$ cc -о efence efence.с -lefence

$ ./efence

Electric Fence 2.2.0 Copyright (С) 1987-1999 Bruce Perens < [email protected]>

Segmentation fault

$

Выполнение под контролем отладчика позволяет получить подробное описание проблемы;

$ cc -g -о efence efence.с -lefence

$ gdb efence

(gdb) run

Starting program: /home/neil/BLP4e/chapter10/efence


Electric Fence 2.2.0 Copyright (C) 1987-1999 Bruce Perens [email protected]


Program received signal SIGSEGV, Segmentation fault.

[Switching to Thread 1024 (LWP 1869)]

0x08048512 in main () at efence.c:10

10  ptr[1024] = 0;

(gdb)

Как это работает

Библиотека ElectricFence заменяет функцию malloc и связанные с ней функции версиями, применяющими аппаратные средства виртуальной памяти для защиты от несанкционированного доступа к памяти. При возникновении подобного обращения к памяти порождается сигнал нарушения сегментации и программа останавливается.

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 ( [email protected]) (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.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*