[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Migliorare Debian e il software libero: trovare bug con valgrind e scrivere le patch



On 28/11/20 22:19, Davide Prina wrote:

Quindi valgrind è uno strumento eccellente e sui casi semplici ti permette di identificare immediatamente il problema senza dover fare debugging, ma guardando solo poche linee di codice sorgente

ho dimenticato di dire che per poter analizzare poche righe di codice, magari guardando in sorgenti anche enormi e senza conosce nulla o quasi di quello che fanno i sorgenti che si stanno guardando, uso cscope.

cscope è un software davvero utilissimo, che ti permette di individuare quello che ti serve in pochi secondi in sorgenti anche vastissimi e di essere subito produttivo (es: capire un problema e proporre una patch).

ad esempio stavo guardando questo, faccio vedere i passi che seguo a partire dalla segnalazione di valgrind per arrivare al punto del problema:

1) eseguo valgrind sull'eseguibile, e mi ritrovo un lungo elenco di chiamate per arrivare al problema:

==21552== 4,096 bytes in 1 blocks are still reachable in loss record 1,931 of 1,937 ==21552== at 0x483AB65: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==21552== by 0x4D7E572: ExpandQuarkTable (/usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
[...]

2) non so dove sia il punto nel sorgente, ma solo la libreria, allora cerco il pacchetto che contiene tale libreria, cerco i simboli di debug e li installo

$ dpkg -S /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0
libx11-6:amd64: /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0
$ apt search libx11-6
[...]
libx11-6-dbgsym/testing-debug 2:1.6.12-1 amd64
[...]

# apt install libx11-6-dbgsym


3) a questo punto rieseguendo valgrind mi segnala il sorgente e la riga incriminata

==21552== 4,096 bytes in 1 blocks are still reachable in loss record 1,931 of 1,937 ==21552== at 0x483AB65: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==21552==    by 0x4D7E572: ExpandQuarkTable (Quarks.c:209)

4) mi installo i sorgenti

$ apt source libx11-6

5) faccio partire cscope dalla directory creata dal punto precedente

$ cd libx11-1.6.12
$ cscope -R

6) appena creato l'indice gli dico di aprirmi il file Quarks.c e mi posiziono alla riga 209
entries = Xcalloc(newmask + 1, sizeof(Entry));

da qui posso vedere dove entries è dichiarato, allocato, salvata la sua posizione in quarkTable e usato per salvarsi altre posizioni, quindi perde la posizione iniziale di allocazione. Quindi la variabile da verificare per capire se vi è il rilascio o meno dell'area allocata è quarkTable

[...]
    register Entry *oldentries, *entries;
[...]
    entries = Xcalloc(newmask + 1, sizeof(Entry));
[...]
    quarkTable = entries;
[...]
        if ((entry = oldentries[oldidx])) {
[...]

7) a questo punto esco dal file e chiedo a cscope di dirmi dove è definito "quarkTable"
static Entry zero = 0;
static Entry *quarkTable = &zero; /* crock */

8) a questo punto esco dal file e chiedo a cscope di dirmi dove è usato il simbolo "quarkTable"
 Quarks.c <global>                   71 static Entry *quarkTable = &zero;
1 Quarks.c ExpandQuarkTable          185 oldentries = quarkTable;
2 Quarks.c ExpandQuarkTable          212 quarkTable = entries;
3 Quarks.c _XrmInternalStringToQuark 252 while ((entry = quarkTable[idx])) {
4 Quarks.c _XrmInternalStringToQuark 337 quarkTable[idx] = entry;

da qui vedo che quarkTable è salvato in oldentries, ma avviene prima di aver allocato entries e quindi il comando free su oldentries presente alla riga 234 non ha nessun effetto su quando allocato in entries.

Da questi pochi passi ho individuato che entries viene allocato, la posizione dell'area allocata è salvata in quarkTable, ma tale area di memoria non è mai rilasciato -> memory leak. In pratica tale area di memoria verrà rilasciata soltanto quando il programma terminerà.

Tutto questo senza sapere nulla di cosa effettivamente fa libx11-6 e senza guardare neanche le 17 chiamate precedenti che valgrind mi segnala per farmi vedere il percorso per arrivare al memory leak. Per fare questo controllo ci avrò messo circa 1-2 minuti, dove la maggior parte del tempo è dovuta allo scaricamento e installazione dei pacchetti.

Nota: in questo caso tutto è nello stesso file Quarks.c, ma le varie componenti potevano essere sparse in 10 file differenti e il tempo di verifica sarebbe stato lo stesso.

Poi va capito perché non viene rilasciata la memoria... forse quelli che l'hanno sviluppato hanno pensato che era inutile rilasciare tale memoria perché alla terminazione del programma viene rilasciata in automatico (e probabilmente più velocemente). Ma se il programma chiama più volte tale funzione, allora si avrà un accumulo di memoria allocata e non rilasciata... ripeto non so cosa serva Quarks.c, ma essendo una libreria il rilascio di memoria dovrebbe essere garantito... magari è compito del chiamante fare il rilascio? Però la libreria non fornisce un metodo per liberare la memoria...

Ciao
Davide
--
Elenco di software libero: http://tinyurl.com/eddgj
GNU/Linux User: 302090: http://counter.li.org
Non autorizzo la memorizzazione del mio indirizzo su outlook



Reply to: