Valgrind kullanarak C ve C++’ta bellek denetimi

Valgrind Linux dağıtımlarında çalıştırabileceğiniz bir bellek denetim programıdır. Yaptığı şey kısaca programınızı kendi alanında çalıştırarak C için malloc ve alloc, C++ için ise new ve delete kullanımlarınızdaki yanlışlıkları izlemek.

Programı www.valgrind.org sitesinden edinebilirsiniz. Bu yazıda birkaç örnekle kullanımına değineceğim.

Yanlış bellek kullanımları programlarda karşılaşabileceğiniz çözümü en zor olan hatalardandır. Bunun nedenlerinin arasında hatanın bir runtime hatası olması ve herhangi anlaşılır bir geri bildirim vermemesi sayılabilir.

İlk önce programı sıkıştırılmış dosyadan çıkartarak ve

./configure
make
make install
komutlarını sırayla çalıştırarak kurulumu tamamlayabilirsiniz.
Denemek için öncelikle basit bir program yazıyoruz.
#include <iostream>
int main()
{
        std::cout<<"Deneme"<<std::endl;
        return 0;
}

Terminalden derliyorsanız

gcc -g deneme.cpp -lstdc++ -o deneme

komutuyla programımızı derliyoruz ve

valgrind --tool=memcheck --leak-check=yes --show-reachable=yes ./deneme

yazarak valgrind çıktımızı alıyoruz.

==16660== Memcheck, a memory error detector
==16660== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==16660== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==16660== Command: ./deneme
==16660==
Deneme
==16660==
==16660== HEAP SUMMARY:
==16660==     in use at exit: 0 bytes in 0 blocks
==16660==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==16660==
==16660== <strong>All heap blocks were freed -- no leaks are possible</strong>
==16660==
==16660== For counts of detected and suppressed errors, rerun with: -v
==16660== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Valgrind bize programımızda bir bellek yerleşim hatasının imkanlı olmadığını söyledi.

Bellek açıklarını bulmak

100 tane dinamik int tipinde değişken oluşturursak ve delete komutu ile silmezsek

#include <iostream>
int main()
{
        int *x = new int[100];
        return 0;
}

dosyasını derleyip

valgrind --tool=memcheck --leak-check=yes --show-reachable=yes ./deneme

komutunu kullandığımızda

==16722== Memcheck, a memory error detector
==16722== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==16722== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==16722== Command: ./deneme
==16722==
==16722==
==16722== HEAP SUMMARY:
==16722==     in use at exit: 400 bytes in 1 blocks
==16722==   total heap usage: 1 allocs, 0 frees, 400 bytes allocated
==16722==
==16722== 400 bytes in 1 blocks are definitely lost in loss record 1 of 1
==16722==    at 0x4C2B7EA: operator new[](unsigned long) (vg_replace_malloc.c:422)
==16722==    by 0x40071E: main (deneme.cpp:5)
==16722==
==16722== LEAK SUMMARY:
==16722==    definitely lost: 400 bytes in 1 blocks
==16722==    indirectly lost: 0 bytes in 0 blocks
==16722==      possibly lost: 0 bytes in 0 blocks
==16722==    still reachable: 0 bytes in 0 blocks
==16722==         suppressed: 0 bytes in 0 blocks
==16722==
==16722== For counts of detected and suppressed errors, rerun with: -v
==16722== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

400 bytelık bir açığımızın olduğunu görebiliriz. (1 int 4 byte olacak şekilde)

Değer verilmemiş değişkenlere erişim hatasını bulmak

#include <iostream>
int main()
{
        int x;
        if(x == 1)
                std::cout<<"deneme";
        return 0;
}

dosyasını derleyip Valgrind ile çalıştırdığımızda

==16886== Memcheck, a memory error detector
==16886== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==16886== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==16886== Command: ./deneme
==16886==
==16886== Conditional jump or move depends on uninitialised value(s)
==16886==    at 0x400789: main (deneme.cpp:6)
==16886==
==16886==
==16886== HEAP SUMMARY:
==16886==     in use at exit: 0 bytes in 0 blocks
==16886==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==16886==
==16886== All heap blocks were freed -- no leaks are possible
==16886==
==16886== For counts of detected and suppressed errors, rerun with: -v
==16886== Use --track-origins=yes to see where uninitialised values come from
==16886== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

çıktısında görebileceğiniz gibi programın hangi satırında değer atamadığımız bir değişkene erişmeye çalıştığımızı görebiliriz.

Yanlış işaretçi kullanımlarını bulmak

#include <iostream>
int main()
{
        int *x = new int[10];
        x[15] = 1;
        return 0;
}

dosyasını derleyip Valgrind ile çalıştırdığımızda ise

==16944== Memcheck, a memory error detector
==16944== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==16944== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==16944== Command: ./deneme
==16944==
==16944== Invalid write of size 4
==16944==    at 0x40072B: main (deneme.cpp:6)
==16944==  Address 0x5a1c07c is 20 bytes after a block of size 40 alloc'd
==16944==    at 0x4C2B7EA: operator new[](unsigned long) (vg_replace_malloc.c:422)
==16944==    by 0x40071E: main (deneme.cpp:5)
==16944==
==16944==
==16944== HEAP SUMMARY:
==16944==     in use at exit: 40 bytes in 1 blocks
==16944==   total heap usage: 1 allocs, 0 frees, 40 bytes allocated
==16944==
==16944== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==16944==    at 0x4C2B7EA: operator new[](unsigned long) (vg_replace_malloc.c:422)
==16944==    by 0x40071E: main (deneme.cpp:5)
==16944==
==16944== LEAK SUMMARY:
==16944==    definitely lost: 40 bytes in 1 blocks
==16944==    indirectly lost: 0 bytes in 0 blocks
==16944==      possibly lost: 0 bytes in 0 blocks
==16944==    still reachable: 0 bytes in 0 blocks
==16944==         suppressed: 0 bytes in 0 blocks
==16944==
==16944== For counts of detected and suppressed errors, rerun with: -v
==16944== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

çıktısından hem delete kullanarak serbest bırakmadığımız bir bellek miktarını ve bu belleğin ayrıldığı satırı hem de büyüklüğü 10 olan bir array’in 15. elemanına ulaşmaya çalıştığımızdan kaynaklanan hatanın yerini görebiliriz.

Etiketler:

Bir Cevap Yazın