PVS-Studio ja pidev integreerimine: TeamCity. Open RollerCoaster Tycoon 2 projekti analüüs.

PVS-Studio ja pidev integreerimine: TeamCity. Open RollerCoaster Tycoon 2 projekti analüüs.
Üks PVS-Studio analüsaatorite kõige asjakohasemaid kasutusstsenaariume on selle integreerimine CI süsteemidega. Ja kuigi PVS-Studio projektianalüüsi saab praktiliselt iga continuous integration süsteemi alla integreerida vaid mõne käsuga, töötame me selle protsessi veelgi mugavdamise nimel. PVS-Studiosse on lisatud tugi analüsaatori väljundi ümberkujundamiseks TeamCity formaati — TeamCity Inspections Type. Vaatame, kuidas see töötab.

Kasutatava tarkvara teave

PVS-Studio — staatiline analüsaator C, C++, C# ja Java koodi jaoks, mis on mõeldud erinevate vigade leidmise ja parandamise ülesande lihtsustamiseks. Analüsaatorit saab kasutada Windowsis, Linuxis ja macOS-is. Käesolevas artiklis kasutame me aktiivselt mitte ainult analüsaatorit, vaid ka mõningaid utiliite selle distributsioonist.

CLMonitor — on jälgimisteenuse server, mis jälgib kompilaatorite käivitusi. Seda tuleb käivitada otse enne oma projekti kokkupanekut. Jälgimismooduliga server jääb kinni kõikide toetatud kompilaatorite käivitustele. Tasub märkida, et seda utiliiti saab kasutada ainult C/C++ projektide analüüsimiseks.

PlogConverter – tööriist analüüsiharu aruande konverteerimiseks erinevatesse formaatidesse.

Teave uuritava projekti kohta

Katsetame seda funktsionaalsust praktilise näitega – analüüsime projekti OpenRCT2.

OpenRCT2 — avatud rakendus mängust RollerCoaster Tycoon 2 (RCT2), mis laiendab seda uute funktsioonidega ja parandab vigu. Mängu sisu keskendub lõbustuspargi ehitamisele ja haldamisele, kus asuvad atraktsioonid, kauplused ja rajatised. Mängija peab püüdma teenida tulu ja säilitama pargi head mainet, hoides samal ajal külalised õnnelikena. OpenRCT2 võimaldab mängida nii stsenaariumide kui ka liivakasti režiimis. Stsenaariumid nõuavad, et mängija täidaks teatud ülesande kindlaksmääratud ajavahemikus, samas kui liivakast võimaldab mängijal ehitada paindlikuma pargi ilma piirangute või rahaliste takistusteta.

Seadistamine

Aja kokkuhoiu huvides jäta vahele paigaldusprotsess ja alustan hetkest, mil mul on TeamCity server arvutis käivitunud. Peame minema: localhost:{paigaldusprotsessis määratud port}(minu puhul, localhost:9090) ja sisestama autentimisandmed. Pärast sisselogimist näeme:

PVS-Studio ja pidev integreerimine: TeamCity. Open RollerCoaster Tycoon 2 projekti analüüs.
Klõpsame nuppu Create Project. Seejärel valime Manually ja täidame väljad.

PVS-Studio ja pidev integreerimine: TeamCity. Open RollerCoaster Tycoon 2 projekti analüüs.
Pärast nupu vajutamist Loo, leiame end seadetega aknast.

PVS-Studio ja pidev integreerimine: TeamCity. Open RollerCoaster Tycoon 2 projekti analüüs.
Klõpsame Create build configuration.

PVS-Studio ja pidev integreerimine: TeamCity. Open RollerCoaster Tycoon 2 projekti analüüs.
Täidame väljad ja vajutame Loo. Näeme aken, kus pakutakse versioonikontrollisüsteemi valikut. Kuna lähtekoodid on juba kohalikult saadaval, vajutame Skip.

PVS-Studio ja pidev integreerimine: TeamCity. Open RollerCoaster Tycoon 2 projekti analüüs.
Lõpuks liigume projekti seadete juurde.

PVS-Studio ja pidev integreerimine: TeamCity. Open RollerCoaster Tycoon 2 projekti analüüs.
Lisame ehitusetapid, selleks vajutame: Build steps -> Add build step.

PVS-Studio ja pidev integreerimine: TeamCity. Open RollerCoaster Tycoon 2 projekti analüüs.
Siit valime:

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

Kuna me viime analüüsi läbi projekti kompileerimise ajal, peavad ehitamine ja analüüs olema üks samm, seega täidame välja Custom Script:

PVS-Studio ja pidev integreerimine: TeamCity. Open RollerCoaster Tycoon 2 projekti analüüs.
Peatume eraldi sammudel hiljem. Oluline on, et analüsaatori laadimine, projekti ehitamine, selle analüüsimine, aruande genereerimine ja vormindamine võtaks kokku vaid üheteist rida koodi.

Viimane asi, mida peame tegema, on keskkonnamuutujate seadistamine, mille abil olen mõnel teel lugemise hõlbustamiseks eraldi määranud. Selleks liigume: Parameters -> Add new parameter ja lisame kolm muutujat:

PVS-Studio ja pidev integreerimine: TeamCity. Open RollerCoaster Tycoon 2 projekti analüüs.
Jääb vaid vajutada nuppu Run paremas ülanurgas. Kui projekt on ehitamisel ja analüüsitakse, räägin teile skriptist.

Tõenäoliselt skript

Alustamiseks peame alla laadima värske PVS-Studio distributsiooni. Selleks kasutame pakihaldurit Chocoatey. Rohkem teavet soovivatele on olemas vastav artikkel:

choco install pvs-studio -y

Seejärel käivitame projekti ehituse jälgimise utiliidi CLMonitor.

%CLmon% monitor --attach

Seejärel teeme projekti ehituse, kus keskkonnaparameeter MSB esindab teed vajalikku MSBuild versioonile minu ehitamiseks

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

Sisestame PVS-Studio kasutajanime ja litsentsivõtme:

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

Ehituse lõppedes käivitame uuesti CLMonitor, et genereerida eelkoostatavad failid ja staatiline analüüs:

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

Peale seda kasutame veel ühte meie distributsioonis olevat utiliiti. PlogConverter teisendab aruande standardvormist TeamCity spetsiifiliseks vorminguks. Nii saame seda vaadata otse ehitusaknas.

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

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

type "C:tempptest.plog_TeamCity.txt"

Täielik skriptikood:

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 on projekti koostamine ja analüüsimine edukalt lõpetatud, saame liikuda vahekaardile Projektid ja veenduda selles.

PVS-Studio ja pidev integreerimine: TeamCity. Open RollerCoaster Tycoon 2 projekti analüüs.
Nüüd klikkige Kokku inspektsioonid, et minna analüüsaraporti vaatamisele:

PVS-Studio ja pidev integreerimine: TeamCity. Open RollerCoaster Tycoon 2 projekti analüüs.
Hoiatused on grupeeritud diagnoosimisreeglite numbrite järgi. Koodis navigeerimiseks tuleb klikkida hoiatusse seotud real oleva numbri peale. Küsimärgi puudutamine paremas ülanurgas avab uue vahekaart dokumentatsiooniga. Samuti on võimalik navigeerida koodis, klikkides analüsaatori hoiatusse seotud real oleva numbri peale. Kaugjuhtimise režiimi kasutamine on võimalik SourceTreeRoot markerit. Need, keda huvitab antud analüsaatori töörežiim, võivad tutvuda vastava jaotisega dokumentatsioonis.

Analüsaatori töö tulemuste vaatamine

Kui oleme lõpetanud kogumise juurutamise ja seadistamise, vaatame mõningaid huvitavaid hoiatusi, mis uuritavas projektis avastati.

Hoiatus N1

V773 [CWE-401] Erand visati, ilma et 'result' näidik vabastataks. Mälu lekke võimalus on olemas. libopenrct2 ObjectFactory.cpp 443

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

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("Kehtetu objekti tüüp");
  }
  return result;
}

Analüüsimootor märkas viga, et pärast dünaamilist mälu eraldamist CreateObject, erandi korral mälu ei puhastata, mis põhjustab mälu lekke.

Hoiatus N2

V501 On identsed alamavaldised '(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äga vähesed, välja arvatud staatiline analüsaator, suudaksid selle tähelepanelikkuse testi läbida. See copy-paste näide on hea just sellega.

Hoiatused N3

V703 On kummaline, et tuletatud klassi 'RCT12BannerElement' 'flags' väljad ületavad baasklassi 'RCT12TileElementBase' väljad. Kontrollige ridu: RCT12.h:570, RCT12.h:259. libopenrct2 RCT12.h 570

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

Tõepoolest, muutuja kasutamine, millel on sama nimi põhiklassis ja pärandis, ei ole alati viga. Kuid päranditehnoloogia eeldab, et kõik vanema klassi väljad on olemas lapsklassides. Kui meil on pärandis väljad sama nimega, tekitame me segadust.

Hoiatus N4

V793 On kummaline, et näitaja 'imageDirection / 8' tulemus on osa tingimusest. Võib-olla oleks see väljend pidanud olema võrreldud millegagi muuga. libopenrct2 ObservationTower.cpp 38

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

Vaatame seda lähemalt. Väljend imageDirection / 8 on vale juhul, kui imageDirection on vahemikus -7 kuni 7. Teine osa: (imageDirection / 8) != 3 kontrollib imageDirection kas see on vahemikust väljas: vahemikus -31 kuni -24 ja vahemikus 24 kuni 31. Ma leian kummalisena kontrollida numbreid niimoodi kindlasse vahemikku kuuluvateks ja isegi kui sellel koodil pole viga, soovitaksin ma neid tingimusi kirjutada selgemaks. See lihtsustaks oluliselt nende inimeste elu, kes seda koodi loevad ja toetavad.

Hoiatus N5

V587 Seda tüüpi ülesannete kummaline 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;                                 // <=
      // Akna sündmus WE_UNKNOWN_0E kutsuti siin,
      // kuid ükski akendest ei rakendanud tegelikult töötlejat ja
      // ei ole teada, milleks see mõeldud oli
      cursorId = edi;                                 // <=
      if ((ebx & 0xFF) != 0)
      {
        set_cursor(cursorId);
        return;
      }
      break;
      ....
  }
  ....
}

See koodilõik on tõenäoliselt saadud dekompileerimise teel. Siis, jääks koodist maha jättes tehtud kommentaari, on eemaldatud osa mittetöötavast koodist. Siiski on jäänud paar operatsiooni cursorId, mis samuti ei kanna erilist tähendust.

Hoiatamine N6

V1004 [CWE-476] 'player' pointerit kasutati enne seda ohtlikult, kui see oli kontrollitud nullptr vastu. 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 suhteliselt lihtne parandada, tuleb lihtsalt teha see kolmas kord kontroll player null viitena, või lisada see tingimuslause keha. Soovitan 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));
    ....
  }
  ....
}

Ühega on võimalik vabaneda raskesti loetavast koodirivist ja lahendada probleem kontrolliga nullptr. Soovitan 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' anti sama väärtus. libopenrct2ui CustomListView.cpp 510

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

Kood näeb üsna kummaline välja. Tundub, et kas lahenduses või muutuja uuesti määramisel oli viga. ColumnHeaderPressedCurrentState väärtusi false.

Kokkuvõte

Nagu näeme, on PVS-Studio staatilise analüsaatori integreerimine oma projekti TeamCitys üsna lihtne. Selleks piisab vaid ühe väikese konfiguratsioonifaili loomise. Koodi kontrollimine võimaldab probleemid avastada kohe pärast ehitamist, mis aitab neid parandada, kui nende keerukus ja maksumus on veel madalad.

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

Allikas: habr.com

Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster