Ponieważ narzędzie Valgrinda do debugowania pamięci p.t. Memcheck sprawdza nie tylko kod aplikacji, ale też wszystkich dynamicznych bibiotek z których ona korzysta, dobrze jest wyłączyć wyświetlanie błędów, których i tak nie możemy naprawić (bo należą do cudzego kodu). O tym jest dzisiejszy wpis.

Tworzenie filtrów

Do filtrowania wyników memchecka pomocne są dwie opcje:

  • –suppressions=plik_z_filtrami – pozwala wskazać plik, z którego Valgrind ma wczytać filtry. Plik ten trzeba umieścić w katalogu, z którego odpalamy Valgrinda – zwykle jest to katalog z naszym skompilowanym programem. Dzięki temu każdy projekt może mieć swój własny zestaw filtrów
  • –gen-suppressions=all – dla każdego błędu generuje sygnaturkę, którą można przekopiować sobie do pliku z filtrami. Następnym razem błąd nie będzie już raportowany

Przykładowa sygnaturka może wyglądać tak:

{
	<FILTR MEMCZEKA>
	Memcheck:Cond
	fun:_Z5test1Ri
	fun:main
}

Pewnie niewiele Ci ona mówi, ale nie przejmuj się tym. Raz w życiu będziesz ją oglądał – kiedy będziesz kopiował ją do pliku z filtrami ;)

Droga na skróty

Zeby nie podawać pliku z filtrami za każdym razem, gdy odpalamy memchecka, warto stworzyć sobie plik konfiguracyjny ~/.valgrindrc, i w nim umieścić linię –suppressions=plik_z_filtrami. Za każdym razem, gdy odpalamy Valgrinda, wczytuje on ten plik i stosuje opcje w nim zapisane.

Przykład

Mamy prosty programik z problemem pamięciowym – wykonujemy instrukcję warunkową w oparciu o niezainicjalizowaną zmienną;

// program.cpp
int main()
{
	int x;
	if (x == 5)
		return 1;
	else
		return 0;
}

Co oczywiście skutkuje protestem memchecka. I bardzo dobrze – takie jest jego zadanie.
My jednak chcemy wyfiltrować ten błąd.
W tym celu, dla wygody, tworzymy sobie plik konfiguracyjny ~/.valgrindrc, i umieszczamy w nim linię –suppressions=plik_z_filtrami.

Następnie w katalogu z programem tworzymy plik o nazwie plik_z_filtrami. W nim będziemy umieszczali nasze filtry.

Dalej, kompilujemy program w trybie debugowania i odpalamy memchecka z opcją generowania sygnatur błędów:

> g++ -g -o program program.cpp
> valgrind --gen-suppressions=all ./program

W wyniku tego otrzymujemy sygnaturkę błędu:

==5626== Conditional jump or move depends on uninitialised value(s)
==5626==    at 0x8048409: main (program.cpp:5)
{
   <insert a suppression name here>
   Memcheck:Cond
   fun:main
}
==5626== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 15 from 1)
==5626== malloc/free: in use at exit: 0 bytes in 0 blocks.
==5626== malloc/free: 0 allocs, 0 frees, 0 bytes allocated.
==5626== For counts of detected errors, rerun with: -v
==5626== All heap blocks were freed -- no leaks are possible.

Wklejamy ją do naszego pliku z filtrami plik_z_filtrami, i odpalamy memczeka jeszcze raz. Tym razem dostajemy taki output:

==5663== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 16 from 2)
==5663== malloc/free: in use at exit: 0 bytes in 0 blocks.
==5663== malloc/free: 0 allocs, 0 frees, 0 bytes allocated.
==5663== For counts of detected errors, rerun with: -v
==5663== All heap blocks were freed -- no leaks are possible.

Czyli udało nam się wyfiltrować nasz błąd :)

Podsumowanie

Dzięk plikowi konfiguracyjnemu ~/.valgrindrc przypisaliśmy Valgrindowi na stałe plik z filtrami błędów.

Tworząc plik z filtrami błędów i wklejając do niego sygnaturkę naszecho niechcianego błędu, na stałe pozbyliśmy się go z raportów memchecka :)

Related Posts: