web-dev-qa-db-fra.com

Pourquoi devriez-vous utiliser strncpy au lieu de strcpy?

Edit: j'ai ajouté le source pour l'exemple.

Je suis tombé sur cet exemple :

char source[MAX] = "123456789";
char source1[MAX] = "123456789";
char destination[MAX] = "abcdefg";
char destination1[MAX] = "abcdefg";
char *return_string;
int index = 5;

/* This is how strcpy works */
printf("destination is originally = '%s'\n", destination);
return_string = strcpy(destination, source);
printf("after strcpy, dest becomes '%s'\n\n", destination);

/* This is how strncpy works */
printf( "destination1 is originally = '%s'\n", destination1 );
return_string = strncpy( destination1, source1, index );
printf( "After strncpy, destination1 becomes '%s'\n", destination1 );

Qui a produit cette sortie:

destination est à l'origine = 'abcdefg' 
 Après strcpy, la destination devient '123456789' 

 destination1 est à l'origine = 'abcdefg' 
 Après strncpy, la destination1 devient '12345fg' 

Ce qui me fait me demander pourquoi quelqu'un voudrait de cet effet. Il semble que ce serait déroutant. Ce programme me fait penser que vous pouvez essentiellement copier le nom de quelqu'un (par exemple, Tom Brokaw) avec Tom Bro763. 

Quels sont les avantages d'utiliserstrncpy()par rapport àstrcpy()?

70
Kredns

strncpy combat le dépassement de mémoire tampon en vous demandant de lui donner une longueur. strcpy dépend d'un \0 final, qui peut ne pas toujours se produire.

Deuxièmement, pourquoi vous avez choisi de ne copier que 5 caractères sur une chaîne de 7 caractères me dépasse, mais produit le comportement attendu. Il ne copie que les premiers caractères n, où n est le troisième argument.

Les fonctions n sont toutes utilisées comme codage défensif contre les dépassements de mémoire tampon. Veuillez les utiliser à la place d'anciennes fonctions, telles que strcpy.

85
Eric

La fonction strncpy() a été conçue pour un problème très particulier: manipuler des chaînes stockées à la manière des entrées de répertoire UNIX d'origine. Ceux-ci utilisaient un tableau de taille fixe, et un zéro-terminateur était utilisé uniquement si le nom du fichier était plus court que le tableau.

C'est ce qui se cache derrière les deux bizarreries de strncpy():

  • Il ne met pas de terminal nul sur la destination s'il est complètement rempli; et
  • Il remplit toujours complètement la destination, avec des nuls si nécessaire.

Pour un "strcpy() plus sûr", vous feriez mieux d'utiliser strncat() comme ceci:

if (dest_size > 0)
{
    dest[0] = '\0';
    strncat(dest, source, dest_size - 1);
}

Cela ne finira toujours pas le résultat et ne copiera pas plus que nécessaire.

157
caf

Bien que je connaisse l'intention de strncpy, ce n'est pas vraiment une bonne fonction. Évitez les deux. Raymond Chen explique .

Personnellement, ma conclusion est simplement d'éviter strncpy et tous ses amis si vous traitez avec des chaînes à zéro terminal. Malgré le "str" ​​dans le nom, ces fonctions ne produisent pas de chaînes à zéro terminal. Ils convertissent une chaîne terminée par un caractère null en un tampon de caractères brut. Les utiliser là où une chaîne terminée par un caractère nul est attendu car le second tampon est tout à fait faux. Non seulement vous ne réussissez pas à obtenir la terminaison NULL appropriée si la source est trop longue, mais en plus, vous obtenez un remplissage nul inutile. 

Voir aussi Pourquoi strncpy n'est-il pas sécurisé?

30
Sinan Ünür

strncpy n’est PAS plus sûr que strcpy, il ne fait qu’échanger un type de bugs avec un autre. En C, lorsque vous manipulez des chaînes de caractères C, vous devez connaître la taille de vos tampons. Il n'y a aucun moyen de les contourner. strncpy était justifié pour le répertoire mentionné par d'autres, mais sinon, vous ne devriez jamais l'utiliser:

  • si vous connaissez la longueur de votre chaîne et de votre tampon, pourquoi utiliser strncpy? C'est au mieux un gaspillage de puissance de calcul (ajouter 0 inutile)
  • si vous ne connaissez pas les longueurs, vous risquez de tronquer vos chaînes en silence, ce qui n’est guère mieux qu’un dépassement de tampon.
26
David Cournapeau

Ce que vous cherchez, c'est la fonction strlcpy() qui termine toujours la chaîne par 0 et initialise le tampon. Il est également capable de détecter les débordements. Seul problème, ce n'est pas (vraiment) portable et n'est présent que sur certains systèmes (BSD, Solaris). Le problème avec cette fonction est qu’elle ouvre une autre boîte de Panders, comme le montrent les discussions sur ce sujet http://en.wikipedia.org/wiki/Strlcpy

Mon opinion personnelle est que cela est beaucoup plus utile que strncpy() et strcpy(). Il offre de meilleures performances et est un bon compagnon pour snprintf(). Pour les plates-formes qui ne le possèdent pas, il est relativement facile à implémenter ..__ (pour la phase de développement d’une application, je substitue ces deux fonctions (snprintf() et strlcpy()) à une version de recouvrement qui annule brutalement le programme de dépassement de tampon ou de troncature Cela permet d’attraper rapidement les pires contrevenants, surtout si vous travaillez sur une base de code avec quelqu'un d’autre.

EDIT: strlcpy() peut être implémenté facilement:

size_t strlcpy(char *dst, const char *src, size_t dstsize)
{
  size_t len = strlen(src);
  if(dstsize) {
    size_t bl = (len < dstsize-1 ? len : dstsize-1);
    ((char*)memcpy(dst, src, bl))[bl] = 0;
  }
  return len;
}
20
Patrick Schlüter

La fonction strncpy() est la plus sûre: vous devez passer la longueur maximale que le tampon de destination peut accepter. Sinon, il pourrait arriver que la chaîne source ne soit pas correctement terminée par 0. Dans ce cas, la fonction strcpy() pourrait écrire plus de caractères dans la destination, endommageant tout ce qui se trouve dans la mémoire après le tampon de destination. C'est le problème de dépassement de tampon utilisé dans de nombreux exploits

De même, pour les fonctions de l'API POSIX telles que read() qui ne met pas le 0 final dans la mémoire tampon, mais renvoie le nombre d'octets lus, vous pouvez placer manuellement le 0 ou le copier à l'aide de strncpy().

Dans votre exemple de code, index n'est en réalité pas un index, mais une count - il indique le nombre de caractères au plus à copier de la source à la destination. S'il n'y a pas d'octet nul parmi les n premiers octets de la source, la chaîne placée dans la destination ne sera pas terminée avec la valeur NULL.

3
CsTamas

strncpy remplit la destination avec '\ 0' pour la taille de la source, bien que la taille de la destination soit plus petite ....

page de manuel:

Si la longueur de src est inférieure à n, strncpy () complète le reste de dest avec octets nuls.

et pas seulement le reste ... également après cela jusqu'à ce que n caractères soit atteint. Et ainsi vous obtenez un débordement ... (voir la page de manuel Implementation)

1
Jeronimo

Cela dépend de nos besoins ... pour les utilisateurs de Windows

Nous utilisons strncpy chaque fois que nous ne voulons pas copier la chaîne entière ou que nous voulons copier uniquement n nombre de caractères. Mais strcpy copie la chaîne entière, y compris le caractère nul final.

Ces liens vous aideront à mieux connaître strcpy et strncpy Et où nous pouvons utiliser.

à propos de strcpy

à propos de strncpy

0
Prakash

Cela peut être utilisé dans de nombreux autres scénarios, dans lesquels vous ne devez copier qu'une partie de votre chaîne d'origine dans la destination. En utilisant strncpy (), vous pouvez copier une partie limitée de la chaîne d'origine, contrairement à strcpy (). Je vois que le code que vous avez mis en place provient de publib.boulder.ibm.com .

0
ARV