web-dev-qa-db-fra.com

Comment contourner l'avertissement de troncature de format dans GCC?

Je reçois l'avertissement de troncation de format gcc suivant:

test.c:8:33: warning: ‘/input’ directive output may be truncated writing 6 bytes into a region of size between 1 and 20 [-Wformat-truncation=]
snprintf(dst, sizeof(dst), "%s-more", src);
                             ^~~~~~
test.c:8:3: note: ‘snprintf’ output between 7 and 26 bytes into a destination of size 20
snprintf(dst, sizeof(dst), "%s-more", src);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sur le code comme ceci:

char dst[20];
char src[20];
scanf("%s", src);
snprintf(dst, sizeof(dst), "%s-more", src);
printf("%s\n", dst);

Je suis conscient du fait qu'il peut être tronqué - mais c'est exactement la raison pour laquelle j'utilise snprintf. Existe-t-il un moyen de faire comprendre au compilateur que cela est prévu (sans utiliser pragma ni troncation -Wno-format)?

4
Marius Melzer

  1. un avertissement a été introduit dans gcc7.1, voir Modifications de la version de gcc7.1 .
  2. De docs gcc

Le niveau 1 de -Wformat-truncation [...] met en garde uniquement à propos des appels aux fonctions liées dont la valeur de retour n'est pas utilisée et qui entraînera très probablement une troncature de la sortie.

  1. Le problème était un rapport de bogue et a été fermé en tant que NOTABUG:

La troncature de sortie non gérée est généralement un bogue du programme. [...]
Dans les cas où une troncature est attendue, l'appelant vérifie généralement la valeur de retour de la fonction et la gère d'une manière ou d'une autre (par exemple, en y créant une branche). Dans ces cas, l'avertissement n'est pas émis. La ligne source imprimée par l'avertissement suggère qu'il ne s'agit pas de l'un de ces cas. L'avertissement fait ce pour quoi il a été conçu.

  1. Mais nous pouvons simplement vérifier la valeur de retour de snprintf, qui renvoie une valeur négative en cas d'erreur.

#include <stdio.h>
#include <stdlib.h>
void f(void) {
    char dst[2], src[2];
    // snprintf(dst, sizeof(dst), "%s!", src);

    int ret = snprintf(dst, sizeof(dst), "%s!", src);
    if (ret < 0) {
         abort();
    }

    // But don't we love confusing one liners?
    for (int ret = snprintf(dst, sizeof(dst), "%s!", src); ret < 0;) exit(ret);
    // Can we do better?
    snprintf(dst, sizeof(dst), "%s!", src) < 0 ? abort() : (void)0;
    // Don't we love obfuscation?
#define snprintf_nowarn(...) (snprintf(__VA_ARGS__) < 0 ? abort() : (void)0)
    snprintf_nowarn(dst, sizeof(dst), "%s!", src);
}

Testé sur https://godbolt.org/ avec gcc7.1 gcc7.2 gcc7.3 gcc8.1 avec -O{0,1,2,3} -Wall -Wextra -pedantic. Ne donne aucun avertissement. gcc8.1 optimise/supprime l'appel à abort() avec une optimisation supérieure à -O1.

5
Kamil Cuk

Vous pouvez ajouter un spécificateur de précision. Ceci imprimera au plus 14 caractères de src en évitant une possible troncature de la chaîne de format et ne déclenchera pas cet avertissement:

snprintf(dst, sizeof(dst), "%.14s-more", src);

compilateur en ligne

1
VTT