Le code suivant provoque une erreur et tue ma demande. Il est logique que le tampon ne soit que 10 octets longs et le texte est de 22 octets long (débordement tampon).
length = _snprintf_s( buffer, 10, 9, "123456789" ); printf( "1) Length=%d\n", length ); // Length == 9 length = _snprintf_s( buffer, 10, 9, "1234567890.1234567890." ); printf( "2) Length=%d\n", length ); // Length == -1 length = _snprintf_s( buffer, 10, 10, "1234567890.1234567890." ); printf( "3) Length=%d\n", length ); // Crash, it needs room for the NULL char
6 Réponses :
de MSDN: P>
L'autre différence principale entre SprintF_S et Sprintf est que SprintF_S prend un paramètre de longueur spécifiant la taille du tampon de sortie dans des caractères. Si le tampon est trop petit pour que le texte soit imprimé, le tampon est défini sur une chaîne vide et le gestionnaire de paramètres non valide est invoqué. Contrairement à Snprintf, Sprintf_S garantit que la mémoire tampon sera terminée (sauf si la taille de la mémoire tampon n'est nulle). P>
si idéalement ce que vous avez écrit devrait fonctionner correctement. p>
Le "gestionnaire de paramètres non valide par défaut termine le processus.
vrai, mais il est facile d'installer un qui ne fait pas, ce qui entraîne Sprintf_s renvoyant -1 si le tampon est trop petit
On dirait que vous écrivez sur MSVC de quelque sorte? P>
Je pense que les documents MSDN pour Sprintf_s indiquent qu'il affirme que les matrices, alors je ne suis pas trop sûr si vous pouvez attraper par programme cela. P>
Comme Lbushkin suggérait, vous êtes beaucoup mieux à l'aide de classes qui gèrent les cordes. P>
C'est par conception. Le point entier de sprintf_s code> et d'autres fonctions à partir de la famille * _ s code> est d'attraper des erreurs de dépassement de tampon et de les traiter comme violations de condition préalable em>. Cela signifie qu'ils ne sont pas vraiment destinés à être récupérables. Ceci est conçu pour attraper des erreurs seulement - vous ne devriez jamais appeler sprintf_s code> si vous savez que la chaîne peut être trop grande pour un tampon de destination. Dans ce cas, utilisez le Strlen CODE> pour vérifier et décider si vous devez couper. P>
Je ne suis pas d'accord. Il est tout à fait raisonnable d'appeler Sprintf_s avec un tampon de destination trop petit, tant que vous utilisez le drapeau _trunate pour indiquer cela. D'accord, techniquement _trunate nécessite d'utiliser SnPrintf_S au lieu de Sprintf_s, mais mon point est essentiellement debout. L'utilisation de SHLEN est souvent inapplicable ou peu pratique, mais en utilisant _trunate est souvent triviale et appropriée.
Je pense que l'utilisation de snprintf_s code> est la différence cruciale, et pas vraiment une simple technicité.
C'est une différence cruciale, définitivement. Mais je pense que votre réponse montre que la famille de fonctions _s ne peut pas tronquer, ce qui pourrait être trompeur.
Oui, vous ne devriez jamais faire une erreur de codage, puis il n'y aurait pas besoin d'exceptions. Ce n'est pas évident mais vous devez remplacer le gestionnaire d'erreur par défaut pour les fonctions d'exécution C. Vous pouvez les gérer à mesure que vous vous voulez, y compris en jetant votre propre exception. Voir _set_invalid_parameter_handler lien et réponse de Jonathon Leffler.
Voir la section 6.6.1 de TR24731 A> qui est le ISO C Comité version de la fonctionnalité mise en œuvre par Microsoft . Il fournit des fonctions Il y a des commentaires de Pavel Minaev suggérant que la mise en œuvre de Microsoft n'adhère pas à la proposition TR24731 (qui est un rapport technique de type 2), de sorte que vous ne pourrez peut-être pas intervenir, ou vous devrez peut-être faire quelque chose de différent. de ce que le TR indique devrait être fait. Pour cela, scruthize MSDN. P> set_constraintore_handler () code>, abort_constraintore_handler () code> et ignore_constraintore_handler () code> fonctions. P>
Malheureusement, MSVC ne met pas en œuvre TR24731 entièrement - en particulier, il ne met pas en œuvre spécifiquement les fonctions que vous faites référence (également que leurs noms se terminent également par _s code> - i.e. set_constraint_handler_s code>).
Mais selon msdn.microsoft.com/en-us /Library/ksazx244%28Vs.80%29.aspx Il existe une fonction fonction _set_invalid_parameter_handler () qui peut être utilisée pour modifier le comportement par défaut d'abandonner le programme.
au lieu de sprintf_s code>, vous pouvez utiliser snaprintf code> (alias _snprintf code> sous Windows).
Remarque: comme une question de sécurité, s'il n'y a pas assez de place, le contenu de la mémoire tampon pourrait ne pas être résilié par NULL.
@Managu: Si la SEP a réclamé la conformité à C99 - que ce n'est pas - que l'affirmation serait faux; La norme C99 nécessite SNPRINTF () à NULL, résiliant la chaîne, à moins que la longueur de la chaîne ne soit égale à 0. Section 7.19.6.5: Si N est nulle, rien n'est écrit ... sinon, les caractères de sortie au-delà du N-1st sont supprimés plutôt que Écrit dans le tableau et un caractère nul est écrit à la fin des caractères réellement écrits dans le tableau. Si la copie a lieu entre des objets qui se chevauchent, le comportement est indéfini.
@Managu Veuillez éditer votre réponse pour supprimer la suggestion d'utiliser _snprintf. C'est une suggestion incroyablement dangereuse.
VC ++ 2015 prend en charge SNPRINTF, de sorte que cela puisse maintenant être utilisé. N'utilisez pas _snprintf comme c'est différent. Mais pour une sécurité réelle (pour éviter les problèmes de spécification incorrecte de la taille de la mémoire tampon) US Sprintf_s ou SnPrintf_s (voir les réponses ci-dessous).
Ceci fonctionne avec VC ++ et est encore plus sûr que d'utiliser SnApRintf (et certainement plus sûr que _snprintf): L'indicateur _trunate indique que la chaîne doit être tronquée. Dans ce formulaire, la taille du tampon n'est pas réellement transmise, qui (paradoxalement!) Est ce qui le rend si sûr. Le compilateur utilise la magie du modèle pour déduire la taille du tampon, ce qui signifie qu'il ne peut pas être spécifié de manière incorrecte (une erreur étonnamment courante). Cette technique peut être appliquée pour créer d'autres emballages de cordes sécurisés, comme décrit dans mon article de blog ici:
https://randomascii.wordpress.com/2013/04/ 03 / Stop-with-strncpy-déjà / p> p>
En regardant la documentation MSDN de _SNPRINTF_S, il apparaît que vous avez oublié un argument dans l'appel à _SNPRINTF_S. Cet argument doit apparaître entre tampon et _trunate et appelézeofbuffer
Je n'ai pas oublié un argument - ce code compile et est parfaitement sûr. Vous devez relire la documentation. Je fais une utilisation d'un modèle de remplacement sur _snprintf_s qui indique au compilateur d'inférer la taille de la mémoire tampon. J'ai vu des centaines d'endroits où les programmeurs ont explicitement transmis une taille de tampon et sont passés dans la taille mal i>. Seulement en demandant au compilateur, la taille de la mémoire tampon peut être évitée. J'ai fait allusion à cette technique dans l'article que j'ai lié à ma solution. Vivement recommandé.
Passer la taille de la mémoire tampon et la taille de la mémoire tampon moins l'un est obtuse et l'erreur sujette. Vous devez préférer la variante que je décris ci-dessous: longueur = _snprintf_s (tampon, _trunate, "1234567890.1234567890."); Étant donné que le premier paramètre de taille est omis, le compilateur utilise la surcharge de gabarit qui déduit la taille. _Trunate est une valeur spéciale qui fait ce qu'elle dit. Pas de chiffres magiques, et maintenant votre code est sécuritaire, maintenu et un bon exemple. Si vous aimez ce commentaire et _snprintf_s, vous devez sélectionner ma réponse, au lieu de la réponse dangereuse SNPRINTF / _SNPRINTF.