IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Analyse statique : problème de unbound sprintf


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de transgohan
    Homme Profil pro
    Développeur Temps réel Embarqué
    Inscrit en
    Janvier 2011
    Messages
    3 149
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Temps réel Embarqué

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3 149
    Par défaut Analyse statique : problème de unbound sprintf
    Bonjour,

    je rencontre un problème lors de l'analyse d'un défaut de code.
    Nous utilisons klocwork pour les analyses de code statique et il me remonte une erreur sur le code suivant :
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    char chaine[5];
    unsigned char i = 10;
    sprintf(chaine, " %02d ", i);

    Je tourne chèvre... Vous êtes bien d'accord qu'on ne peut pas dépasser la taille du buffer ? (unbound sprintf)
    Ou bien j'ai loupé un truc dans le fonctionnement du sprintf ?

    Car si c'est le cas je m'oriente vers un bug klocwork qui n'interprète pas correctement le %02d (ça va être sympa à justifier au client...).

    Note : pas de snprintf dans ma bibliothèque.

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Salut
    Citation Envoyé par transgohan Voir le message
    Vous êtes bien d'accord qu'on ne peut pas dépasser la taille du buffer ? (unbound sprintf)
    Hé non, je ne suis pas d'accord
    Le "%02d" va demander un complément avec des "zéros" pour remplir 2 digits si le nombre n'en fait qu'un (ex 3 est affiché "03") mais ne tronque absolument pas un nombre qui en ferait plus. Et donc si "i" vaut 255 (unsigned char) il reste affiché "255". Plus l'espace avant plus l'espace après cela fait 5 caractères. Et si on rajoute le '\0', tout ça à stocker dans un char [5].
    En plus (enfin là c'est juste une hypothèse), le "%d" demande à printf() de considérer cet argument comme un int donc entre (au mieux) -32768 et 32767, soit déjà 6 caractères avec le "-", plus un 7° avec le '\0' et (oserais-je te rappeler qu'il y a aussi des espaces ? ) tout ça dans un char [5] donc possible que klocwork arrive à une conclusion équivalente sans se préoccuper de la nature "char" de "i" =>
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre Expert
    Avatar de transgohan
    Homme Profil pro
    Développeur Temps réel Embarqué
    Inscrit en
    Janvier 2011
    Messages
    3 149
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Temps réel Embarqué

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3 149
    Par défaut
    Merci de cet éclairage bienvenu Sve@r !
    Tellement peu l'habitude de travailler avec cette fichue fonction que j'ai mal interprété la spécification de format...

    Du coup je me suis dit que j'allais tester ceci :
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    char chaine[5];
    unsigned char i = 10;
    sprintf(chaine, " %02d ", i % 99);
    2 (espaces) + 2 (taille i) + 1 (\0) = 5
    C'est crade (perte potentielle d'information, même si dans mon cas on ne pourra effectivement pas avoir plus de 99) et en plus ça marche pas...

    Je suis toujours mal éclairé ou tu es d'accord avec ma correction ?

    Autre test pour tenter de comprendre même si cela n'apporte rien à mon code :
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    char chaine[5];
    unsigned char i = 10;
    if( i < 100 )
    {
       sprintf(chaine, " %02d ", i);
    }
    Défaut toujours présent...
    Là j'ai vraiment l'impression qu'il s'en fiche et qu'il traite le défaut d'une manière générale...
    Pourtant pour les défauts de dépassement mémoire sur les tableaux il sait très bien interpréter les branches de condition...
    J'ai l'impression qu'il ne le fait pas pour les paramètres d'entrée du sprintf...

    Je vais finir par lui affecter octet par octet si je trouve pas de solution lisible...

  4. #4
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    Nous utilisons klocwork pour les analyses de code statique et il me remonte une erreur sur le code suivant
    Il faut toujours rester prudent sur les analyseurs statiques. Ils sont écrits pas des humains et ont aussi leur limite. Ce que tu demandes n'est pas forcément trivial (la preuve, tu as demandé sur un forum et on t'a donné une explication bien plus longue que ce que tu pensais obtenir).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    char chaine[5];
    unsigned char i = 10;
    if( i < 100 )
    {
       sprintf(chaine, " %02d ", i);
    }
    Ici, l'analyse est relativement simple pour un humain, mais pas forcément pour un algorithme. Souvent, les analyseurs statiques ont du mal à avoir autant de contexte sur une ligne.

    C'est aussi pour ça que tous (?) les analyseurs ont des possibilités pour ignorer certains warnings (soit avec une option pour supprimer toutes les vérifications d'une règle, soit pour marquer une ligne particulière de ton code comme étant un "faux-positif").

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par transgohan Voir le message
    C'est crade (perte potentielle d'information, même si dans mon cas on ne pourra effectivement pas avoir plus de 99) et en plus ça marche pas...
    Je suis toujours mal éclairé ou tu es d'accord avec ma correction ?
    Je suis d'autant plus d'accord que j'étais arrivé au même résultat. Je pensais en effet qu'un modulo (i%100 en réalité si tu veux conserver les valeurs entre 0 et 99 inclus) serait la bonne idée si chaine ne peut pas grandir.

    Alors j'ai une autre hypothèse: le "%d" demande un nombre signé, c'est à dire avec le signe "-" s'il est nécessaire. De là, un nombre négatif même à 2 chiffres occupera 3 espaces, plus les deux espaces et le '\0' et on dépasse 5. Enfin je reproduis là ce que pourrait penser klocwork. Donc déjà moi je mettrais "%02hu" (le "h" c'est une habitude chez-moi de toujours affiner le format mais "%02u" devrait pouvoir faire l'affaire). Et si vraiment ce con ne pige toujours pas, alors rajouter un cast ce qui donnerait sprintf(chaine, " %02hu ", (unsigned char)(i%100)). Tu peux aussi tenter la même chose avec ton second code en remplaçant if (i < 100) par if (i >= 0 && i < 100).

    Citation Envoyé par transgohan Voir le message
    Je vais finir par lui affecter octet par octet si je trouve pas de solution lisible...
    Alors dans ce cas essayer de travailler à l'envers et trouver à partir de combien klocwork est content. Donc essayer char chaine[10], puis char chaine[20] etc. Une fois trouvé, un sprintf() dans une chaine temporaire calée à la taille qui lui convient complété au final d'un strncpy() dans la vraie char chaine[5]. Sans oublier le commentaire adéquat pour que les autres comprennent le but de la manoeuvre.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  6. #6
    Membre Expert
    Avatar de transgohan
    Homme Profil pro
    Développeur Temps réel Embarqué
    Inscrit en
    Janvier 2011
    Messages
    3 149
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Temps réel Embarqué

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3 149
    Par défaut
    Bon beh tout remplacement effectué donne le même résultat...
    Si quelqu'un pense à autre chose je prends !

    C'est aussi pour ça que tous (?) les analyseurs ont des possibilités pour ignorer certains warnings (soit avec une option pour supprimer toutes les vérifications d'une règle, soit pour marquer une ligne particulière de ton code comme étant un "faux-positif").
    C'est pas le plus compliqué en effet de tagguer comme faux-positif les 52 défauts.
    Le plus compliqué c'est l'exigence cliente qui fait que pour chaque faux-positif je dois rédiger un rapport avec test exécutable prouvant qu'il n'y a pas de défaut...
    Bref du temps bien employé... Et bien sûr un rapport+test par défaut, même si ce sont les mêmes...

    C'est pour cela que je cherche par tout moyen à virer un maximum de défaut quitte à provoquer une mauvaise analyse dans certains cas pour que le défaut ne soit pas visible.

    Alors dans ce cas essayer de travailler à l'envers et trouver à partir de combien klocwork est content.
    Je n'ai pas ce luxe de mémoire RAM.
    Il me reste moins de 1ko de mémoire disponible et j'ai encore des évolutions à venir.
    Et je n'ai pas non plus accès à strncpy().

    La joie des très vieux projets embarqués.

  7. #7
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Bonjour,

    un tableau de 5 caractères prend exactement la même place qu'un tableau de 6 caractères car ici il doit être aligné avec la pile.
    Ne peux-tu pas essayer d'utiliser la valeur char chaine[5+1];, avec le sprintf( chaine, " %02hu ", i ); ça pourrait marcher.

Discussions similaires

  1. Analyser statique et analyser dynamique
    Par solar dans le forum C
    Réponses: 10
    Dernier message: 02/05/2011, 10h01
  2. Outil d'analyse statique du code PLSQL
    Par BREMARD dans le forum PL/SQL
    Réponses: 0
    Dernier message: 17/12/2008, 14h51
  3. Analyse statique de code
    Par Bayard dans le forum Analyse de code
    Réponses: 6
    Dernier message: 22/10/2007, 11h07
  4. Outils d'analyse statique
    Par Bayard dans le forum Autres éditeurs
    Réponses: 0
    Dernier message: 12/10/2007, 07h10
  5. Outils d'analyse statique de code assembleur ?
    Par atomic dans le forum Assembleur
    Réponses: 4
    Dernier message: 11/06/2004, 11h42

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo