Pendant l'analyse de code, PVS-Studio analyse le flux de données et exploite des valeurs variables. Les valeurs sont tirées de constantes ou dérivées d'expressions conditionnelles. Nous les appelons des valeurs virtuelles. Récemment, nous les avons affinés afin de travailler avec des constantes multi-caractères et c'est devenu la raison de créer une nouvelle règle de diagnostic.
Présentation
Les littéraux à plusieurs caractères sont
définis par l'implémentation , de sorte que différents compilateurs peuvent les coder de différentes manières. Par exemple, GCC et Clang définissent une valeur, basée sur l'ordre des symboles dans le littéral, tandis que MSVC les déplace en fonction du type de symbole (régulier ou d'échappement).
Par exemple, le littéral «T \ x65s \ x74» sera codé de différentes manières, selon le compilateur. Une logique similaire a dû être ajoutée dans l'analyseur. Par conséquent, nous avons créé une nouvelle règle de diagnostic V1039 pour identifier ces littéraux dans le code. Ces littéraux sont dangereux dans les projets multiplateformes qui utilisent plusieurs compilateurs pour la construction.
Diagnostic V1039
Regardons l'exemple. Le code ci-dessous, compilé par différents compilateurs, se comportera différemment:
#include <stdio.h> void foo(int c) { if (c == 'T\x65s\x74') // <= V1039 { printf("Compiled with GCC or Clang.\n"); } else { printf("It's another compiler (for example, MSVC).\n"); } } int main(int argc, char** argv) { foo('Test'); return 0; }
Le programme, compilé par différents compilateurs, imprimera différents messages à l'écran.
Pour un projet qui utilise un compilateur spécifique, il ne sera pas perceptible. Mais lors du portage, des problèmes peuvent survenir, il convient donc de remplacer ces littéraux par de simples constantes numériques, telles que «Test» doit être modifié avec 0x54657374.
Pour démontrer la différence entre les compilateurs, nous allons écrire un petit utilitaire qui prend des séquences de 3 et 4 symboles, tels que 'GHIJ' et 'GHI', et affiche leur représentation en mémoire après la compilation.
Code utilitaire:
#include <stdio.h> typedef int char_t; void PrintBytes(const char* format, char_t lit) { printf("%20s : ", format); const unsigned char *ptr = (const unsigned char*)&lit; for (int i = sizeof(lit); i--;) { printf("%c", *ptr++); } putchar('\n'); } int main(int argc, char** argv) { printf("Hex codes are: G(%02X) H(%02X) I(%02X) J(%02X)\n",'G','H','I','J'); PrintBytes("'GHIJ'", 'GHIJ'); PrintBytes("'\\x47\\x48\\x49\\x4A'", '\x47\x48\x49\x4A'); PrintBytes("'G\\x48\\x49\\x4A'", 'G\x48\x49\x4A'); PrintBytes("'GH\\x49\\x4A'", 'GH\x49\x4A'); PrintBytes("'G\\x48I\\x4A'", 'G\x48I\x4A'); PrintBytes("'GHI\\x4A'", 'GHI\x4A'); PrintBytes("'GHI'", 'GHI'); PrintBytes("'\\x47\\x48\\x49'", '\x47\x48\x49'); PrintBytes("'GH\\x49'", 'GH\x49'); PrintBytes("'\\x47H\\x49'", '\x47H\x49'); PrintBytes("'\\x47HI'", '\x47HI'); return 0; }
Sortie de l'utilitaire, compilée par Visual C ++:
Hex codes are: G(47) H(48) I(49) J(4A) 'GHIJ' : JIHG '\x47\x48\x49\x4A' : GHIJ 'G\x48\x49\x4A' : HGIJ 'GH\x49\x4A' : JIHG 'G\x48I\x4A' : JIHG 'GHI\x4A' : JIHG 'GHI' : IHG '\x47\x48\x49' : GHI 'GH\x49' : IHG '\x47H\x49' : HGI '\x47HI' : IHG
Sortie de l'utilitaire, compilée par GCC ou Clang:
Hex codes are: G(47) H(48) I(49) J(4A) 'GHIJ' : JIHG '\x47\x48\x49\x4A' : JIHG 'G\x48\x49\x4A' : JIHG 'GH\x49\x4A' : JIHG 'G\x48I\x4A' : JIHG 'GHI\x4A' : JIHG 'GHI' : IHG '\x47\x48\x49' : IHG 'GH\x49' : IHG '\x47H\x49' : IHG '\x47HI' : IHG
Conclusion
Le diagnostic V1039 est ajouté dans l'analyseur PVS-Studio de la version
7.03 , qui a été récemment publié. Vous pouvez télécharger la dernière version de l'analyseur sur la
page de téléchargement .