PVS-Studio na Ushirikiano unaoendelea: TeamCity. Uchambuzi wa mradi wa Open RollerCoaster Tycoon 2

PVS-Studio na Ushirikiano unaoendelea: TeamCity. Uchambuzi wa mradi wa Open RollerCoaster Tycoon 2
Moja ya matukio ya sasa ya kutumia analyzer ya PVS-Studio ni ushirikiano wake na mifumo ya CI. Na ingawa uchanganuzi wa mradi wa PVS-Studio kutoka kwa karibu mfumo wowote wa ujumuishaji unaoendelea unaweza kujengwa kwa amri chache tu, tunaendelea kufanya mchakato huu kuwa rahisi zaidi. PVS-Studio sasa ina usaidizi wa kubadilisha matokeo ya kichanganuzi kuwa umbizo la TeamCity - Aina ya Ukaguzi wa TeamCity. Hebu tuone jinsi inavyofanya kazi.

Taarifa kuhusu programu iliyotumiwa

PVS-Studio β€” kichanganuzi tuli cha msimbo wa C, C++, C# na Java, iliyoundwa ili kuwezesha kazi ya kutafuta na kusahihisha aina mbalimbali za makosa. Analyzer inaweza kutumika kwenye Windows, Linux na macOS. Katika makala hii tutatumia kikamilifu si tu analyzer yenyewe, lakini pia baadhi ya huduma kutoka kwa usambazaji wake.

CLMonitor - ni seva ya ufuatiliaji ambayo inafuatilia uzinduzi wa mkusanyaji. Ni lazima iendeshwe mara moja kabla ya kuanza kujenga mradi wako. Katika hali ya kuchungulia, seva itakatiza utendakazi wa vikusanyaji vyote vinavyotumika. Ni vyema kutambua kwamba shirika hili linaweza kutumika tu kuchambua miradi ya C/C++.

Kibadilishaji cha Plog - matumizi ya kubadilisha ripoti za kichanganuzi kuwa muundo tofauti.

Taarifa kuhusu mradi unaofanyiwa utafiti

Wacha tujaribu utendakazi huu kwenye mfano wa vitendo - wacha tuchambue mradi wa OpenRCT2.

OpenRCT2 - utekelezaji wazi wa mchezo RollerCoaster Tycoon 2 (RCT2), kupanua kwa kazi mpya na kurekebisha mende. Mchezo unahusu kujenga na kudumisha bustani ya burudani iliyo na wapanda farasi, maduka na vifaa. Mchezaji lazima ajaribu kupata faida na kudumisha sifa nzuri ya mbuga huku akiwaweka wageni furaha. OpenRCT2 hukuruhusu kucheza katika hali na sanduku la mchanga. Matukio yanahitaji mchezaji kukamilisha kazi mahususi ndani ya muda uliowekwa, huku Sandbox akimruhusu mchezaji kujenga bustani inayonyumbulika zaidi bila vikwazo au fedha zozote.

marekebisho

Ili kuokoa muda, labda nitaruka mchakato wa usakinishaji na kuanza kutoka wakati ninapokuwa na seva ya TeamCity inayoendesha kwenye kompyuta yangu. Tunahitaji kwenda kwa: localhost:{port iliyobainishwa wakati wa usakinishaji} (kwa upande wangu, localhost:9090) na uweke data ya uidhinishaji. Baada ya kuingia tutasalimiwa na:

PVS-Studio na Ushirikiano unaoendelea: TeamCity. Uchambuzi wa mradi wa Open RollerCoaster Tycoon 2
Bonyeza kitufe cha Unda Mradi. Ifuatayo, chagua kwa mikono na ujaze sehemu.

PVS-Studio na Ushirikiano unaoendelea: TeamCity. Uchambuzi wa mradi wa Open RollerCoaster Tycoon 2
Baada ya kubonyeza kitufe Kujenga, tunasalimiwa na dirisha na mipangilio.

PVS-Studio na Ushirikiano unaoendelea: TeamCity. Uchambuzi wa mradi wa Open RollerCoaster Tycoon 2
Hebu bonyeza Unda usanidi wa muundo.

PVS-Studio na Ushirikiano unaoendelea: TeamCity. Uchambuzi wa mradi wa Open RollerCoaster Tycoon 2
Jaza mashamba na ubofye Kujenga. Tunaona dirisha ikikuuliza uchague mfumo wa kudhibiti toleo. Kwa kuwa vyanzo tayari viko ndani ya nchi, bofya Ruka.

PVS-Studio na Ushirikiano unaoendelea: TeamCity. Uchambuzi wa mradi wa Open RollerCoaster Tycoon 2
Hatimaye, tunaendelea kwenye mipangilio ya mradi.

PVS-Studio na Ushirikiano unaoendelea: TeamCity. Uchambuzi wa mradi wa Open RollerCoaster Tycoon 2
Wacha tuongeze hatua za kusanyiko, kufanya bonyeza hii: Jenga hatua -> Ongeza hatua ya ujenzi.

PVS-Studio na Ushirikiano unaoendelea: TeamCity. Uchambuzi wa mradi wa Open RollerCoaster Tycoon 2
Hapa tunachagua:

  • Aina ya mkimbiaji -> Mstari wa Amri
  • Endesha -> Hati Maalum

Kwa kuwa tutafanya uchambuzi wakati wa ujumuishaji wa mradi, mkusanyiko na uchambuzi unapaswa kuwa hatua moja, kwa hivyo jaza uwanja Hati maalum:

PVS-Studio na Ushirikiano unaoendelea: TeamCity. Uchambuzi wa mradi wa Open RollerCoaster Tycoon 2
Tutaangalia hatua za mtu binafsi baadaye. Ni muhimu kwamba kupakia kichanganuzi, kukusanya mradi, kuchambua, kutoa ripoti na kupangilia inachukua mistari kumi na moja tu ya nambari.

Jambo la mwisho tunalohitaji kufanya ni kuweka anuwai za mazingira, ambazo nimeelezea njia kadhaa za kuboresha usomaji wao. Ili kufanya hivyo, wacha tuendelee: Vigezo -> Ongeza parameta mpya na kuongeza vigezo vitatu:

PVS-Studio na Ushirikiano unaoendelea: TeamCity. Uchambuzi wa mradi wa Open RollerCoaster Tycoon 2
Unachohitajika kufanya ni kubonyeza kitufe Kukimbia kwenye kona ya juu kulia. Wakati mradi unakusanywa na kuchambuliwa, nitakuambia kuhusu script.

Hati ya moja kwa moja

Kwanza, tunahitaji kupakua usambazaji wa hivi karibuni wa PVS-Studio. Kwa hili tunatumia meneja wa kifurushi cha Chocolatey. Kwa wale ambao wanataka kujua zaidi kuhusu hili, kuna sambamba makala:

choco install pvs-studio -y

Ifuatayo, wacha tuzindue matumizi ya ufuatiliaji wa ujenzi wa mradi wa CLMonitor.

%CLmon% monitor –-attach

Kisha tutaunda mradi kama mabadiliko ya mazingira MSB ndio njia ya toleo la MSBuild ninalohitaji kujenga

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

Wacha tuingize kitufe cha kuingia na leseni kwa PVS-Studio:

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

Baada ya ujenzi kukamilika, endesha CLMonitor tena ili kutoa faili zilizosindika na uchambuzi wa tuli:

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

Kisha tutatumia matumizi mengine kutoka kwa usambazaji wetu. PlogConverter hubadilisha ripoti kutoka umbizo la kawaida hadi umbizo mahususi la TeamCity. Shukrani kwa hili, tutaweza kuiona moja kwa moja kwenye dirisha la kujenga.

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

Hatua ya mwisho ni kuonyesha ripoti iliyoumbizwa ndani stdout, ambapo itachukuliwa na mchanganuzi wa TeamCity.

type "C:tempptest.plog_TeamCity.txt"

Nambari kamili ya hati:

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"

Wakati huo huo, mkusanyiko na uchambuzi wa mradi umekamilika kwa mafanikio, tunaweza kwenda kwenye kichupo Miradi na uhakikishe.

PVS-Studio na Ushirikiano unaoendelea: TeamCity. Uchambuzi wa mradi wa Open RollerCoaster Tycoon 2
Sasa hebu bonyeza Jumla ya Ukaguzikwenda kwa kutazama ripoti ya mchambuzi:

PVS-Studio na Ushirikiano unaoendelea: TeamCity. Uchambuzi wa mradi wa Open RollerCoaster Tycoon 2
Maonyo yanapangwa kulingana na nambari za sheria za utambuzi. Ili kupitia msimbo, unahitaji kubofya nambari ya mstari na onyo. Kubofya alama ya swali kwenye kona ya juu kulia kutakufungua kichupo kipya chenye nyaraka. Unaweza pia kupitia msimbo kwa kubofya nambari ya mstari na onyo la kichanganuzi. Urambazaji kutoka kwa kompyuta ya mbali inawezekana wakati wa kutumia SourceTreeRoot alama. Mtu yeyote ambaye ana nia ya hali hii ya uendeshaji wa analyzer anaweza kujitambulisha na sehemu inayofanana nyaraka.

Kuangalia matokeo ya analyzer

Sasa kwa kuwa tumemaliza kupeleka na kusanidi muundo, hebu tuangalie maonyo kadhaa ya kupendeza yanayopatikana katika mradi tunaoangalia.

Onyo N1

V773 [CWE-401] Isipokuwa ilitupwa bila kutoa kielekezi cha 'matokeo'. Uvujaji wa kumbukumbu unawezekana. 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;
}

Mchanganuzi aligundua hitilafu ambayo baada ya kugawa kumbukumbu kwa nguvu CreateObject, wakati ubaguzi hutokea, kumbukumbu haijafutwa, na uvujaji wa kumbukumbu hutokea.

Onyo N2

V501 Kuna maneno madogo yanayofanana '(1ULL << WIDX_MONTH_BOX)' upande wa kushoto na kulia wa '|' mwendeshaji. 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),
  ....
};

Watu wachache isipokuwa kichanganuzi tuli wanaweza kufaulu mtihani huu wa usikivu. Mfano huu wa kunakili-kubandika ni mzuri kwa sababu hii haswa.

Maonyo N3

V703 Ni ajabu kwamba uga wa 'bendera' katika darasa linalotolewa 'RCT12BannerElement' hubatilisha uga katika daraja la msingi 'RCT12TileElementBase'. Angalia mistari: RCT12.h:570, RCT12.h:259. libopenrct2 RCT12.h 570

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

Kwa kweli, kutumia kibadilishaji chenye jina moja katika darasa la msingi na katika kizazi sio kosa kila wakati. Hata hivyo, teknolojia ya urithi yenyewe inadhani kwamba nyanja zote za darasa la wazazi zipo katika darasa la mtoto. Kwa kutangaza mashamba yenye jina moja katika mrithi, tunaleta mkanganyiko.

Onyo N4

V793 Ni ajabu kwamba matokeo ya taarifa ya 'imageDirection / 8' ni sehemu ya hali hiyo. Pengine, kauli hii inapaswa kuwa ikilinganishwa na kitu kingine. libopenrct2 ObservationTower.cpp 38

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

Hebu tuangalie kwa karibu. Kujieleza Mwelekeo wa picha/8 itakuwa uongo kama Mwelekeo wa picha iko katika safu kutoka -7 hadi 7. Sehemu ya pili: (mwelekeo wa picha / 8) != 3 hundi Mwelekeo wa picha kwa kuwa nje ya masafa: kutoka -31 hadi -24 na kutoka 24 hadi 31, kwa mtiririko huo. Inaonekana kwangu kuwa ya kushangaza sana kuangalia nambari za kujumuishwa katika safu fulani kwa njia hii na, hata ikiwa hakuna hitilafu katika kipande hiki cha nambari, ningependekeza kuandika tena masharti haya kuwa wazi zaidi. Hii ingerahisisha maisha kwa watu ambao wangesoma na kudumisha nambari hii.

Onyo N5

V587 Mlolongo usio wa kawaida wa kazi za aina hii: A = B; B = A;. Angalia mistari: 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;
      ....
  }
  ....
}

Kipande hiki cha msimbo kina uwezekano mkubwa kilipatikana kwa kutengana. Kisha, kwa kuzingatia maoni yaliyoachwa, sehemu ya msimbo usiofanya kazi iliondolewa. Walakini, bado kuna shughuli kadhaa zilizobaki kitambulisho cha mshale, ambayo pia haina maana sana.

Onyo N6

V1004 [CWE-476] Kielekezi cha 'mchezaji' kilitumika kwa njia isiyo salama baada ya kuthibitishwa dhidi ya nullptr. Angalia mistari: 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);                    // <=
  }
  ....
}

Nambari hii ni rahisi kusahihisha; unahitaji tu kuiangalia mara ya tatu mchezaji kwa kielekezi kisicho na maana, au uiongeze kwenye mwili wa taarifa ya masharti. Ningependekeza chaguo la pili:

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

Onyo N7

V547 [CWE-570] Usemi 'jina == nullptr' sio kweli kila wakati. libopenrct2 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));
    ....
  }
  ....
}

Unaweza kuondoa safu ngumu kusoma ya nambari kwa mkupuo mmoja na kutatua shida kwa kuangalia nullptr. Ninapendekeza kubadilisha nambari kama ifuatavyo:

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

Onyo N8

V1048 [CWE-1164] Tofauti ya 'ColumnHeaderPressedCurrentState' ilipewa thamani sawa. libopenrct2ui CustomListView.cpp 510

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

Kanuni hiyo inaonekana ya ajabu sana. Inaonekana kwangu kuwa kulikuwa na typo katika hali hiyo au wakati wa kugawa tena kutofautisha ColumnHeaderPressedCurrentState maadili uongo.

Pato

Kama tunavyoona, kuunganisha kichanganuzi tuli cha PVS-Studio kwenye mradi wako wa TeamCity ni rahisi sana. Ili kufanya hivyo, inatosha kuandika faili moja ndogo ya usanidi. Kuangalia msimbo itawawezesha kutambua matatizo mara baada ya kusanyiko, ambayo itasaidia kuondokana nao wakati utata na gharama ya mabadiliko bado ni ya chini.

PVS-Studio na Ushirikiano unaoendelea: TeamCity. Uchambuzi wa mradi wa Open RollerCoaster Tycoon 2
Ikiwa ungependa kushiriki makala hii na hadhira inayozungumza Kiingereza, tafadhali tumia kiungo cha kutafsiri: Vladislav Stolyarov. PVS-Studio na Ushirikiano unaoendelea: TeamCity. Uchambuzi wa mradi wa Open RollerCoaster Tycoon 2.

Chanzo: mapenzi.com

Kuongeza maoni