Während der Codeanalyse analysiert PVS-Studio den Datenfluss und verarbeitet die Werte von Variablen. Werte werden aus Konstanten entnommen oder aus bedingten Ausdrücken abgeleitet. Wir nennen sie virtuelle Werte. Kürzlich haben wir sie für die Arbeit mit Konstanten mit mehreren Zeichen verbessert. Dies war der Grund für die Erstellung einer neuen Diagnoseregel.
Einführung
Ein mehrstelliges Literal ist
implementierungsdefiniert , sodass verschiedene Compiler diese Literale auf unterschiedliche Weise codieren können. Beispielsweise legen GCC und Clang einen Wert fest, der auf der Reihenfolge der Zeichen in einem Literal basiert, während MSVC sie je nach Zeichentyp (regulär oder Escape) verschiebt.
Beispielsweise wird das Literal 'T \ x65s \ x74' je nach Compiler auf unterschiedliche Weise codiert. Eine ähnliche Logik musste dem Analysator hinzugefügt werden. Als Ergebnis haben wir eine neue Diagnoseregel V1039 erstellt, um solche Literale im Code zu identifizieren. Solche Literale sind in plattformübergreifenden Projekten gefährlich, bei denen mehrere Compiler für die Assemblierung verwendet werden.
Diagnose V1039
Betrachten Sie ein Beispiel. Der folgende Code, der von verschiedenen Compilern kompiliert wurde, verhält sich unterschiedlich:
#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; }
Ein von verschiedenen Compilern kompiliertes Programm druckt verschiedene Meldungen auf den Bildschirm.
Bei einem Projekt, das einen bestimmten Compiler verwendet, ist dies nicht erkennbar. Die Portierung kann jedoch zu Problemen führen. Daher sollten Sie solche Literale durch einfache numerische Konstanten ersetzen. Ändern Sie beispielsweise 'Test' in 0x54657374.
Um den Unterschied zwischen Compilern zu demonstrieren, schreiben wir ein kleines Dienstprogramm, in dem Sequenzen mit 3 und 4 Zeichen verwendet werden, z. B. 'GHIJ' und 'GHI', und deren Darstellung im Speicher nach der Kompilierung angezeigt wird.
Dienstprogrammcode:
#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; }
Die Ausgabe des von Visual C ++ kompilierten Dienstprogramms:
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
Die Ausgabe eines von GCC oder Clang kompilierten Dienstprogramms:
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
Fazit
Die V1039-Diagnose wurde dem kürzlich veröffentlichten PVS-Studio Analyzer Version
7.03 hinzugefügt. Sie können die neueste Version des Analysators auf
der Download-Seite herunterladen .

Wenn Sie diesen Artikel einem englischsprachigen Publikum zugänglich machen möchten, verwenden Sie bitte den Link zur Übersetzung: Svyatoslav Razmyslov.
Die Gefahren der Verwendung von Konstanten mit mehreren Zeichen