Les dangers de l'utilisation de constantes multi-caractères

Image 1

Pendant l'analyse de code, PVS-Studio analyse le flux de données et opère sur les valeurs des variables. Les valeurs sont tirées de constantes ou déduites d'expressions conditionnelles. Nous les appelons des valeurs virtuelles. Récemment, nous les avons améliorés pour qu'ils fonctionnent avec des constantes à plusieurs caractères et c'est la raison pour laquelle nous avons créé une nouvelle règle de diagnostic.

Présentation


Un littéral à plusieurs caractères est défini par l'implémentation , de sorte que différents compilateurs peuvent coder ces littéraux de différentes manières. Par exemple, GCC et Clang définissent une valeur basée sur l'ordre des caractères dans un littéral, tandis que MSVC les déplace en fonction du type de caractère (normal 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 à l'analyseur. En conséquence, 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 l'assemblage.

Diagnostics V1039


Prenons un 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; } 

Un programme compilé par différents compilateurs imprimera différents messages à l'écran.

Pour un projet utilisant un compilateur spécifique, cela ne sera pas visible, mais le portage peut entraîner des problèmes, vous devez donc remplacer ces littéraux par de simples constantes numériques, par exemple, remplacez «Test» par 0x54657374.

Pour démontrer la différence entre les compilateurs, nous écrivons un petit utilitaire où les séquences de 3 et 4 caractères sont prises, par exemple, 'GHIJ' et 'GHI', et leur représentation en mémoire après compilation est affichée.

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; } 

La sortie de l'utilitaire compilé 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 

La sortie d'un utilitaire compilé 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 a été ajouté à l'analyseur PVS-Studio 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 .



Si vous souhaitez partager cet article avec un public anglophone, veuillez utiliser le lien vers la traduction: Svyatoslav Razmyslov. Les dangers de l'utilisation de constantes multi-caractères

Source: https://habr.com/ru/post/fr457696/


All Articles