66 votes

C est "mauvais" fonctions contre leurs "bonnes" solutions de rechange"

Quels sont les "mauvais" de fonctions en C, et quelles sont leurs "bonnes" solutions de rechange?

Pourquoi le mauvais est mauvais, et ce qui fait les bons de mieux?

Je sais, par exemple, gets() "mauvaise" car il n'a pas toute forme de vérification des limites. Quelle est sa meilleure alternative? fgets()?

Je l'ai entendu, scanf() qui est mauvais, mais je ne me souviens pas pourquoi. Tout le monde sait? Quelle est la meilleure alternative?

Existe-t-il?

48voto

Adam Batkin Points 20920

Dans les vieux jours, la plupart des fonctions de chaîne n'avait pas de vérification des limites. Bien sûr ils ne pouvaient pas juste supprimer les anciennes fonctions, ou de modifier leurs signatures afin d'inclure une limite supérieure, qui permettrait de casser la compatibilité. Maintenant, pour la presque totalité de ces fonctions, il existe une autre version "n". Par exemple:

strcpy -> strncpy
strlen -> strnlen
strcmp -> strncmp
strcat -> strncat
strdup -> strndup
sprintf -> snprintf
wcscpy -> wcsncpy
wcslen -> wcsnlen

Et de plus en plus.

Edit 2013-12-03:

Voir aussi https://github.com/leafsr/gcc-poison c'est un projet pour créer un fichier d'en-tête qui provoque la gcc pour signaler une erreur si vous utilisez une mauvaise fonction.

36voto

caf Points 114951

Oui, fgets( , , STDIN) est une bonne alternative aux gets(), parce qu'il prend un paramètre de taille.

scanf() est considérée comme problématique dans certains cas, plutôt que de tout droit sortie de "mal", parce que si l'entrée n'est pas conforme au format attendu qu'il peut être impossible de récupérer judicieusement (il ne vous laisse pas rembobiner la saisie et essayez à nouveau). Si vous pouvez simplement abandonner sur une mauvaise mise en forme d'entrée, il est utilisable. Une "meilleure" alternative ici est d'utiliser une fonction d'entrée comme fgets() ou fgetc() pour lire les morceaux de l'entrée, puis l'analyser avec sscanf() ou de l'analyser avec la manipulation des chaînes de fonctions comme strchr() et strtol(). Voir aussi ci-dessous pour un problème spécifique avec le "%s" spécificateur de conversion dans le scanf().

Ce n'est pas une norme en fonction de C, mais la BSD et POSIX fonction mktemp() est généralement impossible à utiliser en toute sécurité, car il y a toujours une condition de concurrence entre les tests pour le fichier de l'existence et de la création. mkstemp() ou tmpfile() sont de bons substituts.

strncpy() est un peu délicate fonction, car il n'est pas nul à la fin de la destination, si il n'y avait pas de place pour elle. Vous pouvez contourner ce soit par l'ajout de nul-terminator à votre destination, ou la définition de la destination à une chaîne vide à l'aide de strncat() à la place.

atoi() peut être un mauvais choix dans certaines situations, parce que vous ne pouvez pas dire quand il y a une erreur de faire la conversion (par exemple. si le nombre de dépassement de la plage d'un int). Utilisation strtol() si c'est important pour vous.

strcpy(), strcat() et sprintf() souffrent d'un problème similaire à gets() - ils ne vous permet pas de spécifier la taille de la mémoire tampon de destination. Il est toujours possible, au moins en théorie, pour une utilisation en toute sécurité - mais vous êtes beaucoup mieux d'utiliser strncat() et snprintf() à la place (vous pouvez utiliser strncpy(), mais voir ci-dessus). Sur le même thème, si vous utilisez le scanf() de la famille de fonctions, de ne pas utiliser un simple "%s" - spécifier la taille de la destination, par exemple. "%200s".

20voto

Dave Markle Points 44637

strtok() est généralement considéré comme le mal, car il stocke les informations d'état entre les appels. N'essayez pas de course QUE dans un environnement multithread!

11voto

Secure Points 2838

Strictement parlant, il est vraiment dangereux de la fonction. Il est gets() parce que son entrée n'est pas sous le contrôle du programmeur. Toutes les autres fonctions mentionnées ici sont sûrs d'eux-mêmes. Les "bons" et "mauvais" se résume à une programmation défensive, à savoir les préconditions, postconditions et de code réutilisable.

Prenons la fonction strcpy() par exemple. Il a certaines conditions pour que le programmeur doit s'acquitter avant l'appel de la fonction. Les deux chaînes doivent être valides, non pointeurs NULL à zéro des chaînes terminées, et la destination doivent fournir suffisamment d'espace avec une finale de longueur de chaîne à l'intérieur de la gamme de size_t. En outre, les deux chaînes ne sont pas autorisés à se chevaucher.

Qui sont tout à fait beaucoup de conditions préalables, et aucune d'elles est contrôlée par la fonction strcpy(). Le programmeur doit s'assurer qu'elles sont remplies, ou il doit explicitement les tester avec d'autres code réutilisable avant d'appeler la fonction strcpy():

n = DST_BUFFER_SIZE;
if ((dst != NULL) && (src != NULL) && (strlen(dst)+strlen(src)+1 <= n))
{
    strcpy(dst, src);
}

Déjà silencieusement en supposant que le non-recouvrement et à zéro des chaînes terminées.

strncpy() ne comprennent certaines de ces vérifications, mais il ajoute une autre postcondition le programmeur doit prendre soin, après l'appel de la fonction, parce que le résultat peut ne pas être égale à zéro terminée.

strncpy(dst, src, n);
if (n > 0)
{
    dst[n-1] = '\0';
}

Pourquoi ces fonctions considéré comme "mauvais"? Car ils auront besoin supplémentaire de code réutilisable pour chaque appel à vraiment être sur le côté sûr, lorsque le programmeur suppose tort à propos de la validité, et les programmeurs ont tendance à oublier ce code.

Ou même de s'y opposer. Prendre le printf() de la famille. Ces fonctions renvoient un état qui indiquent l'erreur et de succès. Qui vérifie si la sortie vers stdout ou stderr réussi? Avec l'argument que vous ne pouvez pas faire quoi que ce soit quand le standard des canaux ne sont pas de travail. Eh bien, ce sujet rescueing les données de l'utilisateur et de terminer le programme avec une erreur indiquant un code de sortie? Au lieu de la solution de rechange possible de crash et brûler, plus tard, de corruption des données de l'utilisateur.

Dans un temps et de l'argent limitée de l'environnement, il est toujours la question de savoir combien de filets de sécurité que vous voulez vraiment et quel est le pire scénario? Si c'est un dépassement de tampon dans le cas de la str-fonctions, alors il est logique de les interdire et probablement fournir des fonctions wrapper avec les filets de sécurité déjà à l'intérieur.

Une dernière question à ce sujet: Ce qui fait de vous assurer que vos "bonnes" solutions de rechange sont vraiment bon?

7voto

Mitch Wheat Points 169614

Une fonction qui ne prend pas en prendre un maximum de paramètres de longueur et repose plutôt sur la fin-de - marqueur à être présent (comme beaucoup de "chaîne" des fonctions de gestion).

Toute méthode qui gère l'état entre les appels.

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