"Zgomot" in valgrind

De curand nu stiu ce naiba au facut astia (g++/glibc), dar un “program” care nu face absolut nimic aloca memorie in heap si ma scoate din sarite ca imi apare o alocare in plus decat ce am facut eu pe acolo. Stie cineva daca exista vreo optiune in gcc care sa dezactiveze “optimizarea” aia macar cat timp fac eu developmentul?

int main(int argc, char *argv[])
{
    return 0;
}
g++ test.cpp -o test
valgrind ./test
==4079== Memcheck, a memory error detector
==4079== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==4079== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==4079== Command: ./icefact-lab
==4079==
==4079==
==4079== HEAP SUMMARY:
==4079==     in use at exit: 0 bytes in 0 blocks
==4079==   total heap usage: 1 allocs, 1 frees, 72,704 bytes allocated
==4079==
==4079== All heap blocks were freed -- no leaks are possible
==4079==
==4079== For counts of detected and suppressed errors, rerun with: -v
==4079== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
2 Likes

Si altă aberaţie, si mai mare. Doar fac linking la o biblioteca externa (fara s-o apelez din interiorul programului) si devine imposibil sa-ti dai seama ce ai alocat, ce ai dealocat etc, pentru ca nici macar nu mai corespunde numarul de alloc-uri cu free-urile.

g++ test.cpp -o test -lcairo
valgrind ./test
==4147== Memcheck, a memory error detector
==4147== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==4147== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==4147== Command: ./test
==4147==
==4147==
==4147== HEAP SUMMARY:
==4147==     in use at exit: 12,317 bytes in 58 blocks
==4147==   total heap usage: 145 allocs, 87 frees, 91,026 bytes allocated
==4147==
==4147== LEAK SUMMARY:
==4147==    definitely lost: 0 bytes in 0 blocks
==4147==    indirectly lost: 0 bytes in 0 blocks
==4147==      possibly lost: 0 bytes in 0 blocks
==4147==    still reachable: 12,317 bytes in 58 blocks
==4147==         suppressed: 0 bytes in 0 blocks
==4147== Reachable blocks (those to which a pointer was found) are not shown.
==4147== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==4147==
==4147== For counts of detected and suppressed errors, rerun with: -v
==4147== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
2 Likes

Ce versiune de glibc folosesti? Poate chiar e o regresie. Merita ridicat un bug cu echipa glibc daca gasesti niste versiuni mai vechi unde nu e o problema.

OTOH, nu cred ca ai niciunde garantat ca un program chior are rezultate OK in valgrind. main nu e punctul in care executia incepe intr-un executabil. E foarte posibil ca parte din codul care pregateste environmentul sa faca o alocare. Poti si tu sa ai hook-uri care se executa inainte/dupa main.

Cairo e o librarie mare si complexa. Probabil ca face ceva de genul.

Iar apoi, e bine ca un program sa dealoce ce a alocat, dar nu e musai. Daca ai deajunsa memorie pentru ce-ti trebuie, poti sa nu dealoci nimic, pentru ca oricum nu conteaza dupa ce procesul s-a terminat. Mult cod numeric poate sa fie scris asa, de exemplu. Nu e nice, dar cateodata nu ai ce sa faci - o librarie care aloca memorie, dar pentru care utilizatorul uita sa cheme codul care dealoca, de exemplu.

Cel mai bine urmezi sfaturile de aici si limitezi verificarile la codul tau.

Versiunea de glibc este 2.24 (cea default din Fedora 25), dar nu cred ca e un regression. Cel mai probabil e o prealocare care se face din motive de performanta in runtime. Fisierul de suprimare a “zgomotului” nu prea are ce sa faca, Fedora deja vine cu o gramada de reguli de suprimare. Chestia e ca apare total heap usage: 1 allocs, 1 frees, 72,704 bytes allocated si e deranjant, ca ma incurca si nu mai stiu cate alocari/dealocari am facut eu.

Eu ma intrebam daca nu cumva exista vreo optiune in gcc sau vreo variabila de environment care sa dezactiveze temporar “optimizarea” cu pricina (sa nu prealoce nimic).

PS Apropo de cairo, mi s-a parut suprinzator ca a prealocat in heap niste chestii doar pentru am link-uit biblioteca la executabilul meu. Pana acum am crezut ca linking-ul e o chestie pasiva, adica pana nu apelezi vreun simbol din biblioteca respectiva nu se intampla nimic. Daca cairo era in C++, da, as fi presupus ca au pus o clasa ca variabila globala si aia ar fi putut sa aloce memorie heap in constructor. Dar in C chior nu-mi pot imagina cum ai putea aloca memorie heap fara sa apelezi o functie.

De exemplu asa ceva este plauzibil, nu executi nimic in main si totusi se aloca heap. Dar nu-mi dau seama cum s-ar putea face asta in C chior.

class Test {
public:
	Test()
	{
		new char[10];
	}
} test;

int main()
{
	return 0;
}

==6035== Memcheck, a memory error detector
==6035== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6035== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==6035== Command: ./test
==6035==
==6035==
==6035== HEAP SUMMARY:
==6035==     in use at exit: 10 bytes in 1 blocks
==6035==   total heap usage: 2 allocs, 1 frees, 72,714 bytes allocated
==6035==
==6035== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1
==6035==    at 0x4C2E8E9: operator new[](unsigned long) (vg_replace_malloc.c:423)
==6035==    by 0x400645: Test::Test() (in /home/serghei/test)
==6035==    by 0x400617: __static_initialization_and_destruction_0(int, int) (in /home/serghei/test)
==6035==    by 0x40062D: _GLOBAL__sub_I_test (in /home/serghei/test)
==6035==    by 0x40069C: __libc_csu_init (in /home/serghei/test)
==6035==    by 0x570238F: (below main) (in /usr/lib64/libc-2.24.so)
==6035==
==6035== LEAK SUMMARY:
==6035==    definitely lost: 10 bytes in 1 blocks
==6035==    indirectly lost: 0 bytes in 0 blocks
==6035==      possibly lost: 0 bytes in 0 blocks
==6035==    still reachable: 0 bytes in 0 blocks
==6035==         suppressed: 0 bytes in 0 blocks
==6035==
==6035== For counts of detected and suppressed errors, rerun with: -v
==6035== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Edit: acum aruncat o privire la link-urile tale si am vazut attribute ((constructor)). Nu stiam de extensia asta, oricum nu cred ca e o idee buna sa folosesti extensii nestandard in proiecte, mai ales daca exista posibilitatea sa trebuiasca sa compilezi si cu alte compilatoare (de exemplu eu compilez acelasi cod pentru Mac, dar acolo folosesc clang, nu gcc).

Sigur nu este de la return 0;? Ma gandesc ca poate acel 0 este alocat in afara main-ului, pentru cazul in care functia este apelata de undeva, iar apoi dealocat dupa ce termina de prelucrat ce returneaza.

Poate alocarea aia se face in orice functie (eventual cu exceptia tipului void), pentru a putea returna ce trebuie, la apelarea functiei. Iar faptul ca main se apeleaza automat, este luat in considerare…

E putin probabil sa aloce memorie pentru o amarata de constanta. Compilatorul GCC este oricum incredibil de destept, face niste optimizari de ramai prost cand te uiti in codul ASM generat. Nu se impiedica el intr-un return.

In afara de asta, un integer pe 64 de biti ocupa doar 8 bytes, in niciun caz 72704 bytes… Mai degraba ma gandesc ca isi pregateste in avans niste structuri ca sa evite alocarile in runtime, pentru ca alocarile de memorie in heap sunt printre cele mai expensive operatii.

2 Likes