В данном посте речь пойдет о mudflap.
mudflap - это технология проверки указателей, основанная не на бинарной инструментации, как valgrind или dr. Memory, а на инструментации времени компиляции. Если в кратце, во время компиляции программы в исходный код делаются вставки, которые обспечивают различные проверки указателей,к которым осуществляется доступ.
Теперь разберем работу mudflap на конкретном примере.
Для того, чтобы можно было использовать mudflap, нужа поддержка этой технологии в компиляторе и собственно сама библиотека, выполняющая проверки: gcc должен быть скомпилирован с опцией --enable-libmudflap, и в системе должна присутствовать библиотека libmudflap.so.
В качестве примера рассмотрим программу, котороя пытается записать в уже освобожденную память:
#include <malloc.h> int main (void) { const int chunk_size = 18; const int count = 10000; int j = 0; void * ptrs [count]; /* выделяем 10 000 кусочков памяти по 18 байт.*/ for (j = 0; j < count; j++) { ptrs [j] = malloc (chunk_size); } /* освобождаем все, кроме первого и последнего */ for (j = 1; j < count - 2; j++) if (ptrs [j]) free (ptrs [j]); /* записываем в освобожденную память*/ *(char*)ptrs [10] = 10; /* просим glibc сделать "дефрагментацию" выделенной памяти */ malloc_trim (1); return 0; }Результатом работы программы будет Segmentation Fault.
Это происходит потому что при попытке записи в освобожденную память (на самом деле она не освобождается, а помечается как неиспользуемая) программа портит служебную информацию glibc, а именно связный список, который используется в glibc для управления памятью.
Чтобы отловить ошибку в программе нужно пересобрать программы с mudflap инструментацией:
gcc -fmudflapth -lmudflap -Wall -Wextra -g -ggdb3 buggy.cЗапускаем:
./a.out
В результате работы программа выдает следующее:
******* mudflap violation 1 (check/write): time=1320343428.778161 ptr=0xe85c10 size=1 pc=0x7fcc8d0dc4f8 location=`buggy.c:22:21 (main)' /usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/libmudflap.so.0(__mf_check+0x38) [0x7fcc8d0dc4f8] ./a.out(main+0x301) [0x400da5] /lib64/libc.so.6(__libc_start_main+0xec) [0x7fcc8cd63e8c] number of nearby objects: 0
Ясно видно где в исходном коде возникает проблема.
Для проверки, запустим программу под valgrind-ом, который выдает следующую информацию:
==26575== ==26575== Invalid write of size 1 ==26575== at 0x4006E0: main (buggy.c:22) ==26575== Address 0x51bc400 is 0 bytes inside a block of size 18 free'd ==26575== at 0x4C27F6C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==26575== by 0x4006C8: main (buggy.c:19)valgrind как и mudflap, точно показал место ошибки в программе:
buggy.c: 22
Резюмирая можно обозначить плюсы и минусы mudflap:
"+" :
1. Более низкий overhead по сравнению с valgrind.
2. Лучшая переносимость: доступен для платформ ARM и MIPS.
3. Из-за того, что инструментация происходи во время выполнения, может находить более сложные ошибки и более точно показывать их в коде.
"-":
1. Поддержка кода, написанного только на C/C++.
2. Привязка к компилятору GCC.
3. Необходимость перекомпиляции.
Таким образом, mudflap вполне удобный тул, который позволяет искать утечки в памяти не используя valgrind, что особенно полезно для встраиваемых систем (ARM и MIPS), где на исполнение кода существенно влияют накладные расходы на инструментацию.
Больше информации о mudflap можно посмотреть тут : http://gcc.gnu.org/wiki/Mudflap_Pointer_Debugging