Bonjour, bonne année et meilleurs voeux ^^
Récemment je me suis replongé dans la programmation en C et j'ai été confronté a un "effet de bord" assez déroutant...
J'écris une fonction qui va lire l'arborescence d'un répertoire, chaque "entrée" (un nom de fichier régulier sous Linux) est "insérée" dans une liste doublement chaînée...
La librairie qui gère les listes doublement chaînées a été éprouvée et dans d'autres applications où j'insère des chaînes de caractères je n'ai jamais rencontré ce que j'ai observé en testant cette fonction,
je pars donc du principe que "cela ne vient pas de ma librairie".
Voici la boucle principale dans laquelle nous retrouvons le point de récursion...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 void BrowseFiles(char *pPath) { DIR *desc_REP; struct dirent *fichier; char Buffer[FILENAME_MAX]="\0"; if(pPath==NULL) return; desc_REP = opendir(pPath); if(desc_REP==NULL) return;
Ici j'ai changé en Buffer[0]='\0'... apparemment si je ne passe pas de paramètre en ligne de commande ça provoque une erreur de segmentation :{
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 do { fichier=readdir(desc_REP); if(fichier==NULL) break; // ignorer les répertoires spéciaux '.' et '..' de la liste if(strcmp(fichier->d_name,".") && strcmp(fichier->d_name,"..")) { // si le nom du fichier est différent de '.' et '..' if(fichier->d_type==DT_DIR) { // il s'agit d'un répertoire memcpy(Buffer,0,FILENAME_MAX);
C'est ici que ça coince ^^
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 getcwd(Buffer,FILENAME_MAX); strncat(Buffer,"/",1); strncat(Buffer,fichier->d_name,strlen(fichier->d_name)); chdir(Buffer); BrowseFiles(Buffer); // point de récursion chdir(".."); } if(fichier->d_type==DT_REG) { if(strstr(fichier->d_name," -- ")) {
En regardant la valeur retournée à "fichier" je me suis dit que la fonction readdir() faisait un malloc() ou calloc() (j'ai pas encore pris la peine d'aller voir dans les sources)
et que le pointeur était retourné en fin de traitement, donc je me suis dit que je pouvais allégremment prendre le contenu du champs d_name de cette structure et l'insérer
dans ma liste chaînée...
Le soucis c'est qu'en regardant le résultat lors de l'affichage du contenu de la liste, c'est du "n'importe quoi" comme si à un moment donné il n'y avait plus de '\0' en fin
de chaîne de caractères, un effet de bord classique, qui heureusement ici ne se solde pas par un core dump, une erreur de segmentation.
Les instructions ci-dessus permettent d'afficher un contenu cohérent des données...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 #ifndef SHOWBUG char *toadd=calloc(1,strlen(fichier->d_name)); strcpy(toadd,fichier->d_name); lc_insert((void*)toadd,ll_NomsFichiers,cssmuserdef,sizeof(char*));
L'instruction ci-dessus provoque un affichage des données quelque peu "foireux"... symptômatique des effets de bords...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 #else lc_insert((void*)fichier->d_name,ll_NomsFichiers,cssmuserdef,sizeof(char*)); #endif
C'est tout de même étrange de devoir passer par la copie (j'ai volontairement évité de faire toadd=fichier->d_name et préféré utiliser strcpy() ) alors que readdir() est censé fournir un champs d_name valide.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 } } } }while(fichier); }
Voici ce que j'ai observé au niveau du "header" /usr/lib/bits/dirent.h...
Les noms de mes fichiers ne font jamais plus de 256 caractères... je suis un peu dérouté par rapport au "comportement" de mon application...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 struct dirent64 { __ino64_t d_ino; __off64_t d_off; unsigned short int d_reclen; unsigned char d_type; char d_name[256]; /* We must not include limits.h! */ };
Je pense que d_name n'est jamais liée à un malloc() ou calloc()... je continues de chercher en espérant que l'accès au système de fichier et le changement du contenu de d_name ne fasse pas partie d'une fonction écrite en assembleur parce que là je vais galèrer ^^
Partager