Pourquoi utiliser Asprintf?

J’ai du mal à comprendre pourquoi vous auriez besoin d’asprintf. Ici dans le manuel il est dit

Les fonctions asprintf () et vasprintf () sont des analogues de sprintf (3) et vsprintf (3), sauf qu’elles allouent une chaîne suffisamment grande pour contenir la sortie, y compris l’octet nul final, et y renvoient un pointeur via le premier argument. . Ce pointeur doit être transmis à free (3) pour libérer le stockage alloué lorsqu’il n’est plus nécessaire.

Alors voici l’exemple que j’essaie de comprendre:

asprintf(&buffer, "/bin/echo %s is cool", getenv("USER")); 

Quelle est la différence si le tampon alloue une chaîne assez grande par rapport à dire char * = (chaîne)

Si vous utilisez sprintf () ou vsprintf (), vous devez d’abord allouer un tampon et vous devez vous assurer que le tampon est suffisamment grand pour contenir ce que sprintf écrit. Sinon, sprintf écrasera avec plaisir la mémoire située au-delà de la fin du tampon.

 char* x = malloc(5 * sizeof(char)); sprintf(x,"%s%s%s", "12", "34", "56"); // writes "123456" +null but overruns the buffer 

… écrit le ‘6’ et la terminaison null au-delà de la fin de l’espace alloué à x , soit en corrompant une autre variable, soit en provoquant une erreur de segmentation.

Si vous êtes chanceux, il va piétiner la mémoire entre les blocs alloués, et ne fera aucun mal – cette fois. Cela conduit à des bugs intermittents – les plus difficiles à diagnostiquer. Il est bon d’utiliser un outil comme ElecsortingcFence qui provoque des dépassements de délais.

Un utilisateur non malveillant qui fournit une entrée trop longue peut provoquer un comportement inattendu du programme. Un utilisateur mal intentionné pourrait exploiter cela pour obtenir son propre code exécutable dans le système.

Une garde contre cela est d’utiliser snprintf() , qui tronque la chaîne à la longueur maximale que vous fournissez.

 char *x = malloc(5 * sizeof(char)); int size = snprintf(x, 5, "%s%s%s", "12", "34", "56"); // writes "1234" + null 

La size valeur de retour est la longueur qui aurait été écrite si l’espace était disponible – sans la valeur de terminaison nulle .

Dans ce cas, si la size est supérieure ou égale à 5, vous savez que la troncature a eu lieu – et si vous ne voulez pas de troncature, vous pouvez allouer une nouvelle chaîne et essayer à nouveau snprintf() .

 char *x = malloc(BUF_LEN * sizeof(char)); int size = snprintf(x, 5, "%s%s%s", "12", "34", "56"); if(size >= BUF_LEN) { realloc(&x,(size + 1) * sizeof(char)); snprintf(x, 5, "%s%s%s", "12", "34", "56"); } 

(c’est un algorithme assez naïf, mais ça illustre bien le point)

asprintf() fait en une étape – calcule la longueur de la chaîne, alloue cette quantité de mémoire et y écrit la chaîne.

 char *x; int size = asprintf(&x, "%s%s%s", "12", "34", "56"); 

Dans tous les cas, une fois que vous avez terminé avec x vous devez le libérer ou vous perdez de la mémoire:

 free(x); 

asprintf() est un malloc() implicite, vous devez donc vérifier qu’il fonctionne, comme vous le feriez avec malloc() ou tout autre appel système.

 if(size == -1 ) { /* deal with error in some way */ } 

Notez que asprintf() fait partie des extensions GNU et BSD de libc – vous ne pouvez pas être sûr qu’il sera disponible dans tous les environnements C. sprintf() et snprintf() font partie des normes POSIX et C99.

L’avantage est la sécurité.

De nombreux programmes ont permis aux exploits du système de se produire en faisant déborder les tampons fournis par le programmateur lorsqu’ils sont remplis avec les données fournies par l’utilisateur.

Avoir asprintf allouer le tampon pour vous garantit que cela ne peut pas arriver.

Cependant, vous devez vérifier la valeur de retour de asprintf pour vous assurer que l’allocation de mémoire a bien réussi. Voir http://blogs.23.nu/ilja/2006/10/antville-12995/