Newsgroup: it.comp.programmare
Titolo: Memory leak: ma c'è davvero?

Ciao, ieri sera mi sono rotto la testa su un memory leak segnalato da 
valgrind. Sto sviluppando un programma per GNOME utilizzando glib.
(Se volete vedere tutto il codice basta un
bzr branch lp:luce
)
Per ora il mio programma scandisce una directory e restituisce una lista 
di stringhe contenenti i nomi dei file che sono di tipo image/jpeg.
Ho provato valgrind per vedere se ci sono problemi; ebbene mi segnala 
che nella funzione che mi elenca tutti i file (luce_get_dir_files, qui 
sotto), c'ï¿œ un memory leak.
GList*
luce_get_dir_files(const gchar* dirname)
{
	GDir*   gdir;
	GList*	ret_list=NULL;
 
	gdir=g_dir_open(dirname,0,NULL);
	if(!gdir)
	{
		printf("Error opening directory '%s'\n", dirname);
		return NULL;
	}
	while(1)
	{
		const gchar* file;
		gchar*  absolute_file;
		file=g_dir_read_name(gdir);
		if(!file)
			break;
		absolute_file=g_build_filename(dirname,file,NULL);
		ret_list=g_list_append(ret_list,(gpointer)absolute_file);
	}
	g_dir_close(gdir);
	return ret_list;
}
Ecco il report di valgrind:
Codice:
==25359== 112 bytes in 7 blocks are definitely lost in loss record 753 
of 810
==25359==    at 0x4024D12: realloc (vg_replace_malloc.c:476)
==25359==    by 0x44401DE: g_realloc (in /lib/libglib-2.0.so.0.2200.3)
==25359==    by 0x445B1DE: ??? (in /lib/libglib-2.0.so.0.2200.3)
==25359==    by 0x445BD57: g_string_insert_len (in 
/lib/libglib-2.0.so.0.2200.3)
==25359==    by 0x445C0BA: g_string_append_len (in 
/lib/libglib-2.0.so.0.2200.3)
==25359==    by 0x442702C: ??? (in /lib/libglib-2.0.so.0.2200.3)
==25359==    by 0x4427243: g_build_filename (in 
/lib/libglib-2.0.so.0.2200.3)
==25359==    by 0x8048BD3: luce_get_dir_files (luce.c:173)
==25359==    by 0x8048FA9: main (luce.c:220)
Sembra insomma che secondo lui la parte puntata da absolute_file vada 
persa (dico male?), perï¿œ non mi pare proprio che sia cosï¿œ. La 
g_list_append() mica crea una nuova stringa, utilizza il puntatore alla 
stringa corrente.... Boh!!!
Avete qualche idea?
Ciao e grazie!
  Marco

 Avete qualche idea?
Tutti quei puntatori di cui sopra, a che cosa puntano?
Qualcuno (dirname) puntera' ad un'area di memora prima di entrare in
quella funzione.
Siamo sicuri che tale area sia grande abbastanza?
Non e' che viene sovrascritta nel ciclo provocando l'errore?

 Non e' che viene sovrascritta nel ciclo provocando l'errore?
dirname non viene toccata n� dalla g_build_filename n� da altre 
funzioni, quindi non ci dovrebbero essere problemi...
file invece punta al nome del file nella directory e nemmeno quello 
viene toccato.
absolute_file si becca il risultato della g_build_filename, che � una 
stringa allocata "di fresco".
La g_list_append � una funzione di libreria generica per stringhe, e nel 
rispettivo nodo viene inserito l'indirizzo puntato da absolute_file.
Al giro dopo absolute_file punter� a qualcos'altro ma la parte puntata 
precedentemente non va persa come invece dice valgrind... mah!
Forse non ho capito bene il messaggio di errore...
Ciao e grazie

absolute_file viene messo in lista e quindi potrebbe essere rilasciato 
altrove (verifica che la lista sia rilasciata in modo corretto), ma file 
non deve essere rilasciato in qualche modo dentro il loop?
-- 
Valter Minute
(the reply address of this message is invalid)
(l'indirizzo di reply di questo messaggio non ï¿œ valido)


in realtï¿œ no! E' una cosa un po' strana in effetti, perï¿œ qui dice di no:
http://library.gnome.org/devel/glib/unstable/glib-File-Utilities.html#g-dir-read-name
g_dir_read_name ()
const gchar *       g_dir_read_name                     (GDir *dir);
Retrieves the name of the next entry in the directory. The '.' and '..' 
entries are omitted. On Windows, the returned name is in UTF-8. On Unix, 
it is in the on-disk encoding.
dir :
a GDir* created by g_dir_open()
Returns :
The entry's name or NULL if there are no more entries. The return value 
is owned by GLib and must not be modified or freed.
Ciao e grazie


era proprio questo! Non rilascia i nodi!
Grazie mille per la dritta, ti devo una birra!
Ciao
  Marco

 precedentemente non va persa come invece dice valgrind... mah!
Quindi da qualche parte qualcuno alloca qualcosa che non viene liberata.
Non e' che e' proprio la g_build_filename che al suo interno alloca lo 
spazio di cui ritorna il puntatore?


Io pensavo di liberare quella memoria attraverso una successiva g_list_free.
Tuttavia, la g_list_free rilascia la struttura di controllo della lista 
(quella cioè composta dal puntatore al nodo e dai puntatori a next e a 
prev) ma non il nodo stesso. Che andava rilasciato a mano!
Ecco risolto l'inghippo!
Ciao e grazie anche a te per l'aiuto!
Marco

 Ecco risolto l'inghippo!
In effetti e' un comportamento piu' che logico.
Un oggetto libera quanto alloca egli stesso: non puo' e non deve
liberare oggetti che riceve, dei quali nulla sa.
Nel tuo caso l'oggetto che gli passi arriva da una allocazione
dinamica esterna, ma potebbe benissimo essere un oggetto statico per
quanto gli riguarda, oppure lo potresti stare utilizzando anche
altrove quando disallochi la lista.
Se tutti gli elementi della tua lista vengono allocati in runtime,
come mi pare di capire, prima di chiudere la lista dovresti scriverti
un ciclo che se la scorre tutta e disalloca gli oggetti puntati da
essa.