PVS-Studio un nepārtraukta integrācija: TeamCity. Projekta Open RollerCoaster Tycoon 2 analīze

PVS-Studio un nepārtraukta integrācija: TeamCity. Projekta Open RollerCoaster Tycoon 2 analīze
Viens no aktuālākajiem PVS-Studio analizatora izmantoÅ”anas scenārijiem ir tā integrācija ar CI sistēmām. Un, lai gan PVS-Studio projekta analÄ«zi no gandrÄ«z jebkuras nepārtrauktas integrācijas sistēmas var iebÅ«vēt tikai dažās komandās, mēs turpinām padarÄ«t Å”o procesu vēl ērtāku. PVS-Studio tagad atbalsta analizatora izvades pārveidoÅ”anu TeamCity formātā ā€” TeamCity Inspections Type. ApskatÄ«sim, kā tas darbojas.

Informācija par izmantoto programmatūru

PVS-studija ā€” statisks C, C++, C# un Java koda analizators, kas paredzēts, lai atvieglotu dažāda veida kļūdu atraÅ”anu un laboÅ”anu. Analizatoru var izmantot operētājsistēmās Windows, Linux un macOS. Å ajā rakstā mēs aktÄ«vi izmantosim ne tikai paÅ”u analizatoru, bet arÄ« dažas utilÄ«tas no tā izplatÄ«Å”anas.

CLMonitor ā€” ir uzraudzÄ«bas serveris, kas uzrauga kompilatora palaiÅ”anu. Tas ir jāpalaiž tieÅ”i pirms projekta izveides. Snooping režīmā serveris pārtvers visu atbalstÄ«to kompilatoru darbÄ«bas. Ir vērts atzÄ«mēt, ka Å”o utilÄ«tu var izmantot tikai C/C++ projektu analÄ«zei.

PlogConverter ā€“ utilÄ«ta analizatora atskaiÅ”u konvertÄ“Å”anai dažādos formātos.

Informācija par pētāmo projektu

Izmēģināsim Å”o funkcionalitāti praktiskā piemērā ā€“ analizēsim OpenRCT2 projektu.

OpenRCT2 - spēles RollerCoaster Tycoon 2 (RCT2) atklāta ievieÅ”ana, paplaÅ”inot to ar jaunām funkcijām un labojot kļūdas. Spēles mērÄ·is ir izveidot un uzturēt atrakciju parku, kurā ir atrakcijas, veikali un telpas. Spēlētājam jācenÅ”as gÅ«t peļņu un uzturēt parka labo reputāciju, vienlaikus nodroÅ”inot viesus laimÄ«gus. OpenRCT2 ļauj spēlēt gan scenārijā, gan smilÅ”u kastē. Scenāriji paredz, ka spēlētājam ir jāpaveic konkrēts uzdevums noteiktā laikā, savukārt Sandbox ļauj spēlētājam izveidot elastÄ«gāku parku bez jebkādiem ierobežojumiem un finansēm.

koriģēŔana

Lai ietaupÄ«tu laiku, es, iespējams, izlaidÄ«Å”u instalÄ“Å”anas procesu un sākÅ”u no brīža, kad manā datorā darbojas TeamCity serveris. Mums jāiet uz vietni localhost:{instalÄ“Å”anas procesā norādÄ«tais ports} (manā gadÄ«jumā localhost:9090) un jāievada autorizācijas dati. Pēc ieieÅ”anas mÅ«s sagaidÄ«s:

PVS-Studio un nepārtraukta integrācija: TeamCity. Projekta Open RollerCoaster Tycoon 2 analīze
NoklikŔķiniet uz pogas Izveidot projektu. Pēc tam atlasiet Manuāli un aizpildiet laukus.

PVS-Studio un nepārtraukta integrācija: TeamCity. Projekta Open RollerCoaster Tycoon 2 analīze
Pēc pogas nospieÅ”anas izveidot, mÅ«s sagaida logs ar iestatÄ«jumiem.

PVS-Studio un nepārtraukta integrācija: TeamCity. Projekta Open RollerCoaster Tycoon 2 analīze
NoklikŔķināsim Izveidojiet bÅ«vējuma konfigurāciju.

PVS-Studio un nepārtraukta integrācija: TeamCity. Projekta Open RollerCoaster Tycoon 2 analīze
Aizpildiet laukus un noklikŔķiniet uz izveidot. Tiek parādÄ«ts logs ar aicinājumu izvēlēties versiju kontroles sistēmu. Tā kā avoti jau atrodas lokāli, noklikŔķiniet uz Izlaist.

PVS-Studio un nepārtraukta integrācija: TeamCity. Projekta Open RollerCoaster Tycoon 2 analīze
Visbeidzot, mēs pārejam pie projekta iestatījumiem.

PVS-Studio un nepārtraukta integrācija: TeamCity. Projekta Open RollerCoaster Tycoon 2 analīze
Pievienosim montāžas soļus, lai to izdarÄ«tu, noklikŔķiniet: BÅ«vÄ“Å”anas soļi ā€”> Pievienot bÅ«vÄ“Å”anas soli.

PVS-Studio un nepārtraukta integrācija: TeamCity. Projekta Open RollerCoaster Tycoon 2 analīze
Šeit mēs izvēlamies:

  • Skrējēja veids -> Komandrinda
  • Palaist -> Pielāgots skripts

Tā kā mēs veiksim analÄ«zi projekta apkopoÅ”anas laikā, montāžai un analÄ«zei jābÅ«t vienam solim, tāpēc aizpildiet lauku Pielāgots skripts:

PVS-Studio un nepārtraukta integrācija: TeamCity. Projekta Open RollerCoaster Tycoon 2 analīze
AtseviŔķus soļus apskatÄ«sim vēlāk. Ir svarÄ«gi, lai analizatora ielāde, projekta salikÅ”ana, analÄ«ze, atskaites izvadÄ«Å”ana un formatÄ“Å”ana aizņem tikai vienpadsmit koda rindiņas.

Pēdējā lieta, kas mums jādara, ir vides mainÄ«go iestatÄ«Å”ana, un esmu aprakstÄ«jis dažus veidus, kā uzlabot to lasāmÄ«bu. Lai to izdarÄ«tu, turpināsim: Parametri -> Pievienot jaunu parametru un pievienojiet trÄ«s mainÄ«gos:

PVS-Studio un nepārtraukta integrācija: TeamCity. Projekta Open RollerCoaster Tycoon 2 analīze
Viss, kas jums jādara, ir jānospiež poga skrējiens augŔējā labajā stÅ«rÄ«. Kamēr projekts tiek montēts un analizēts, es jums pastāstÄ«Å”u par scenāriju.

TieŔi skripts

Pirmkārt, mums ir jālejupielādē jaunākā PVS-Studio izplatÄ«Å”ana. Å im nolÅ«kam mēs izmantojam Chocolatey pakotņu pārvaldnieku. Tiem, kas vēlas uzzināt vairāk par Å”o, ir atbilstoÅ”s raksts:

choco install pvs-studio -y

Pēc tam palaidÄ«sim CLMonitor projekta bÅ«vÄ“Å”anas izsekoÅ”anas utilÄ«tu.

%CLmon% monitor ā€“-attach

Tad mēs veidosim projektu kā vides mainÄ«go MSB ir ceļŔ uz MSBuild versiju, kas man jāveido

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

IevadÄ«sim PVS-Studio pieteikÅ”anās un licences atslēgu:

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

Kad izveide ir pabeigta, vēlreiz palaidiet CLMonitor, lai Ä£enerētu iepriekÅ” apstrādātus failus un statisko analÄ«zi:

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

Tad mēs izmantosim citu utilÄ«tu no mÅ«su izplatÄ«Å”anas. PlogConverter pārveido atskaiti no standarta formāta uz TeamCity specifisku formātu. Pateicoties tam, mēs to varēsim skatÄ«t tieÅ”i bÅ«vÄ“Å”anas logā.

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

Pēdējais solis ir parādīt formatēto pārskatu stdout, kur to paņems TeamCity parsētājs.

type "C:tempptest.plog_TeamCity.txt"

Pilns skripta kods:

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"

Pa to laiku projekta montāža un analīze ir veiksmīgi pabeigta, varam doties uz cilni AKTIVITĀTES un pārliecinieties par to.

PVS-Studio un nepārtraukta integrācija: TeamCity. Projekta Open RollerCoaster Tycoon 2 analīze
Tagad noklikŔķiniet uz Pārbaudes Kopālai pārietu uz analizatora atskaites apskati:

PVS-Studio un nepārtraukta integrācija: TeamCity. Projekta Open RollerCoaster Tycoon 2 analīze
BrÄ«dinājumi ir sagrupēti pēc diagnostikas noteikumu numuriem. Lai pārvietotos pa kodu, jums jānoklikŔķina uz rindas numura ar brÄ«dinājumu. NoklikŔķinot uz jautājuma zÄ«mes augŔējā labajā stÅ«rÄ«, tiks atvērta jauna cilne ar dokumentāciju. Varat arÄ« pārvietoties pa kodu, noklikŔķinot uz rindas numura ar analizatora brÄ«dinājumu. Lietojot, ir iespējama navigācija no attālā datora SourceTreeRoot marÄ·ieris. Ikviens, kurÅ” interesējas par Å”o analizatora darbÄ«bas režīmu, var iepazÄ«ties ar atbilstoÅ”o sadaļu dokumentācija.

Analizatora rezultātu apskate

Tagad, kad esam pabeiguÅ”i bÅ«vējuma izvietoÅ”anu un konfigurÄ“Å”anu, apskatÄ«sim dažus interesantus brÄ«dinājumus, kas atrodami aplÅ«kotajā projektā.

Brīdinājums N1

V773 [CWE-401] Izņēmums tika izmests, neatlaižot 'rezultāta' rādītāju. Iespējama atmiņas noplūde. libopenct2 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;
}

Analizators pamanÄ«ja kļūdu, kas radās pēc dinamiskas atmiņas pieŔķirÅ”anas CreateObject, kad notiek izņēmums, atmiņa netiek notÄ«rÄ«ta un rodas atmiņas noplÅ«de.

Brīdinājums N2

V501 Ir identiskas apakŔizteiksmes '(1ULL << WIDX_MONTH_BOX)' pa kreisi un pa labi no '|' operators. libopenct2ui 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),
  ....
};

Tikai daži cilvēki, izņemot statisko analizatoru, varētu izturēt Å”o uzmanÄ«bas pārbaudi. Å is kopÄ“Å”anas un ielÄ«mÄ“Å”anas piemērs ir labs tieÅ”i Ŕī iemesla dēļ.

Brīdinājumi N3

V703 Ir dÄ«vaini, ka lauks ā€œkarogiā€ atvasinātajā klasē ā€œRCT12BannerElementā€ pārraksta lauku bāzes klasē ā€œRCT12TileElementBaseā€. Pārbaudes lÄ«nijas: RCT12.h:570, RCT12.h:259. libopenct2 RCT12.h 570

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

Protams, mainÄ«gā ar tādu paÅ”u nosaukumu izmantoÅ”ana pamatklasē un pēcnācējā ne vienmēr ir kļūda. Tomēr pati mantojuma tehnoloÄ£ija pieņem, ka visi vecāku klases lauki atrodas bērnu klasē. Deklarējot laukus ar tādu paÅ”u nosaukumu mantiniekā, mēs radām neskaidrÄ«bas.

Brīdinājums N4

V793 Ir dÄ«vaini, ka priekÅ”raksta ā€œimageDirection / 8ā€ rezultāts ir nosacÄ«juma sastāvdaļa. Iespējams, Å”is apgalvojums bÅ«tu jāsalÄ«dzina ar kaut ko citu. libopenct2 ObservationTower.cpp 38

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

ApskatÄ«sim tuvāk. Izteiksme imageDirection/8 bÅ«s nepatiess, ja imageDirection ir diapazonā no -7 lÄ«dz 7. Otrā daļa: (imageDirection / 8) != 3 pārbaudes imageDirection par atraÅ”anos ārpus diapazona: attiecÄ«gi no -31 lÄ«dz -24 un no 24 lÄ«dz 31. Man Ŕķiet diezgan dÄ«vaini Ŕādā veidā pārbaudÄ«t, vai skaitļi ir iekļauti noteiktā diapazonā, un, pat ja Å”ajā koda daļā nav kļūdu, es ieteiktu Å”os nosacÄ«jumus pārrakstÄ«t, lai tie bÅ«tu skaidrāki. Tas padarÄ«tu dzÄ«vi daudz vieglāku cilvēkiem, kuri lasÄ«tu un uzturētu Å”o kodu.

Brīdinājums N5

V587 Šāda veida uzdevumu nepāra secība: A = B; B = A;. Pārbaudes rindiņas: 1115, 1118. libopenct2ui 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;
      ....
  }
  ....
}

Å is koda fragments, visticamāk, tika iegÅ«ts dekompilācijas ceļā. Tad, spriežot pēc atstātā komentāra, daļa no nestrādājoŔā koda tika izņemta. Tomēr atlikuÅ”as vēl pāris operācijas kursora ID, kam arÄ« nav lielas jēgas.

Brīdinājums N6

V1004 [CWE-476] Atskaņotāja rādÄ«tājs tika izmantots nedroÅ”i pēc tam, kad tika pārbaudÄ«ts pret nullptr. Pārbaudes rindiņas: 2085, 2094. libopenct2 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);                    // <=
  }
  ....
}

Å o kodu ir diezgan viegli labot; jums tas tikai jāpārbauda treÅ”o reizi atskaņotājs uz nulles rādÄ«tāju vai pievienojiet to nosacÄ«juma priekÅ”raksta pamattekstam. Es ieteiktu otro variantu:

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

Brīdinājums N7

V547 [CWE-570] Izteiksme 'name == nullptr' vienmēr ir nepatiesa. libopenct2 ServerList.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));
    ....
  }
  ....
}

Varat vienā rāvienā atbrÄ«voties no grÅ«ti salasāmas koda rindas un atrisināt problēmu, pārbaudot, vai nullptr. Es iesaku mainÄ«t kodu Ŕādi:

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

Brīdinājums N8

V1048 [CWE-1164] MainÄ«gajam 'ColumnHeaderPressedCurrentState' tika pieŔķirta tāda pati vērtÄ«ba. libopenct2ui CustomListView.cpp 510

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

Kods izskatās diezgan dīvains. Man Ŕķiet, ka bija drukas kļūda vai nu nosacījumā, vai arī mainot mainīgo ColumnHeaderPressedCurrentState nozīme nepatiess.

secinājums

Kā redzam, PVS-Studio statiskā analizatora integrÄ“Å”ana TeamCity projektā ir pavisam vienkārÅ”a. Lai to izdarÄ«tu, pietiek ar vienu nelielu konfigurācijas failu. Koda pārbaude ļaus identificēt problēmas uzreiz pēc montāžas, kas palÄ«dzēs tās novērst, ja izmaiņu sarežģītÄ«ba un izmaksas joprojām ir zemas.

PVS-Studio un nepārtraukta integrācija: TeamCity. Projekta Open RollerCoaster Tycoon 2 analīze
Ja vēlaties dalÄ«ties ar Å”o rakstu ar angliski runājoÅ”u auditoriju, lÅ«dzu, izmantojiet tulkoÅ”anas saiti: Vladislavs Stoļarovs. PVS-Studio un nepārtraukta integrācija: TeamCity. Projekta Open RollerCoaster Tycoon 2 analÄ«ze.

Avots: www.habr.com

Pievieno komentāru