Analyse de code statique pour le portage de code vers des plates-formes 64 bits
Par Parasoft
7 octobre 2010
3 min lire
Dans mon post précédent, J'ai introduit un processus que vous pouvez appliquer pour préparer l'application pour le processus de portage 64 bits:
Effectuer des tests de mutation via la détection des erreurs de mémoire d'exécution
Utilisez l'analyse statique pour identifier le code sujet aux erreurs et non portable
Répéter la détection des erreurs de mémoire d'exécution
Effectuer des tests unitaires (facultatif)
Dans cet article, nous examinerons de plus près certains revue de code statique règles que vous voudrez peut-être vérifier à l'étape 2.
Règles qui exposent un code sujet aux erreurs
- Ne renvoyez jamais une référence à un objet local ou à un pointeur déréférencé initialisé par «nouveau» dans la fonction. Le renvoi d'une référence à un objet local peut entraîner une corruption de la pile. Le renvoi d'un pointeur déréférencé initialisé par «nouveau» dans la fonction peut provoquer une fuite de mémoire.
- Ne convertissez jamais un const en non-const. Cela peut nuire à l'intégrité des données en autorisant le changement de valeurs supposées constantes. Cette pratique réduit également la lisibilité du code car vous ne pouvez pas supposer que les variables const sont constantes.
- Si une classe a des fonctions virtuelles, elle doit avoir un destructeur virtuel. Cette norme empêche les fuites de mémoire dans les classes dérivées. Une classe qui a des fonctions virtuelles est destinée à être utilisée comme classe de base, elle doit donc avoir un destructeur virtuel pour garantir que le destructeur sera appelé lorsque l'objet dérivé est référencé via un pointeur vers la classe de base.
- Les fonctions membres publiques doivent renvoyer des descripteurs const aux données membres.
- Lorsque vous fournissez des descripteurs non const aux données des membres, vous compromettez l'encapsulation en permettant aux appelants de modifier les données des membres en dehors des fonctions membres.
- Un pointeur vers une classe ne doit pas être converti en un pointeur d'une seconde classe à moins qu'il n'hérite de la seconde. Cette conversion descendante «invalide» peut entraîner des pointeurs sauvages, des problèmes de corruption des données et d'autres erreurs.
- N'accédez pas directement aux données globales à partir d'un constructeur.
L'ordre d'initialisation des objets statiques définis dans différentes unités de compilation n'est pas défini dans la définition du langage C ++. Par conséquent, l'accès aux données globales à partir d'un constructeur peut entraîner la lecture d'objets non initialisés.
Pour plus de règles, voir les œuvres de Scott Meyers, Martin Klaus et Herb Sutter.
Règles qui exposent un code de port difficile
Après avoir localisé et réparé ce code sujet aux erreurs, commencez à rechercher du code qui fonctionne correctement sur votre plate-forme / architecture actuelle, mais qui pourrait ne pas être correctement porté. Certaines règles applicables à la plupart des projets de portage 64 bits incluent:
- Utilisez les types standard le cas échéant. Pensez à utiliser size_t plutôt que «int», par exemple. Utilisez uint64_t si vous voulez un entier 64 bits non signé. Non seulement cette pratique aidera à identifier et à prévenir les bogues actuels dans le code, mais elle contribuera à l'effort de portage à l'avenir lorsque le code sera porté sur des processeurs 128 bits.
- Passez en revue toutes les utilisations existantes des types de données longs dans le code source. Si les valeurs à contenir dans ces variables, champs et paramètres se situent dans la plage de 2Gig-1 à –2Gig ou 4Gig à 0, alors il est probablement préférable d'utiliser respectivement int32_t ou uint32_t.
- Examinez toutes les instances d'affectation restreinte. Évitez de telles affectations car l'attribution d'une valeur longue à un int entraînera une troncature de la valeur 64 bits.
- Trouvez des moulages rétrécis. Utilisez des castes restrictives sur les expressions, pas des opérandes.
- Trouvez des casts de long * à int *. Dans un environnement 32 bits, ceux-ci peuvent avoir été utilisés de manière interchangeable. Examinez toutes les instances d'affectations de pointeurs incompatibles.
- Trouvez des casts de int * à long *. Dans un environnement 32 bits, ceux-ci peuvent avoir été utilisés de manière interchangeable. Examinez toutes les instances d'affectations de pointeurs incompatibles.
- Trouvez des valeurs longues initialisées avec des littéraux int. Évitez de telles initialisations car les constantes intégrales peuvent être représentées sous forme de types 32 bits même lorsqu'elles sont utilisées dans des expressions avec des types 64 bits.
- Localisez les littéraux int dans les opérations binaires pour lesquelles le résultat est affecté à une valeur longue. Une multiplication de 64 bits est souhaitée si le résultat est une valeur de 64 bits.
- Trouvez les constantes int utilisées dans les expressions 64 bits. Utilisez des valeurs 64 bits dans des expressions 64 bits.
- Recherchez les utilisations d'expressions multiplicatives ne contenant pas de type 64 bits dans l'un ou l'autre des opérandes. Pour que les expressions intégrales produisent des résultats 64 bits, au moins l'un des opérandes doit avoir un type de données 64 bits signé ou non signé.
- Utilisez les suffixes appropriés sur les constantes littérales entières et flottantes si votre compilateur les autorise. Par exemple:
non signé int j = 123u;
non signé k long = 456UL;
etc
***
Crédit photo: quapan