Bonjour tout le monde,
je continue à pratiquer mon C tranquillement, et je tombe sur une autre erreur (toujours dans le même programme). L’erreur en question c’est :
free(): double free detected in tcache 2
Grâce aux (nombreux) messages de debug que j’ai intégré à mon programme, j’ai pu identifier la fonction exacte qui me sort ce soucis. Je pensais au départ que c’était dû à un free que j’y utilisais, mais après avoir jeté un œil à valgrind (merci grim7reaper!), en fait c’est realloc() qui fout la merde.
Donc plutôt que de passer des heures à essayer de trouver pourquoi il ne marche pas, je vais vous expliquer pourquoi je m’en sers, et vous demander comment je peux faire autrement. 😃
Dans mon programme j’ai cette structure:
typedef struct
/* structure representing a file to be compressed into a bzf archive */
{
uint32_t fname_l; // filename length
uint32_t dirname_l; // dirname length
uint32_t numchunks; // number of chunks compressed
uint32_t compressed_size; // total compressed size, including infos
char *fname; // filename
char *dirname; // dirname
} bzfile;
En gros c’est tout plein d’informations dont j’ai besoin à propos d’un fichier, avant de compresser le fichier et de l’insérer dans une archive.
Pour initialiser un truc comme ça, je fais quelque chose du genre:
/* Allocate memory for structure */
fprop = (bzfile *)malloc(sizeof(bzfile));
/* Get dir and file names’ length */
fprop->dirname_l = (uint32_t)strlen(dirname);
fprop->fname_l = (uint32_t)strlen(filename);
/* Allocate memory for names */
fprop->dirname = (char *)malloc(fprop->dirname_l + 1);
fprop->fname = (char *)malloc(fprop->fname_l + 1);
/* Fill in file properties */
strcpy(fprop->dirname, dirname);
strcpy(fprop->fname, filename);
Bon, déjà rien que ça ça ne me semble pas super chouette: j’ai beaucoup trop de malloc, et si je fais un free(fprop), est-ce que ses attributs dirname et fname sont aussi libérés, j’en doute, bref, c’est pas top.
Mais c’est pas tout! Des trucs comme ça, il m’en faut tout une liste! 😃 (Ce ne serait pas drôle sinon.) Et je dis bien une liste et pas un tableau: je n’en connais pas le nombre à l’avance. Du coup, en pratique, ça ressemble plus à ça:
/* Allocate memory for files prop */
fprop = (bzfile **)extend((char *)fprop, (*files_count + 1) * sizeof(bzfile *));
fprop[*files_count] = (bzfile *)malloc(sizeof(bzfile));
/* Get dir and file names’ length */
fprop[*files_count]->dirname_l = (uint32_t)strlen(dirname);
fprop[*files_count]->fname_l = (uint32_t)strlen(filename);
/* Allocate memory for names */
fprop[*files_count]->dirname = (char *)malloc(fprop[*files_count]->dirname_l + 1);
fprop[*files_count]->fname = (char *)malloc(fprop[*files_count]->fname_l + 1);
/* Fill in file properties */
strcpy(fprop[*files_count]->dirname, dirname);
strcpy(fprop[*files_count]->fname, filename);
/* Increase files count */
(*files_count)++;
(Vous aurez compris que le tout est inséré dans une boucle.)
Où extend(char* ptr, int size) est une fonction de ma création qui étend la mémoire allouée à ptr jusqu’à une taille de size. Je vous en mets le code là, elle est relativement courte et vous pourrez me faire des retours dessus comme ça:
char* extend(char *ptr, size_t new_size)
/* Extends a pointer */
{
/* Reallocates memory in a temporary pointer */
char* tmp = realloc(ptr, new_size); // temporary pointer
if(tmp != NULL)
{
/* Allocation succeded, change pointer */
ptr = tmp;
}
else
{
/* Allocation failed: quit or free memory */
fprintf(stderr, "Memory allocation error");
exit(-1);
/*
free(ptr);
ptr = NULL; /**/
}
return ptr;
}
Bon, même en admettant que je n’utilise pas cette structure (cette liste de structures!) en respectant les bons usages, c’est une approche qui tend à multiplier les erreurs possible, en particulier les trucs relous du genre double free qui ne sont pas faciles à débugger, voire qui m’amène à créer des UB au petit bonheur la chance. Donc plutôt que d’essayer de débugguer ce code un peu crâde, qu’est-ce que vous me conseilleriez comme structure de données pour ce genre de problème?
Pour rappel, le problème en question c’est: j’ai besoin des informations ci-dessus pour une quantité de fichiers dont j’ignore la taille (et je ne peux pas les traiter au fur et à mesure: il me faut toutes les stocker en mémoire).
Merci!