PVS-Studio ja pidev integratsioon: TeamCity. Analüüs projektist Open RollerCoaster Tycoon 2

PVS-Studio ja pidev integratsioon: TeamCity. Analüüs projektist Open RollerCoaster Tycoon 2
Üks kõige asjakohasemaid PVS-Studio analüsaatori kasutusstsenaariume on selle integreerimine CI süsteemidega. Kuigi PVS-Studio projektianalüüsi saab peaaegu igasuguste pideva integratsiooni süsteemidega integreerida vaid paarikümne käsuga, jätkame selle protsessi mugavamaks muutmist. PVS-Studios on lisatud tugi analüsaatori väljundi konverteerimiseks TeamCity vormingusse — TeamCity Inspections Type. Vaadakem, kuidas see töötab.

Teave kasutatava tarkvara kohta

PVS-Studio — staatiline C, C++, C# ja Java koodi analüsaator, mis on mõeldud erinevate vigade leidmise ja parandamise ülesande lihtsustamiseks. Analüsaatorit saab kasutada Windowsis, Linuxis ja macOSis. Selles artiklis kasutame aktiivselt mitte ainult analüsaatorit, vaid ka mõningaid tööriistu selle jaotises.

CLMonitor — on jälgimise server, mis jälgib kompilaatorite käivitusi. Seda tuleb käivitada otse enne oma projekti koostamise alustamist. Jälgimisrežiimis püüab server kinni kõigi toetatud kompilaatorite käivitused. Oluline on märkida, et seda utiliiti saab kasutada ainult C/C++ projektide analüüsimiseks.

PlogConverter – on utiliit analüsaatori aruande konverteerimiseks erinevatesse formaatidesse.

Teave uuritava projekti kohta

Katsume seda funktsionaalsust praktilise näite põhjal - analüüsime OpenRCT2 projekti.

OpenRCT2 — on RollerCoaster Tycoon 2 (RCT2) mängu avatud rakendus, mis laiendab seda uute funktsioonide ja vigade parandamisega. Mängu protsess keerleb lõbustuspargi ehitamise ja hooldamise ümber, kus asuvad atraktsioonid, poed ja objektiid. Mängija peab püüdma teenida kasumit ja säilitama pargi head mainet, hoides seejuures külastajad õnnelikena. OpenRCT2 võimaldab mängida nii stsenaariumides kui ka liivakastis. Stsenaariumid nõuavad, et mängija täidaks teatud ülesande määratud aja jooksul, samas kui liivakast võimaldab mängijal luua paindlikuma pargi ilma igasuguste piirangute või rahaga seotud küsimusteta.

Seadistamine

Aja kokkuhoiu huvides jätan ma tõenäoliselt vahele installimisprotsessi ja alustan hetkest, mil mul on arvutis käivitatud TeamCity server. Peame minema: localhost:{installimisprotsessis määratud port}(minu puhul localhost:9090) ja sisestama sisselogimise andmed. Pärast sisselogimist kohtume järgmisega:

PVS-Studio ja pidev integratsioon: TeamCity. Analüüs projektist Open RollerCoaster Tycoon 2
Klõpsame nuppu Create Project. Järgmine, valime Manually ja täidame väljad.

PVS-Studio ja pidev integratsioon: TeamCity. Analüüs projektist Open RollerCoaster Tycoon 2
Pärast nupu vajutamist Loo, meid tervitab seadistuste aken.

PVS-Studio ja pidev integratsioon: TeamCity. Analüüs projektist Open RollerCoaster Tycoon 2
Klõpsame Create build configuration.

PVS-Studio ja pidev integratsioon: TeamCity. Analüüs projektist Open RollerCoaster Tycoon 2
Täidame väljad, klõpsame Loo. Me näeme akent, kus on versioonihaldussüsteemi valiku ettepanek. Kuna lähtekoodid asuvad juba kohalikult, vajutame Skip.

PVS-Studio ja pidev integratsioon: TeamCity. Analüüs projektist Open RollerCoaster Tycoon 2
Lõpuks liigume projekti seadistuste juurde.

PVS-Studio ja pidev integratsioon: TeamCity. Analüüs projektist Open RollerCoaster Tycoon 2
Lisame ehitusetapid, selleks klõpsame: Build steps -> Add build step.

PVS-Studio ja pidev integratsioon: TeamCity. Analüüs projektist Open RollerCoaster Tycoon 2
Siit valime:

  • Runner type -> Command Line
  • Run -> Custom Script

Kuna me teeme analüüsi projekti kompileerimise ajal, peavad ehitamine ja analüüs olema ühes etapis, seega täidame väljaku Custom Script:

PVS-Studio ja pidev integratsioon: TeamCity. Analüüs projektist Open RollerCoaster Tycoon 2
Loodud etappidel peatume hiljem. Oluline on, et analüsaatori laadimine, projekti ehitamine, selle analüüs, aruande genereerimine ja vormindamine võtaks kokku ainult üheksa rida koodi.

Viimane asi, mida peame tegema, on seadistada keskkonnamuutujad, mille kaudu olen mõned teed parandanud, et need oleksid paremini loetavad. Selleks liigume: Parameters -> Add new parameter ja lisame kolm muutuja:

PVS-Studio ja pidev integratsioon: TeamCity. Analüüs projektist Open RollerCoaster Tycoon 2
Jääb vaid vajutada nuppu Käita paremas ülanurgas. Kui projekti ehitamine ja analüüs käib, räägin teile skriptist.

Otse skript

Esialgu peame alla laadima värske PVS-Studio distributsiooni. Selleks kasutame pakihaldurit Ch chocolatey. Neile, kes soovivad rohkem teada saada, on olemas vastav artikkel:

choco install pvs-studio -y

Järgmisena käivitame projekti ehitamise jälgimise utiliidi CLMonitor.

%CLmon% monitor --attach

Siis viime projekti ehitamiseni, keskkonnamuutujana MSB on tee vajaliku MSBuildi versiooni jaoks

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

Sisestame PVS-Studio kasutajanime ja litsentsi võtme:

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

Peale ehitamise lõppu käivitame taas CLMonitori, et genereerida eelprotsessitud faile ja staatilist analüüsi:

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

Seejärel kasutame veel ühte utiliiti meie distributsioonist. PlogConverter muudab aruande standardse vormi TeamCity vormiks. Tänu sellele saame seda vaadata otse ehitamise aknas.

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

Viimase sammuna väljastame vormindatud aruande stdout, kus TeamCity parser selle haarab.

type "C:tempptest.plog_TeamCity.txt"

Skripti täielik kood:

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"

Vahepeal, projekti kogumine ja analüüs on edukalt lõpule viidud, saame minna vahekaardile Projects ja veenduda, et see nii on.

PVS-Studio ja pidev integratsioon: TeamCity. Analüüs projektist Open RollerCoaster Tycoon 2
Nüüd klõpsame Inspections Total, et minna üle analüsaatori aruande vaatamisele:

PVS-Studio ja pidev integratsioon: TeamCity. Analüüs projektist Open RollerCoaster Tycoon 2
Hoiatused on grupeeritud diagnostiliste reeglite numbrite kaupa. Koodi navigeerimiseks tuleb klõpsata hoiatuses oleva rida numbril. Paremas ülanurgas asuvale küsimärgi ikoonile klõpsamine avab uue vahekaardi dokumentatsiooniga. Samuti on võimalik koodis navigeerida, klõpsates analüsaatori hoiatuses oleva rida numbril. Eemalt navigeerimine on võimalik, kasutades SourceTreeRoot markerit. Need, kes on huvitatud analüsaatori töörežiimist, saavad tutvuda vastava osaga dokumentatsioon.

Analüsaatori töö tulemuste vaatamine

Pärast sellest ülesande ja seadistamise lõpetamist, soovitan vaadata mõningaid huvitavaid hoiatusi, mis leiti uuritavast projektist.

Hoiatus N1

V773 [CWE-401] Erand visati ilma 'result' pointerit vabastamata. Võimalik mäluleke. 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;
}

Analüsaator märkis vea, mille kohaselt pärast dünaamilist mälu eraldamist CreateObject, erandite tekkimisel mälu ei vabastata, mis omakorda viib mälu lekkimiseni.

Hoiatus N2

V501 On olemas identsed alamekspressioonid '(1ULL << WIDX_MONTH_BOX)' vasakul ja paremal '|' operaatorist. 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),
  ....
};

Vähegsed on vaid staatilised analüsaatorid, kes suudavad selle tähelepanutesti läbi teha. See näidis kopeerimisest ongi sellepärast hea.

Hoiatus N3

V703 On kummaline, et „flags” väli tuletatud klassis „RCT12BannerElement” ületab väljade klassis „RCT12TileElementBase”. Kontrollige ridu: RCT12.h:570, RCT12.h:259. libopenrct2 RCT12.h 570

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

Muidugi ei ole üks ja sama nimega muutuja kasutamine aluseks ja tuletatud klassis alati viga. Siiski eeldab pärimise tehnoloogia, et tuletatud klassis on kõik aluse klassi väljad. Kui kuulutame järglas klassis väljad sama nimega, põhjustame segadust.

Hoiatus N4

V793 On kummaline, et 'imageDirection / 8' avaldise tulemus on osa tingimusest. Võib-olla peaks see avaldis olema võrreldud millegi muuga. libopenrct2 ObservationTower.cpp 38

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

Vaatame seda lähemalt. Avaldise imageDirection / 8 on vale, kui imageDirection on vahemikus -7 kuni 7. Teine osa: (imageDirection / 8) != 3 kontrollib imageDirection vahemikust väljajäämist: -31 kuni -24 ja 24 kuni 31 vastavalt. Tundub väga kummaline kontrollida numbreid mingisse kindlasse vahemikku nii, ja isegi kui selle koodilõigu kontekstis pole viga, soovitaksin neid tingimusi ümber kirjutada selgemaks. See lihtsustaks oluliselt elu inimestele, kes seda koodi loevad ja toetavad.

Hoiatus N5

V587 Kummaline määramissegmenteerimise järjestus: A = B; B = A;. Kontrollige ridu: 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;
      ....
  }
  ....
}

See koodifragmendi on tõenäoliselt saadud dekompileerimise teel. Järeldub, et kustutati osa toimimatust koodist. Siiski on alles mõned operatsioonid üle cursorId, mis samuti ei sisalda erilist tähendust.

Hoiatus N6

V1004 [CWE-476] Näidatakse, et 'player' pointerit kasutati ohtlikult pärast nulli kontrollimist. Kontrollige ridu: 2085, 2094. libopenrct2 Network.cpp 2094

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

Seda koodi on üsna lihtne parandada, tuleb kas kolmandat korda kontrollida player nulli väärtuse suhtes või tuua see tingimuse keha sisse. Soovitaksin teist varianti:

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

Hoiatus N7

V547 [CWE-570] Väljend 'name == nullptr' on alati vale. libopenrct2 ServerList.cpp 102

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

Ühe käega saab vaevalt loetavast koodireast lahti ja lahendada probleemi kontrollimise osas nullptr. Soovitaksin muuta koodi järgmiselt:

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

Hoiatus N8

V1048 [CWE-1164] Muutujale 'ColumnHeaderPressedCurrentState' omistati sama väärtus. libopenrct2ui CustomListView.cpp 510

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

Kood näeb välja üsna veider. Mulle tundub, et tingimuses või muutuja taaskirjutamisel oli trükiviga ColumnHeaderPressedCurrentState mõisted false.

Kokkuvõte

Kuidas me näeme, PVS-Studio staatilise analüsaatori integreerimine oma projekti TeamCity'sse on suhteliselt lihtne. Selleks piisab, kui kirjutada vaid üks väike konfiguratsioonifail. Koodi kontrollimine võimaldab tuvastada probleemid kohe pärast kompileerimist, mis aitab neid kõrvaldada, kui parandamise keerukus ja maksumus on veel madalad.

PVS-Studio ja pidev integratsioon: TeamCity. Analüüs projektist Open RollerCoaster Tycoon 2
Kui soovite seda artiklit ingliskeelse publikuga jagada, siis palun kasutage tõlke linki: Vladislav Stolyarov. PVS-Studio ja pidev integreerimine: TeamCity. Analüüs avatud RollerCoaster Tycoon 2 projektist.

Allikas: habr.com

Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster