L’analyse de code C++ dans Visual Studio 2012 : un outil puissant

Read this post in english

lots-of-crashes

Le problème avec ce genre de message, c’est qu’il décourage un client d’utiliser une application. Si ça se passe pendant la période d’essai d’un logiciel ?

L’analyse de code est l’un des remèdes à ce genre de problème.

L’analyse de code examine le code lors de la compilation pour trouver les causes des bugs avant qu’ils ne se produisent chez un client. C’est un outil supplémentaire pour déboguer une application, et vient en complément des procédures de test habituelles (tests fonctionnels, tests unitaires…) Elle trouve des bugs lors de la compilation en recherchant dans le code des patterns produisant des bugs.

L’analyse de code est l’un des outils permettant de développer des applications plus sures que Microsoft met à disposition des développeurs. Elle est fait partie de la méthodologie Microsoft SDL (Security Development Lifecycle, ou Sécuriser les Développements Logiciels).

L’analyseur sait quels bugs vous allez créer, et les recherche dans votre code ! Par exemple :

  • déréférencement de pointeurs nuls
  • débordement de buffer
  • utilisation de variables non initialisées
  • fuites de mémoire
  • problèmes d’accès concurrent

L’analyse de code C++ dans Visual C++ 2012 et les MFC

 

L’équipe qui a créé l’analyse de code C++ s’est basé sur l’immense base de code de Windows. Ils savent quel type de code est sûr, et quel type de code peut provoquer un crash !

L’analyse de code de Visual Studio 2010 était seulement incluse dans les versions Premium et Ultimate. Mais Microsoft a pensé qu’il était important d’aider le plus de monde possible à utiliser ces outils, alors certaines règles d’analyse de code sont d’ores et déjà incluses dans Visual Studio 11 Express, et la totalité des 200+ règles seront dans les versions Professionnelles et Ultimate de Visual Studio 11.

L’analyse de code C++ dans Visual Studio 11 a été améliorée de deux façons : elle est plus facile à utiliser, notamment grâce à la nouvelle fenêtre Code Analysis, plus puissante, plus lisible (messages plus explicites) et les problèmes signalés sont plus pertinents. Les règles sont améliorées, et couvrent un éventail de code plus large, notamment le multitâche, et bientôt le support de la compilation 64 bits.

Visual Studio 11 Developer Preview, une pré-version du prochain Visual Studio, permet déjà d’utiliser l’analyse de code et ses pièges à bugs, sous Windows 7. Visual Studio 11 est le nom temporaire de la version qui succèdera à Visual Studio 2010. Il n’est disponible qu’en anglais pour l’instant.

Lorsqu’on utilise l’assistant de génération d’application C++ MFC (menu File/New project/MFC Application), une option SDL checks permet d’activer l’analyse de code :

MFC-app-wizard-11-SDL-check

Lorsque le projet est généré, un menu permet de lancer l’analyse du code du projet très simplement :

Visual -studio-2010-build-menu-code-analysys

L’analyse de code nécessite juste la recompilation du projet. C’est légèrement plus long qu’une simple recompilation.

 

Exemples de bugs détectés

 

Tous les indices des tableaux sont examinés à la loupe, notamment dans le boucles pour détecter les débordements éventuels. Et si un indice déborde d’un tableau dans une boucle, le problème sera signalé.

Dans la classe CDocument, déclarons un tableau, et utilisons le comme suit :

class CMFCApplication1Doc : public CDocument
{
    // ...
    static const int m_size = 100;
    char m_tab[m_size];
    // ...
};
void CMFCApplication1Doc::ShiftArray()
{
    for (int i=0; i< m_size; i++)
    {
        m_tab[i] = m_tab[i+1];
    }
}

Bien sûr il y a un problème. Une relecture de code pas très attentive peut la laisser passer, surtout si le code est plus fourni que dans l’exemple. L’analyse de code trouve le problème et signale que les index valides pour le tableau m_tab vont de 0 à 99, et que l’indice 100 est invalide :

visual studio 2012 code analysis

On peut remarquer qu’en saisissant un texte dans le champ de recherche, en haut de la fenêtre d’analyse de code, on filtre les résultats. Ci-dessus, seuls les résultats concernant les fichiers dont le nom contient “doc” sont affichés.

Voici un autre exemple de code à problème :

void CMFCApplication1Doc::SetDelay(int delay)
{
    CDelayHolder *pObj = nullptr;
    bool isFound = false;
    for (int index = 0; index <10; index++)
    {
        if (index >= delay)
        {
            pObj = new CDelayHolder();
        }
        else
        {
            if (!isFound)
                isFound = WaitDelay(delay);
            else
                pObj->Wait(delay);
        }
    }
}

Oui c’est du code un peu bizarre, mais qui existe ! L’analyseur de code trouve le problème et l’explique. Il se produit lors du deuxième passage dans la boucle :

visual studio 2012 code analysis-loop

 

Débordement de tableau ou de mémoire, pointeur invalide, fuite mémoire,  et bien d’autres problèmes sont recherchés dans le code. L’analyse utilise plus de 200 règles pour vérifier la sécurité du code.

 

Paramétrer l’analyse de code

 

Il est possible de paramétrer les règles de l’analyseur de code selon ses besoins. Il suffit de créer un nouveau fichier de règles (menu File/New Code Analysis rule set), et de désactiver ou traiter certaines règles comme erreur ou avertissement.

visual studio 2012 code analysis-list

L’onglet Code Analysis des propriétés du projet permet de voir ou de modifier la liste des règles d’analyse actives.

On peut aussi modifier le comportement de l’analyse dans le code en utilisant #pragma warning :

#pragma warning(suppress: 6011) #pragma warning (error: 6001) 

 

L’annotation sémantique du code

 

Il est très facile d’obtenir un diagnostic sur la qualité du code avec Visual Studio 11. Mais il est possible d’aller encore plus loin en aidant l’analyseur de code à faire son travail. SAL (Source code Annotation Language), est une liste de mots-clés qui, ajoutés dans le code source, seront reconnus par l’analyseur de code et affineront les résultats.

On peut voir SAL comme des commentaires sémantiques sur le code, destinés à être utilisés par l’analyseur pour qu’il vérifient certaines conditions. Ils sont définis dans le fichier sal.h.

Les mot-clés SAL les plus utilisé sont _In_ et _Out_, dans une déclaration de fonction :

void GetTextProperty(_In_ LPCTSTR szPropertyName,
                    _Out_ LPTSTR szOutBuffer,
                    _In_ int nBufferSize);

Les mots-clés _In_ et _Out_ sont utilisés par l’analyseur de code qui vérifiera que szPropertyName n’est jamais nul.

L’équipe qui développe Windows chez Microsoft utilise SAL, et plus de 3 millions d’annotations SAL ont été ajoutées au code de Windows. C’est ainsi que les fichiers include de Windows comportent des annotations qui sont utiles pour nos programmes. Par exemple, la fonction Win32 GlobalLock est définie ainsi dans winbase.h :

_Ret_maybenull_ LPVOID WINAPI GlobalLock (_In_ HGLOBAL hMem); 

C’est assez explicite : le paramètre hMem ne doit pas être nul en entrée, et la valeur de retour de la fonction peut être nulle.

Ainsi, le code suivant provoque l’affichage de deux messages lors de l’analyse de code :

HGLOBAL hMem = nullptr;
char *p = (char *)GlobalLock(hMem);
*p = 'a';

visual studio 2012 code analysis-globallock

Le premier message signale qu’il n’est pas permis de passer un pointeur nul à GlobalLock. Le second indique que, puisque GlobalLock peut retourner un pointeur nul, alors il est illégal de le déréférencer sans tester s’il est nul.

Le code des MFC utilise également SAL. Par exemple, la méthode CWnd::GetWindowText est déclarée ainsi :

int GetWindowText(_Out_writes_to_(nMaxCount, return + 1) LPTSTR lpszStrBuf,
    _In_ int nMaxCount) const;

L’analyseur de code vérifie que le paramètre lpszStrBuf pointe vers une zone mémoire accessible en écriture de nMaxCount octets, et que nMaxCount ne doit pas être nul.

Et le code suivant génère une erreur de débordement de mémoire :

TCHAR buffer[80];
AfxGetMainWnd()->GetWindowText(buffer, 100);

visual studio 2012 code analysis-getwindowtext

 

L’analyse du code multitâche

 

L’analyse de code C++ permet de trouver des bugs dans du code multitâche. Plus de 100 règles concernent particulièrement ce sujet.

Un des problèmes communs lors de l’écriture de code multitâche est l’accès concurrent à une variable. Il faut en protéger l’accès, et une erreur à ce niveau peut provoquer un écrasement de la valeur ou un blocage de l’application (dead lock).

L’exemple de code suivant utilise un entier count protégé par une section critique cs.

_Garded_by_ est un mot-clé SAL qui indique qu’une variable doit être protégée par un verrou, ici la section critique cs. Ainsi l’analyse de code pourra détecter les accès à count qui ne sont pas protégés par cs.

typedef struct
{
    _Garded_by_(cs) int count;
    CRITICAL_SECTION cs;
}COUNT; 

bool CMFCApplication1Doc::UpdateCount(_In_ COUNT *p, _In_ int diff)
{
    EnterCriticalSection(&p->cs);
    if (p->count < diff)
        return false;
    p->count -= diff;
    LeaveCriticalSection(&p->cs);
    return !p->count;
}

Il y a deux problèmes, les deux repérés par l’analyse de code C++ : un return au milieu de la section critique, et un accès à count non protégé :

visual studio 2012 code analysis-critical section

 

L’analyse de code C++ – conclusion

 

Ces derniers exemples m’impressionnent… Pendant des dizaines d’années on a cherché à la main les débordements de zone mémoire ! Et ces exemples ne montrent qu’une partie de l’impressionnante puissance de l’analyseur de code C++.

L’une des conclusions que l’on tire de l’utilisation de l’analyseur de code sur un programme conséquent est qu’il ne faut plus utiliser les pointeurs *, les opérateurs new et delete, mais les remplacer par les pointeurs intelligents de C++11. Si vous n’êtes pas un adepte de shared_ptr ou unique_ptr, il faut absolument vous y mettre. Non seulement il n’y a plus à utiliser delete, mais l’usage de ces pointeurs intelligents produit du code beaucoup plus sur. Je pense à certains énormes projets en C++ que j’ai pu croiser, et qui gagneraient énormément en sécurité (plantages et fuites mémoires) à utiliser les pointeurs intelligents.

Entre les nouveautés de C++11 et ce nouvel analyseur de code pour C++ natif, il va bientôt devenir difficile d’écrire du code C++ avec des bugs !

Rappelons juste, pour la fin, qu’une version allégée de l’analyseur de code C++ sera disponible gratuitement dans Visual C++ express 11 (la prochaine version de Visual C++), et que la version complète, avec toutes les règles, sera incluse dans toutes les versions payantes de Visual Studio 11.

One thought on “L’analyse de code C++ dans Visual Studio 2012 : un outil puissant

  1. Pingback: C++ code analysis in Visual Studio 2012 | BlogMFC

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>