95 votes

Quelles sont les fonctions C de la bibliothèque standard qui doivent / devraient-ils être évités?

J'ai lu sur stackoverflow que certaines fonctions C sont "obsolètes" ou devrait être "évité'. Pouvez-vous me donner quelques exemples de ce type de fonctions + la raison.

Quelles solutions de rechange de ces fonction existe ?

Peut-on les utiliser en toute sécurité - tout de bonnes pratiques ?

Plus tard edit: À partir des réponses:

  • obtient : peut provoquer des dépassements de tampon.
  • scanf : pour les chaînes qu'il serait préférable d'utiliser fgets (suivie d'une auto-analyse en utilisant sscanf ou strchr).
  • sprintf (au lieu d'utiliser snprintf)
  • strcat : éviter lorsque vous traitez avec la saisie de l'utilisateur (au lieu d'utiliser strncat, même si strncat a ses pièges.)
  • strcpy : éviter lorsque vous traitez avec la saisie de l'utilisateur (au lieu d'utiliser strncpy, même si strncopy a ses pièges.)
  • strtok : n'est pas thread-safe.

60voto

Michael Aaron Safyan Points 45071

Obsolète Fonctions
L'insécurité
Un parfait exemple d'une telle fonction gets(), car il n'y a aucun moyen de savoir comment big le tampon de destination est. Par conséquent, tout programme qui prend en entrée à l'aide de gets() a une vulnérabilité de dépassement de tampon. Pour des raisons similaires, on devrait utiliser strncpy() à la place de la fonction strcpy() et strncat() à la place de strcat().

Encore d'autres exemples comprennent la tmpfile() et mktemp() fonction en raison de problèmes de sécurité potentiels avec d'écraser les fichiers temporaires et qui sont remplacées par le plus sécurisé mkstemp() fonction.

Non Réentrant
D'autres exemples comprennent gethostbyaddr() et gethostbyname() , qui sont non réentrant (et, par conséquent, de ne pas être thread-safe) et ont été remplacés par le réentrant getaddrinfo() et freeaddrinfo().

Vous avez peut-être remarqué un modèle ici... soit le manque de sécurité (éventuellement en omettant d'inclure suffisamment d'informations dans la signature, éventuellement, de mettre en œuvre de manière sécurisée) ou non réentrance sont des sources communes de la dépréciation.

Obsolète, Non Portable
Quelques autres fonctions simplement devenu obsolète car ils font double emploi avec les fonctionnalités et ne sont pas aussi portable que d'autres variantes. Par exemple, bzero() est dépréciée en faveur de memset().

Fil de Sécurité et de re-ouverture
Vous avez demandé, dans votre post, à propos de la sécurité des threads et de la re-ouverture. Il y a une légère différence. Une fonction est réentrant si elle n'utilise pas tout partagé, mutable état. Ainsi, par exemple, si toutes les informations dont il a besoin est transmis à la fonction, et toutes les tampons nécessaires sont également transmis à la fonction (plutôt que partagée par tous les appels à la fonction), puis il est réentrant. Cela signifie que les différents threads, en utilisant des paramètres indépendants, ne risque pas accidentellement l'état de partage. La réentrance est un renforcement de la garantie de la sécurité des threads. Une fonction est thread-safe si elle peut être utilisée par plusieurs threads simultanément. Une fonction est thread-safe si:

  • Il est réentrant (c'est à dire qu'il ne partage pas tout de l'état entre les appels), ou:
  • Il est non réentrant, mais il utilise la synchronisation/verrouillage comme nécessaire pour l'état partagé.

En général, dans la Single UNIX Specification et IEEE 1003.1 (c'est à dire "POSIX"), toute fonction qui n'est pas garanti d'être réentrant n'est pas garanti d'être thread-safe. Donc, en d'autres termes, seules les fonctions qui sont garantis d'être réentrant peut-être de façon portable utilisé dans les applications multithread (sans verrouillage externe). Cela ne signifie pas, cependant, que les implémentations de ces normes ne peuvent pas choisir de faire un non-fonction réentrante des threads. Par exemple, Linux ajoute fréquemment la synchronisation non-fonctions réentrantes afin d'ajouter une garantie (au-delà de celle de la Single UNIX Specification) de threadsafety.

Des chaînes de caractères (et de la Mémoire tampon, en Général)
Vous m'avez également demandé si il y a un vice fondamental de cordes/tableaux. Certains diront que c'est le cas, mais je dirais que non, il n'y a pas de faille fondamentale dans la langue. C et C++ vous obliger à passer la longueur/la capacité d'un tableau séparément (ce n'est pas une ".la longueur de la propriété" comme dans quelques autres langues). Ce n'est pas un défaut, per se. Tout le C et le C++ développeur peut écrire du code correct, tout simplement en passant la longueur comme un paramètre en cas de besoin. Le problème est que plusieurs Api que nécessaire, cette information a omis de spécifier que c'est un paramètre. Ou supposé que certains MAX_BUFFER_SIZE constante serait utilisé. Ces Api sont maintenant obsolètes et remplacés par d'autres Api qui permettent le tableau/tampon/string taille spécifiée.

Scanf (En Réponse à Votre Dernière Question)
Personnellement, j'utilise le C++ iostreams bibliothèque (std::cin, std::cout << et >> les opérateurs, std::getline, std::istringstream, std::ostringstream, etc.), donc je n'ai généralement pas le gérer. Si je ont été forcés à utiliser pur C, si, je serais personnellement utiliser fgetc() ou getchar() en combinaison avec strtol(), strtoul(), etc. et d'analyser les choses manuellement, puisque je ne suis pas un grand fan de varargs ou des chaînes de format. Cela dit, à ma connaissance, il n'y a pas de problème avec [f]scanf(), [f]printf(), etc. aussi longtemps que vous le métier de chaînes de format vous-même, vous ne laissez jamais passer arbitraire des chaînes de format ou de permettre l'entrée d'utilisateur pour être utilisés comme des chaînes de format, et que vous utilisez la mise en forme des macros définies dans <inttypes.h> le cas échéant. (Remarque, snprintf() doit être utilisé à la place de sprintf(), mais qui a à voir avec omettant de spécifier la taille de la mémoire tampon de destination et non pas de l'utilisation de chaînes de format). Je tiens également à souligner que, en C++, boost::format fournit printf comme le formatage sans varargs.

24voto

Dipstick Points 4869

Encore une fois, les gens de répéter des mantras, le ridicule affirmation que la version "n" de str fonctions sont des versions sûres.

Si c'était ce à quoi ils étaient destinés à des fins alors qu'ils seraient toujours null mettre fin à la les chaînes.

Le "n" versions de l'fonctions ont été écrites pour une utilisation avec des champs de longueur fixe (tels que les entrées de répertoire au début de systèmes de fichiers) où le nul de terminaison est nécessaire uniquement si la chaîne de ne pas remplir le champ. C'est aussi la raison pour laquelle les fonctions ont des effets secondaires étranges qui sont inutilement inefficace si seulement utilisé en remplacement - prendre strncpy() par exemple:

Si le tableau pointé par s2 est un chaîne plus courte que n octets, des octets nuls sont annexées à la copie le tableau pointé par s1, jusqu'à ce que n d'octets dans tous sont écrits.

Comme les tampons alloués pour gérer les noms de fichiers sont généralement 4kbytes cela peut conduire à une détérioration massive de la performance.

Si vous voulez "soi-disant" sûr versions puis obtenir de l'écriture ou de votre propre strl routines (strlcpy, strlcat etc) qui ont toujours nul résilier les cordes et n'ont pas d'effets secondaires. Merci de noter que ce ne sont pas vraiment sûr que ils peuvent silencieusement tronquer la chaîne - ce qui est rarement le meilleur cours de l'action dans tout monde réel programme. Il y a des moments où c'est OK, mais il y a aussi de nombreux cas où elle pourrait conduire à des résultats catastrophiques (par exemple, l'impression de prescriptions médicales).

20voto

Michael Burr Points 181287

Plusieurs réponses ici vous suggérons d'utiliser strncat() sur strcat(); je proposerais que strncat() (et strncpy()) devraient également être évités. Il y a des problèmes qui font qu'il est difficile à utiliser correctement et entraîner des bugs:

  • le paramètre de durée d' strncat() est liée à l' (mais pas tout à fait exactement - voir le 3ème point) le nombre maximum de caractères qui peuvent être copiés vers la destination plutôt que la taille de la mémoire tampon de destination. Cela rend strncat() plus difficile à utiliser que ce qu'il devrait être, en particulier si plusieurs éléments seront concaténés à la destination.
  • il peut être difficile de déterminer si le résultat a été tronqué (qui peut ou peut ne pas être important)
  • il est facile d'avoir un tout-en-un message d'erreur. Comme le standard C99 notes, "Ainsi, le nombre maximum de caractères qui peuvent se retrouver dans le tableau pointé par s1 est strlen(s1)+n+1" pour un appel qui ressemble strncat( s1, s2, n)

strncpy() a aussi un problème qui peut provoquer des bugs que vous essayez de l'utiliser de manière intuitive - il ne garantit pas que la destination est null. Pour vous assurer que vous avez à faire assurez-vous de traiter spécifiquement de ce coin de cas par la chute d'un '\0' dans le tampon du dernier endroit où vous-même (au moins dans certaines situations).

Je vous suggère d'utiliser quelque chose comme OpenBSD strlcat() et strlcpy() (même si je sais que certaines personnes n'aiment pas ces fonctions; je crois qu'ils sont beaucoup plus faciles à utiliser en toute sécurité qu' strncat()/strncpy()).

Voici un peu de ce que Todd Miller et Theo de Raadt avait à dire à propos de problèmes avec strncat() et strncpy():

Il y a plusieurs problèmes rencontrés lors de l' strncpy() et strncat() sont utilisés comme des versions sûres d' strcpy() et strcat(). Les deux fonctions de traiter de NUL-résiliation et les paramètres de longueur différentes et non intuitive des moyens qui confondent encore les programmeurs expérimentés. Ils fournissent également pas facile à détecter lorsque la troncature se produit. ... De toutes ces questions, la confusion causée par les paramètres de longueur et la question connexe de NUL de terminaison sont les plus importants. Lorsque nous avons vérifié les sources d'OpenBSD pour les failles de sécurité potentielles, nous avons trouvé les abus rampante de l' strncpy() et strncat(). Bien que pas tous ces abouti à des trous de sécurité exploitables, ils ont clairement fait savoir que les règles d'utilisation strncpy() et strncat() sécuritaire des opérations de la chaîne sont largement méconnu.

OpenBSD de sécurité de la vérification a permis de constater que des bugs avec ces fonctions ont été "rampante". Contrairement aux gets(), ces fonctions peuvent être utilisées en toute sécurité, mais dans la pratique, il y a beaucoup de problèmes, car l'interface est confuse, peu intuitive et difficile à utiliser correctement. Je sais que Microsoft a également fait l'analyse (même si je ne sais pas combien de leurs données, ils peuvent avoir publié), et comme un résultat ont interdit (ou au moins très fortement déconseillé de - la 'ban' peut ne pas être absolue) de l'utilisation de strncat() et strncpy() (entre autres fonctions).

Certains liens avec plus d'informations:

7voto

Eli Bendersky Points 82298

Certaines personnes prétendent que le strcpy et strcat doit être évitée, en faveur de l' strncpy et strncat. C'est un peu subjectif, à mon avis.

Ils devraient certainement être évitée lorsque vous traitez avec la saisie de l'utilisateur - pas de doute ici.

Dans le code "loin" de l'utilisateur, lorsque vous savez juste les tampons sont assez longs, strcpy et strcat peut-être un peu plus efficace, car le calcul de l' n pour passer à leurs cousins peut-être superflu.

6voto

codaddict Points 154968

Éviter

  • strtok pour les programmes multithread comme sa pas thread-safe.
  • gets , car cela peut provoquer de dépassement de tampon

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X