valgrind détecte une fuite de mémoire mais l’application fonctionne

J’ai écrit une application capable de lire en firebase database sqlite grâce à cette fonction:

struct query_res excucute_sql_statement(char *database, char *zSQL){ sqlite3 *conn; sqlite3_stmt *res; const char *tail, *buf, *zErrMsg; struct query_res q_res; char table[MAXSTMTNUM][MAXCOLNUM][MAXSTRINGLEN]; q_res.table = table; q_res.num = 0; int maxtry = 5, try = 0; while (sqlite3_open(database, &conn)) { if (try > maxtry) break; printf("Can not open database \'%s\'. %s\n", database, sqlite3_errmsg(conn)); usleep(50000); try ++; } if (sqlite3_exec(conn, zSQL, callback, &q_res, &zErrMsg)){ printf("Excecuting %s\n", zSQL); printf("We did not get any data! error %s\n",zErrMsg); if(sqlite3_finalize(conn)) printf("Can not finalize database. %s\n", sqlite3_errmsg(conn)); if(sqlite3_close(conn)) printf("Can not close database. %s\n", sqlite3_errmsg(conn)); return q_res; } sqlite3_free(zSQL); if(sqlite3_close(conn)) printf("Can not close database. %s\n", sqlite3_errmsg(conn)); return q_res; } 

Pour chaque ligne renvoyée, la fonction callback est appelée:

 static int callback(void *buf, int argc, char **argv, char **azColName){ int i; struct query_res *q_res; q_res = (struct query_res *)buf; if (q_res->num >= MAXSTMTNUM) return 0; q_res->table[q_res->num] = calloc(argc, sizeof(char *)); for(i=0; i= MAXCOLNUM) break; q_res->table[q_res->num][i] = calloc(((strlen(argv[i]) table[q_res->num][i], argv[i], ((strlen(argv[i]) num ++; return 0; } 

Voici l’extrait du code où excucute_sql_statement est appelé:

 struct query_res res; res = excucute_sql_statement(database, zSQL); directions = malloc(sizeof (struct direction_list)); directions->directions = calloc(5, sizeof (struct direction)); double cur_dist, min_dist = 30; float s_lat, s_lon, e_lat, e_lon; directions->direction_num = 0; //printf("Res table num %d\n", res.num); //printf("First elem %s\n", res.table[0][0]); for (i = 0 ; i direction_num); //printf("cur_dist %f\n", cur_dist); if (cur_dist directions[0] = fill_direction(rs, rp, database); directions->direction_num = 1; min_dist = cur_dist; } else if (cur_dist == min_dist){ directions->directions[directions->direction_num] = fill_direction(rs, rp, database); directions->direction_num ++; } } 

Ces fonctions fonctionnent bien et donnent le résultat attendu, mais lors de l’exécution de valgrind, j’ai la sortie suivante:

 ==22808== Thread 2: ==22808== Invalid read of size 4 ==22808== at 0x804946B: get_all_possible_directions (util.c:240) ==22808== by 0x8049D73: start_direction_detection (direction_detection.c:293) ==22808== by 0x40C41C88: ??? ==22808== Address 0x4f03690 is not stack'd, malloc'd or (recently) free'd ==22808== ==22808== Invalid read of size 1 ==22808== at 0x402F5C3: __GI___rawmemchr (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) ==22808== by 0x40C246E: _IO_str_init_static_internal (strops.c:44) ==22808== by 0x8049D73: start_direction_detection (direction_detection.c:293) ==22808== by 0x40C41C88: ??? ==22808== Address 0x45aa01b is 0 bytes after a block of size 11 alloc'd ==22808== at 0x402B965: calloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) ==22808== by 0x8048F59: callback (util.c:57) ==22808== ==22808== Invalid read of size 4 ==22808== at 0x8049487: get_all_possible_directions (util.c:241) ==22808== by 0x8049D73: start_direction_detection (direction_detection.c:293) ==22808== by 0x40C41C88: ??? ==22808== Address 0x4f03690 is not stack'd, malloc'd or (recently) free'd 

etc …

Notez que la ligne 240 correspond à la première instruction scanf.

Je pense qu’il y a quelque chose qui ne va pas avec l’initialisation de ma table. Peut-être ici:

 q_res->table[q_res->num] = calloc(argc, sizeof(char *)); 

Avez-vous une idée de la raison pour laquelle valgrind a provoqué cette erreur?

Merci


[mise à jour du commentaire:]

struct query_res est composé de char ***table et int num .

Dans excucute_sql_statement() , ici

 q_res.table = table; 

vous copiez une référence à la mémoire de stockage local ( table ) dans la structure renvoyée par la fonction.

Le stockage local de stack devient invalide dès le retour de la fonction. La table membres de la structure fait donc référence à la mémoire non valide (non allouée) après le retour de la fonction.

Pour résoudre ce problème excucute_sql_statement()

 struct query_res excucute_sql_statement(char *database, char *zSQL) { [...] /* char table[MAXSTMTNUM][MAXCOLNUM][MAXSTRINGLEN]; */ /* Delete this line. */ q_res.table = NULL; q_res.num = 0; 

et callback()

 static int callback(void *buf, int argc, char **argv, char **azColName) { size_t i; struct query_res * q_res = (struct query_res *) buf; /* Resize statement table, adding one new entry. */ q_res->table = realloc(q_res->table, (q_res->num + 1) * sizeof(*q_res->table)); /* Allocate new argument table. */ /* (Allocate +1 for a stopper element which stays NULL to be able to detect the end of the table.) */ q_res->table[q_res->num] = calloc(argc + 1, sizeof(*q_res->table[q_res->num])); for(i=0; itable[q_res->num][i] = malloc(strlen(argv[i]) + 1); /* Copy argument. */ strcpy(q_res->table[q_res->num][i], argv[i]); } q_res->num++; return 0; } 

(non testé)

Veuillez également noter que le code complet (le vôtre et le mien) manque une vérification d’erreur correcte. Ici, en particulier, les valeurs réaccordées des appels d’allocation à malooc/calloc/realloc doivent être testées par rapport à NULL !