C'est d'ailleurs pour ça qu'entre la page de manuel de (disons) scanf, et ce qu'on peut trouver sur le net pour expliquer son fonctionnement, ça peut donner ça : http://xrenault.developpez.com/tutoriels/c/scanf/
Par là je veux dire: certaines fonctions de la bibliothèque standard sont juste mal foutues, point. À l'époque elles avaient peut-être du sens, mais le langage C est loin d'être simple (enfin, sa syntaxe et sa grammaire le sont, mais pas son utilisation).
Ensuite, concernant strncpy/strncat: « il suffit de lire la doc » ? Vraiment ? C'est pour ça que, malgré la ressemblance entre les deux noms, chaque fonction a une page de manuel super étendue je suppose, avec des comportements différents pour que ce soit encore plus rigolo (et encore, elles étaient bien plus succintes il y a dix ans) ?
Ça donne de joyeux bouts de code du genre :
char*src;chardst[size+1];charbuf[K*size];size_tlen=0;/* ... src est alloué, initialisé, etc. quelque part ici ... *//* strncpy() copie au maximum "size" caractères de la chaîne src vers la chaîne dst. * Mais attention ! Si la longueur de src dépasse "size", alors il n'y aura pas de '2878b2550166f39398d09567f242898acfb5ed97' * final ! Il faudra le rajouter à la main du coup. */len=strlen(src);/* il faut espérer que src est bien terminé par '0円'... */strncpy(dst,src,size);if(size<=len)dst[size]='\0';/* ... */process(buf,...);/* traitement de buf, qui contient une certaine chaîne de caractères au retour de l'appel */len=strlen(buf);/* il faut espérer que buf est bien terminé par '0円'... *//* Rigolons un bon coup. strncat() prend un taille en troisième paramètre. * Si celle-ci est plus grande que la taille de ce qu'il faut concaténer, * "tout va bien" : strncat rajoute un '0円' juste après le dernier caractère copié. * Bon bien sûr, maintenant, j'ai beau avoir demandé N caractères max à concaténer, * si ma chaîne source contient plus que n caractères, alors strncat va écrire n+1 * caractères. */strncat(buf,dst,K*size-len-1);/* Comme quoi, c'était pas si compliqué ! */
et faire un truc du genre
char*src;chardst[size+1];charbuf[K*size];size_tlen1=0,len2=0;/* ... src est alloué, initialisé, etc. quelque part ici ... */len1=strlen(src);memcpy(dst,src,size);dst[size]='\0';/* ... */process(buf,...);len2=strlen(buf);size_ttmp=len1+len2+1<=K*size?len1+len2:K*size-1;memcpy(buf,dst,tmp);buf[tmp]='\0';
Ou encore :
char*src;chardst[size+1];charbuf[K*size];size_tlen1=0,len2=0;/* ... src est alloué, initialisé, etc. quelque part ici ... */len1=strlen(src);memcpy(dst,src,size);dst[size]='\0';/* ... */process(buf,...);len2=strlen(buf);if(len2+len1<K*size)strcat(buf,dst);/* La concaténation est sûre */else/* K*size < len1+len2 */{memcpy(buf+len2,dst,K*size-len2-1);buf[K*size-1]='\0';}
Ah si: au moins, dans le deuxième cas, tu ne te poses pas la question de « est-ce que c'est strncat ou strncpy qui rajoute un 0円 additionnel ? »: dans tous les cas tu as un comportement éprouvé (i.e. tu ne manipules que des bytes). Bon bien entendu, t'es niqué quand le byte fait 1 octet, mais que le char en fait 2 (comme ça peut arriver sur certains DSP).
Ce n'est pas pour rien que les dévs OpenBSD on rajouté strlcat/strlcpy: non seulement le comportement des fonctions est homogène, mais en plus elles renvoient une vraie information utile : le nombre de caractères copiés (au lieu du pointeur destination que tu as toi-même passé en paramètre au moment de l'appel...).
char*src;chardst[size+1];charbuf[K*size];/* ... src est alloué, initialisé, etc. quelque part ici ... */size_tsrc_len=strlen(src);size_tcpy_res=strlcpy(dst,src,size);/* J'ai la garantie que dst est a un '0円' */if(cpy_res<src_len){/* Gestion de la troncature */}/* ... */process(buf,...);size_tbuf_len=strlen(buf);size_tcat_res=strlcat(buf,dst,K*size);if(cat_res>=buf_len){/* Gestion de la troncature */}
(Il est tard au moment où j'écris ces lignes, et il y a de fortes chances que j'aie fait une erreur : je n'ai pas compilé pour vérifier)
Donc voilà. Je suis surpris que tu te permettes de dire que « y'à qu'à bien savoir compter », alors que même les développeurs d'environnements qui se veulent sécurisés disent que strcpy/strcat Vs strncpy/strncat est une fausse « sécurité ». Je me souviens avoir entendu et lu Marc Espie à plusieurs reprises concernant le fait que, même plein de bonne volonté, le dév qui cherche à remplacer ses strcpy/strcat par strncpy/strncat va souvent se planter à cause de la différence de sémantique dans les deux fonctions. Alors qu'au moins avec strcpy/strcat, la règle est simple : tu vérifies la taille de tes buffers avant de faire quoi que ce soit (et bien entendu, avec strlcat/strlcpy, c'est ENCORE plus simple).
[^] # Re: Dépassement de tampon
Posté par lasher . En réponse à la dépêche Naissance d'un géant : Java. Évalué à 4.
C'est d'ailleurs pour ça qu'entre la page de manuel de (disons) scanf, et ce qu'on peut trouver sur le net pour expliquer son fonctionnement, ça peut donner ça : http://xrenault.developpez.com/tutoriels/c/scanf/
Par là je veux dire: certaines fonctions de la bibliothèque standard sont juste mal foutues, point. À l'époque elles avaient peut-être du sens, mais le langage C est loin d'être simple (enfin, sa syntaxe et sa grammaire le sont, mais pas son utilisation).
Ensuite, concernant strncpy/strncat: « il suffit de lire la doc » ? Vraiment ? C'est pour ça que, malgré la ressemblance entre les deux noms, chaque fonction a une page de manuel super étendue je suppose, avec des comportements différents pour que ce soit encore plus rigolo (et encore, elles étaient bien plus succintes il y a dix ans) ?
Ça donne de joyeux bouts de code du genre :
et faire un truc du genre
Ou encore :
Ah si: au moins, dans le deuxième cas, tu ne te poses pas la question de « est-ce que c'est strncat ou strncpy qui rajoute un 0円 additionnel ? »: dans tous les cas tu as un comportement éprouvé (i.e. tu ne manipules que des bytes). Bon bien entendu, t'es niqué quand le byte fait 1 octet, mais que le char en fait 2 (comme ça peut arriver sur certains DSP).
Ce n'est pas pour rien que les dévs OpenBSD on rajouté strlcat/strlcpy: non seulement le comportement des fonctions est homogène, mais en plus elles renvoient une vraie information utile : le nombre de caractères copiés (au lieu du pointeur destination que tu as toi-même passé en paramètre au moment de l'appel...).
(Il est tard au moment où j'écris ces lignes, et il y a de fortes chances que j'aie fait une erreur : je n'ai pas compilé pour vérifier)
Donc voilà. Je suis surpris que tu te permettes de dire que « y'à qu'à bien savoir compter », alors que même les développeurs d'environnements qui se veulent sécurisés disent que strcpy/strcat Vs strncpy/strncat est une fausse « sécurité ». Je me souviens avoir entendu et lu Marc Espie à plusieurs reprises concernant le fait que, même plein de bonne volonté, le dév qui cherche à remplacer ses strcpy/strcat par strncpy/strncat va souvent se planter à cause de la différence de sémantique dans les deux fonctions. Alors qu'au moins avec strcpy/strcat, la règle est simple : tu vérifies la taille de tes buffers avant de faire quoi que ce soit (et bien entendu, avec strlcat/strlcpy, c'est ENCORE plus simple).