PVS-Studio et intégration continue : TeamCity. Analyse du projet Open RollerCoaster Tycoon 2

PVS-Studio et intégration continue : TeamCity. Analyse du projet Open RollerCoaster Tycoon 2
L'un des scénarios les plus actuels d'utilisation de l'analyseur PVS-Studio est son intégration avec les systèmes CI. Et bien que l'analyse d'un projet PVS-Studio à partir de presque n'importe quel système d'intégration continue puisse être intégrée à quelques commandes seulement, nous continuons à rendre ce processus encore plus pratique. PVS-Studio prend désormais en charge la conversion de la sortie de l'analyseur dans un format pour TeamCity - TeamCity Inspections Type. Voyons voir comment ça fonctionne.

Informations sur le logiciel utilisé

PVS-Studio — un analyseur statique de code C, C++, C# et Java, conçu pour faciliter la tâche de recherche et de correction de divers types d'erreurs. L'analyseur peut être utilisé sous Windows, Linux et macOS. Dans cet article, nous utiliserons activement non seulement l'analyseur lui-même, mais également certains utilitaires de sa distribution.

CLMoniteur - est un serveur de surveillance qui surveille les lancements du compilateur. Il doit être exécuté immédiatement avant de commencer à construire votre projet. En mode surveillance, le serveur interceptera les exécutions de tous les compilateurs pris en charge. Il est à noter que cet utilitaire ne peut être utilisé que pour analyser des projets C/C++.

Convertisseur Plog – un utilitaire pour convertir les rapports de l'analyseur en différents formats.

Informations sur le projet à l'étude

Essayons cette fonctionnalité sur un exemple pratique - analysons le projet OpenRCT2.

OuvertRCT2 - une implémentation ouverte du jeu RollerCoaster Tycoon 2 (RCT2), en l'étendant avec de nouvelles fonctions et en corrigeant des bugs. Le gameplay tourne autour de la construction et de l'entretien d'un parc d'attractions contenant des manèges, des magasins et des installations. Le joueur doit essayer de faire du profit et de maintenir la bonne réputation du parc tout en gardant les clients heureux. OpenRCT2 vous permet de jouer à la fois en scénario et en bac à sable. Les scénarios exigent que le joueur accomplisse une tâche spécifique dans un délai défini, tandis que Sandbox permet au joueur de construire un parc plus flexible sans aucune restriction ni financement.

réglage

Afin de gagner du temps, je vais probablement ignorer le processus d'installation et commencer à partir du moment où le serveur TeamCity est en cours d'exécution sur mon ordinateur. Nous devons accéder à : localhost : {port spécifié lors du processus d'installation} (dans mon cas, localhost : 9090) et saisir les données d'autorisation. Après être entré, nous serons accueillis par :

PVS-Studio et intégration continue : TeamCity. Analyse du projet Open RollerCoaster Tycoon 2
Cliquez sur le bouton Créer un projet. Ensuite, sélectionnez Manuellement et remplissez les champs.

PVS-Studio et intégration continue : TeamCity. Analyse du projet Open RollerCoaster Tycoon 2
Après avoir appuyé sur le bouton Création, nous sommes accueillis par une fenêtre avec des paramètres.

PVS-Studio et intégration continue : TeamCity. Analyse du projet Open RollerCoaster Tycoon 2
Cliquons Créer une configuration de build.

PVS-Studio et intégration continue : TeamCity. Analyse du projet Open RollerCoaster Tycoon 2
Remplissez les champs et cliquez Création. Nous voyons une fenêtre vous demandant de sélectionner un système de contrôle de version. Puisque les sources sont déjà localisées localement, cliquez sur Skip.

PVS-Studio et intégration continue : TeamCity. Analyse du projet Open RollerCoaster Tycoon 2
Enfin, nous passons aux paramètres du projet.

PVS-Studio et intégration continue : TeamCity. Analyse du projet Open RollerCoaster Tycoon 2
Ajoutons des étapes d'assemblage, pour cela cliquez : Étapes de construction -> Ajouter une étape de construction.

PVS-Studio et intégration continue : TeamCity. Analyse du projet Open RollerCoaster Tycoon 2
Ici, nous choisissons :

  • Type de coureur -> Ligne de commande
  • Exécuter -> Script personnalisé

Puisque nous effectuerons une analyse lors de la compilation du projet, l'assemblage et l'analyse devraient être une seule étape, alors remplissez le champ Script personnalisé:

PVS-Studio et intégration continue : TeamCity. Analyse du projet Open RollerCoaster Tycoon 2
Nous examinerons les étapes individuelles plus tard. Il est important que le chargement de l'analyseur, l'assemblage du projet, son analyse, la sortie du rapport et son formatage ne prennent que onze lignes de code.

La dernière chose que nous devons faire est de définir les variables d'environnement, dont j'ai décrit les moyens d'améliorer leur lisibilité. Pour ce faire, passons à autre chose : Paramètres -> Ajouter un nouveau paramètre et ajoutez trois variables :

PVS-Studio et intégration continue : TeamCity. Analyse du projet Open RollerCoaster Tycoon 2
Il ne vous reste plus qu'à appuyer sur le bouton Courir dans le coin supérieur droit. Pendant que le projet est assemblé et analysé, je vais vous parler du scénario.

Directement script

Tout d’abord, nous devons télécharger la dernière distribution PVS-Studio. Pour cela, nous utilisons le gestionnaire de packages Chocolatey. Pour ceux qui veulent en savoir plus, il existe un article:

choco install pvs-studio -y

Ensuite, lançons l'utilitaire de suivi de construction de projet CLMonitor.

%CLmon% monitor –-attach

Ensuite, nous construirons le projet en tant que variable d'environnement MSB est le chemin d'accès à la version de MSBuild que je dois construire

%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable

Entrons le login et la clé de licence pour PVS-Studio :

%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%

Une fois la construction terminée, exécutez à nouveau CLMonitor pour générer des fichiers prétraités et une analyse statique :

%CLmon% analyze -l "c:ptest.plog"

Ensuite, nous utiliserons un autre utilitaire de notre distribution. PlogConverter convertit un rapport d'un format standard en un format spécifique à TeamCity. Grâce à cela, nous pourrons le visualiser directement dans la fenêtre de construction.

%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"

La dernière étape consiste à afficher le rapport formaté dans Stdout, où il sera récupéré par l'analyseur TeamCity.

type "C:tempptest.plog_TeamCity.txt"

Code complet du script :

choco install pvs-studio -y
%CLmon% monitor --attach
set platform=x64
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
%CLmon% analyze -l "c:ptest.plog"
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
type "C:tempptest.plog_TeamCity.txt"

En attendant, le montage et l'analyse du projet s'est terminé avec succès, on peut aller dans l'onglet Projets et убедиться в этом.

PVS-Studio et intégration continue : TeamCity. Analyse du projet Open RollerCoaster Tycoon 2
Maintenant cliquons sur Total des inspectionspour accéder à la visualisation du rapport de l'analyseur :

PVS-Studio et intégration continue : TeamCity. Analyse du projet Open RollerCoaster Tycoon 2
Les avertissements sont regroupés par numéros de règle de diagnostic. Pour naviguer dans le code, vous devez cliquer sur le numéro de ligne avec l'avertissement. En cliquant sur le point d'interrogation dans le coin supérieur droit, vous ouvrirez un nouvel onglet avec de la documentation. Vous pouvez également naviguer dans le code en cliquant sur le numéro de ligne avec l'avertissement de l'analyseur. La navigation depuis un ordinateur distant est possible lors de l'utilisation Racine de l'arbre source marqueur. Toute personne intéressée par ce mode de fonctionnement de l'analyseur peut se familiariser avec la rubrique correspondante documentation.

Visualisation des résultats de l'analyseur

Maintenant que nous avons fini de déployer et de configurer la version, examinons quelques avertissements intéressants trouvés dans le projet que nous examinons.

Avertissement N1

V773 [CWE-401] L'exception a été levée sans libérer le pointeur 'result'. Une fuite de mémoire est possible. libopenrct2 ObjectFactory.cpp 443

Object* CreateObjectFromJson(....)
{
  Object* result = nullptr;
  ....
  result = CreateObject(entry);
  ....
  if (readContext.WasError())
  {
    throw std::runtime_error("Object has errors");
  }
  ....
}

Object* CreateObject(const rct_object_entry& entry)
{
  Object* result;
  switch (entry.GetType())
  {
    case OBJECT_TYPE_RIDE:
      result = new RideObject(entry);
      break;
    case OBJECT_TYPE_SMALL_SCENERY:
      result = new SmallSceneryObject(entry);
      break;
    case OBJECT_TYPE_LARGE_SCENERY:
      result = new LargeSceneryObject(entry);
      break;
    ....
    default:
      throw std::runtime_error("Invalid object type");
  }
  return result;
}

L'analyseur a remarqué une erreur qui, après l'allocation dynamique de mémoire dans CreateObject, lorsqu'une exception se produit, la mémoire n'est pas effacée et une fuite de mémoire se produit.

Avertissement N2

V501 Il y a des sous-expressions identiques '(1ULL << WIDX_MONTH_BOX)' à gauche et à droite du '|' opérateur. libopenrct2ui Cheats.cpp 487

static uint64_t window_cheats_page_enabled_widgets[] = 
{
  MAIN_CHEAT_ENABLED_WIDGETS |
  (1ULL << WIDX_NO_MONEY) |
  (1ULL << WIDX_ADD_SET_MONEY_GROUP) |
  (1ULL << WIDX_MONEY_SPINNER) |
  (1ULL << WIDX_MONEY_SPINNER_INCREMENT) |
  (1ULL << WIDX_MONEY_SPINNER_DECREMENT) |
  (1ULL << WIDX_ADD_MONEY) |
  (1ULL << WIDX_SET_MONEY) |
  (1ULL << WIDX_CLEAR_LOAN) |
  (1ULL << WIDX_DATE_SET) |
  (1ULL << WIDX_MONTH_BOX) |  // <=
  (1ULL << WIDX_MONTH_UP) |
  (1ULL << WIDX_MONTH_DOWN) |
  (1ULL << WIDX_YEAR_BOX) |
  (1ULL << WIDX_YEAR_UP) |
  (1ULL << WIDX_YEAR_DOWN) |
  (1ULL << WIDX_DAY_BOX) |
  (1ULL << WIDX_DAY_UP) |
  (1ULL << WIDX_DAY_DOWN) |
  (1ULL << WIDX_MONTH_BOX) |  // <=
  (1ULL << WIDX_DATE_GROUP) |
  (1ULL << WIDX_DATE_RESET),
  ....
};

Peu de personnes autres qu'un analyseur statique pourraient réussir ce test d'attention. Cet exemple de copier-coller est bon précisément pour cette raison.

Avertissements N3

V703 Il est étrange que le champ « flags » de la classe dérivée « RCT12BannerElement » écrase le champ de la classe de base « RCT12TileElementBase ». Lignes de contrôle : RCT12.h:570, RCT12.h:259. libopenrct2 RCT12.h 570

struct RCT12SpriteBase
{
  ....
  uint8_t flags;
  ....
};
struct rct1_peep : RCT12SpriteBase
{
  ....
  uint8_t flags;
  ....
};

Bien entendu, utiliser une variable du même nom dans la classe de base et dans le descendant n’est pas toujours une erreur. Cependant, la technologie d’héritage elle-même suppose que tous les champs de la classe parent sont présents dans la classe enfant. En déclarant des champs de même nom chez l'héritier, on introduit une confusion.

Avertissement N4

V793 Il est étrange que le résultat de l'instruction 'imageDirection / 8' fasse partie de la condition. Peut-être aurait-on dû comparer cette affirmation à autre chose. libopenrct2 ObservationTower.cpp 38

void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
  if ((imageDirection / 8) && (imageDirection / 8) != 3)
  {
    ....
  }
  ....
}

Regardons de plus près. Expression imageDirection/8 sera faux si Direction de l'image est compris entre -7 et 7. Deuxième partie : (directionimage / 8) != 3 chèques Direction de l'image pour être en dehors de la plage : de -31 à -24 et de 24 à 31, respectivement. Il me semble assez étrange de vérifier ainsi l'inclusion de nombres dans une certaine plage et, même s'il n'y a pas d'erreur dans ce morceau de code, je recommanderais de réécrire ces conditions pour qu'elles soient plus explicites. Cela rendrait la vie beaucoup plus facile aux personnes qui liraient et maintiendraient ce code.

Avertissement N5

V587 Une séquence étrange d'affectations de ce genre : A = B ; B = UNE ;. Vérifiez les lignes : 1115, 1118. libopenrct2ui MouseInput.cpp 1118

void process_mouse_over(....)
{
  ....
  switch (window->widgets[widgetId].type)
  {
    case WWT_VIEWPORT:
      ebx = 0;
      edi = cursorId;                                 // <=
      // Window event WE_UNKNOWN_0E was called here,
      // but no windows actually implemented a handler and
      // it's not known what it was for
      cursorId = edi;                                 // <=
      if ((ebx & 0xFF) != 0)
      {
        set_cursor(cursorId);
        return;
      }
      break;
      ....
  }
  ....
}

Ce fragment de code a très probablement été obtenu par décompilation. Ensuite, à en juger par le commentaire laissé, une partie du code qui ne fonctionnait pas a été supprimée. Cependant, il reste encore quelques opérations ID du curseur, ce qui n’a pas non plus beaucoup de sens.

Avertissement N6

V1004 [CWE-476] Le pointeur 'player' a été utilisé de manière non sécurisée après avoir été vérifié par rapport à nullptr. Vérifiez les lignes : 2085, 2094. libopenrct2 Network.cpp 2094

void Network::ProcessPlayerList()
{
  ....
  auto* player = GetPlayerByID(pendingPlayer.Id);
  if (player == nullptr)
  {
    // Add new player.
    player = AddPlayer("", "");
    if (player)                                          // <=
    {
      *player = pendingPlayer;
       if (player->Flags & NETWORK_PLAYER_FLAG_ISSERVER)
       {
         _serverConnection->Player = player;
       }
    }
    newPlayers.push_back(player->Id);                    // <=
  }
  ....
}

Ce code est assez simple à corriger, il suffit de le vérifier une troisième fois joueur vers un pointeur nul, ou ajoutez-le au corps de l'instruction conditionnelle. Je suggérerais la deuxième option :

void Network::ProcessPlayerList()
{
  ....
  auto* player = GetPlayerByID(pendingPlayer.Id);
  if (player == nullptr)
  {
    // Add new player.
    player = AddPlayer("", "");
    if (player)
    {
      *player = pendingPlayer;
      if (player->Flags & NETWORK_PLAYER_FLAG_ISSERVER)
      {
        _serverConnection->Player = player;
      }
      newPlayers.push_back(player->Id);
    }
  }
  ....
}

Avertissement N7

V547 [CWE-570] L'expression 'name == nullptr' est toujours fausse. libopenrct2 ListeServeurs.cpp 102

std::optional<ServerListEntry> ServerListEntry::FromJson(...)
{
  auto name = json_object_get(server, "name");
  .....
  if (name == nullptr || version == nullptr)
  {
    ....
  }
  else
  {
    ....
    entry.name = (name == nullptr ? "" : json_string_value(name));
    ....
  }
  ....
}

Vous pouvez vous débarrasser d'une ligne de code difficile à lire d'un seul coup et résoudre le problème en vérifiant nullptr. Je suggère de changer le code comme suit :

std::optional<ServerListEntry> ServerListEntry::FromJson(...)
{
  auto name = json_object_get(server, "name");
  .....
  if (name == nullptr || version == nullptr)
  {
    name = ""
    ....
  }
  else
  {
    ....
    entry.name = json_string_value(name);
    ....
  }
  ....
}

Avertissement N8

V1048 [CWE-1164] La variable 'ColumnHeaderPressedCurrentState' a reçu la même valeur. libopenrct2ui CustomListView.cpp 510

void CustomListView::MouseUp(....)
{
  ....
  if (!ColumnHeaderPressedCurrentState)
  {
    ColumnHeaderPressed = std::nullopt;
    ColumnHeaderPressedCurrentState = false;
    Invalidate();
  }
}

Le code semble assez étrange. Il me semble qu'il y a eu une faute de frappe soit dans la condition, soit lors de la réaffectation de la variable ColumnHeaderPressedCurrentState sens non.

conclusion

Comme nous pouvons le constater, intégrer l'analyseur statique PVS-Studio dans votre projet TeamCity est assez simple. Pour ce faire, il suffit d'écrire un seul petit fichier de configuration. La vérification du code vous permettra d'identifier les problèmes immédiatement après l'assemblage, ce qui contribuera à les éliminer lorsque la complexité et le coût des modifications sont encore faibles.

PVS-Studio et intégration continue : TeamCity. Analyse du projet Open RollerCoaster Tycoon 2
Si vous souhaitez partager cet article avec un public anglophone, veuillez utiliser le lien de traduction : Vladislav Stolyarov. PVS-Studio et intégration continue : TeamCity. Analyse du projet Open RollerCoaster Tycoon 2.

Source: habr.com

Ajouter un commentaire