PVS-Stiwdio ac Integreiddio Parhaus: TeamCity. Dadansoddiad o brosiect Open RollerCoaster Tycoon 2

PVS-Stiwdio ac Integreiddio Parhaus: TeamCity. Dadansoddiad o brosiect Open RollerCoaster Tycoon 2
Un o'r senarios mwyaf cyfredol ar gyfer defnyddio'r dadansoddwr PVS-Studio yw ei integreiddio Γ’ systemau CI. Ac er y gellir ymgorffori dadansoddiad o brosiect PVS-Studio o bron unrhyw system integreiddio barhaus i ychydig o orchmynion, rydym yn parhau i wneud y broses hon hyd yn oed yn fwy cyfleus. Bellach mae gan PVS-Studio gefnogaeth ar gyfer trosi allbwn dadansoddwr yn fformat ar gyfer TeamCity - Math o Arolygiadau TeamCity. Gawn ni weld sut mae'n gweithio.

Gwybodaeth am y meddalwedd a ddefnyddir

PVS-Stiwdio β€” dadansoddwr statig o god C, C++, C# a Java, wedi'i gynllunio i hwyluso'r dasg o ddod o hyd i wahanol fathau o wallau a'u cywiro. Gellir defnyddio'r dadansoddwr ar Windows, Linux a macOS. Yn yr erthygl hon byddwn yn mynd ati i ddefnyddio nid yn unig y dadansoddwr ei hun, ond hefyd rhai cyfleustodau o'i ddosbarthiad.

CLMonitor - yn weinydd monitro sy'n monitro lansiadau casglwr. Rhaid ei redeg yn syth cyn dechrau adeiladu eich prosiect. Yn y modd snooping, bydd y gweinydd yn rhyng-gipio rhediadau o'r holl gasglwyr a gefnogir. Mae'n werth nodi mai dim ond i ddadansoddi prosiectau C/C++ y gellir defnyddio'r cyfleustodau hwn.

PlogConverter – cyfleustodau ar gyfer trosi adroddiadau dadansoddwr i fformatau gwahanol.

Gwybodaeth am y prosiect sy'n cael ei astudio

Gadewch i ni roi cynnig ar y swyddogaeth hon gydag enghraifft ymarferol - gadewch i ni ddadansoddi'r prosiect OpenRCT2.

AgoredRCT2 - gweithrediad agored o'r gΓͺm RollerCoaster Tycoon 2 (RCT2), gan ei ehangu gyda swyddogaethau newydd a thrwsio chwilod. Mae chwarae gΓͺm yn ymwneud ag adeiladu a chynnal parc difyrion sy'n cynnwys reidiau, siopau a chyfleusterau. Rhaid i'r chwaraewr geisio gwneud elw a chynnal enw da'r parc tra'n cadw gwesteion yn hapus. Mae OpenRCT2 yn caniatΓ‘u ichi chwarae mewn senario a blwch tywod. Mae senarios yn ei gwneud yn ofynnol i'r chwaraewr gwblhau tasg benodol o fewn amser penodol, tra bod Sandbox yn caniatΓ‘u i'r chwaraewr adeiladu parc mwy hyblyg heb unrhyw gyfyngiadau na chyllid.

addasiad

Er mwyn arbed amser, mae'n debyg y byddaf yn hepgor y broses osod ac yn cychwyn o'r eiliad pan fydd gweinydd TeamCity yn rhedeg ar fy nghyfrifiadur. Mae angen i ni fynd i: localhost: {porth a nodir yn ystod y broses osod} (yn fy achos i, localhost: 9090) a mewnbynnu data awdurdodi. Ar Γ΄l dod i mewn byddwn yn cael ein cyfarch gan:

PVS-Stiwdio ac Integreiddio Parhaus: TeamCity. Dadansoddiad o brosiect Open RollerCoaster Tycoon 2
Cliciwch ar y botwm Creu Prosiect. Nesaf, dewiswch Γ’ llaw a llenwch y meysydd.

PVS-Stiwdio ac Integreiddio Parhaus: TeamCity. Dadansoddiad o brosiect Open RollerCoaster Tycoon 2
Ar Γ΄l pwyso'r botwm Creu, cawn ein cyfarch gan ffenestr gyda gosodiadau.

PVS-Stiwdio ac Integreiddio Parhaus: TeamCity. Dadansoddiad o brosiect Open RollerCoaster Tycoon 2
Gadewch i ni glicio Creu cyfluniad adeiladu.

PVS-Stiwdio ac Integreiddio Parhaus: TeamCity. Dadansoddiad o brosiect Open RollerCoaster Tycoon 2
Llenwch y meysydd a chliciwch Creu. Rydym yn gweld ffenestr yn gofyn i chi ddewis system rheoli fersiwn. Gan fod y ffynonellau eisoes wedi'u lleoli'n lleol, cliciwch Skip.

PVS-Stiwdio ac Integreiddio Parhaus: TeamCity. Dadansoddiad o brosiect Open RollerCoaster Tycoon 2
Yn olaf, symudwn ymlaen i osodiadau'r prosiect.

PVS-Stiwdio ac Integreiddio Parhaus: TeamCity. Dadansoddiad o brosiect Open RollerCoaster Tycoon 2
Gadewch i ni ychwanegu camau cynulliad, i wneud hyn cliciwch: Adeiladu camau -> Ychwanegu cam adeiladu.

PVS-Stiwdio ac Integreiddio Parhaus: TeamCity. Dadansoddiad o brosiect Open RollerCoaster Tycoon 2
Yma rydym yn dewis:

  • Math rhedwr -> Llinell Reoli
  • Rhedeg -> Sgript Custom

Gan y byddwn yn perfformio dadansoddiad yn ystod llunio prosiect, dylai cydosod a dadansoddi fod yn un cam, felly llenwch y maes Sgript Custom:

PVS-Stiwdio ac Integreiddio Parhaus: TeamCity. Dadansoddiad o brosiect Open RollerCoaster Tycoon 2
Byddwn yn edrych ar gamau unigol yn ddiweddarach. Mae'n bwysig bod llwytho'r dadansoddwr, cydosod y prosiect, ei ddadansoddi, allbynnu'r adroddiad a'i fformatio yn cymryd dim ond un ar ddeg llinell o god.

Y peth olaf y mae angen inni ei wneud yw gosod y newidynnau amgylchedd, yr wyf wedi amlinellu rhai ffyrdd o wella eu darllenadwyedd. I wneud hyn, gadewch i ni symud ymlaen: Paramedrau -> Ychwanegu paramedr newydd ac ychwanegu tri newidyn:

PVS-Stiwdio ac Integreiddio Parhaus: TeamCity. Dadansoddiad o brosiect Open RollerCoaster Tycoon 2
Y cyfan sy'n rhaid i chi ei wneud yw pwyso'r botwm Run yn y gornel dde uchaf. Tra bod y prosiect yn cael ei gydosod a'i ddadansoddi, byddaf yn dweud wrthych am y sgript.

Sgript yn uniongyrchol

Yn gyntaf, mae angen inni lawrlwytho'r dosbarthiad PVS-Studio diweddaraf. Ar gyfer hyn rydym yn defnyddio'r rheolwr pecyn Chocolatey. I'r rhai sydd am wybod mwy am hyn, mae cyfatebol erthygl:

choco install pvs-studio -y

Nesaf, gadewch i ni lansio cyfleustodau olrhain adeiladu prosiect CLMonitor.

%CLmon% monitor –-attach

Yna byddwn yn adeiladu'r prosiect fel newidyn amgylcheddol MSB yw'r llwybr i'r fersiwn o MBuild y mae angen i mi ei adeiladu

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

Gadewch i ni nodi'r allwedd mewngofnodi a thrwydded ar gyfer PVS-Studio:

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

Ar Γ΄l i'r gwaith adeiladu gael ei gwblhau, rhedwch CLMonitor eto i gynhyrchu ffeiliau wedi'u prosesu ymlaen llaw a dadansoddiad statig:

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

Yna byddwn yn defnyddio cyfleustodau arall o'n dosbarthiad. Mae PlogConverter yn trosi adroddiad o fformat safonol i fformat sy'n benodol i TeamCity. Diolch i hyn, byddwn yn gallu ei weld yn uniongyrchol yn y ffenestr adeiladu.

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

Y cam olaf yw dangos yr adroddiad wedi'i fformatio i mewn stdout, lle bydd y parser TeamCity yn ei godi.

type "C:tempptest.plog_TeamCity.txt"

Cod sgript llawn:

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"

Yn y cyfamser, mae cynulliad a dadansoddiad y prosiect wedi'i gwblhau'n llwyddiannus, gallwn fynd i'r tab prosiectau a gwnewch yn siwr ohono.

PVS-Stiwdio ac Integreiddio Parhaus: TeamCity. Dadansoddiad o brosiect Open RollerCoaster Tycoon 2
Nawr gadewch i ni glicio ar Cyfanswm yr Arolygiadaui fynd i weld adroddiad y dadansoddwr:

PVS-Stiwdio ac Integreiddio Parhaus: TeamCity. Dadansoddiad o brosiect Open RollerCoaster Tycoon 2
Mae rhybuddion yn cael eu grwpio yn Γ΄l rhifau rheolau diagnostig. I lywio drwy'r cod, mae angen i chi glicio ar y rhif llinell gyda'r rhybudd. Bydd clicio ar y marc cwestiwn yn y gornel dde uchaf yn agor tab newydd i chi gyda dogfennaeth. Gallwch hefyd lywio trwy'r cod trwy glicio ar y rhif llinell gyda rhybudd y dadansoddwr. Mae llywio o gyfrifiadur o bell yn bosibl wrth ddefnyddio FfynhonnellTreeRoot marciwr. Gall unrhyw un sydd Γ’ diddordeb yn y dull hwn o weithredu'r dadansoddwr ymgyfarwyddo Γ’'r adran gyfatebol dogfennaeth.

Gweld canlyniadau'r dadansoddwr

Nawr ein bod ni wedi gorffen lleoli a ffurfweddu'r adeilad, gadewch i ni edrych ar rai rhybuddion diddorol a ddarganfuwyd yn y prosiect rydyn ni'n edrych arno.

Rhybudd N1

V773 [CWE-401] Taflwyd yr eithriad heb ryddhau'r pwyntydd 'canlyniad'. Mae gollyngiad cof yn bosibl. 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;
}

Sylwodd y dadansoddwr wall ar Γ΄l dyrannu cof yn ddeinamig i mewn Creu Gwrthrych, pan fydd eithriad yn digwydd, nid yw'r cof yn cael ei glirio, ac mae gollyngiad cof yn digwydd.

Rhybudd N2

V501 Mae is-fynegiadau union yr un fath '(1ULL << WIDX_MONTH_BOX)' i'r chwith ac i'r dde o'r '|' gweithredydd. 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),
  ....
};

Ychydig iawn o bobl heblaw dadansoddwr statig a allai basio'r prawf sylw hwn. Mae'r enghraifft copi-gludo hon yn dda am yr union reswm hwn.

Rhybuddion N3

V703 Mae'n rhyfedd bod y maes 'baneri' yn y dosbarth deilliedig 'RCT12BannerElement' yn trosysgrifo maes yn y dosbarth sylfaen 'RCT12TileElementBase'. Llinellau gwirio: RCT12.h:570, RCT12.h:259. libopenrct2 RCT12.h 570

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

Wrth gwrs, nid yw defnyddio newidyn gyda'r un enw yn y dosbarth sylfaenol ac yn y disgynnydd bob amser yn gamgymeriad. Fodd bynnag, mae technoleg etifeddiaeth ei hun yn rhagdybio bod holl feysydd y dosbarth rhiant yn bresennol yn y dosbarth plentyn. Trwy ddatgan caeau gyda'r un enw yn yr etifedd, rydym yn creu dryswch.

Rhybudd N4

V793 Mae'n rhyfedd fod canlyniad y gosodiad 'imageDirection / 8' yn rhan o'r cyflwr. Efallai y dylai’r datganiad hwn fod wedi’i gymharu Γ’ rhywbeth arall. libopenrct2 ObservationTower.cpp 38

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

Gadewch i ni edrych yn agosach. Mynegiant delweddCyfarwyddyd/8 bydd yn anwir os delweddCyfeiriad yn yr ystod o -7 i 7. Ail ran: (imageDirection/8) !=3 gwiriadau delweddCyfeiriad am fod y tu allan i'r ystod: o -31 i -24 ac o 24 i 31, yn y drefn honno. Mae'n ymddangos yn eithaf rhyfedd i mi wirio niferoedd i'w cynnwys mewn ystod benodol yn y modd hwn a, hyd yn oed os nad oes gwall yn y darn hwn o god, byddwn yn argymell ailysgrifennu'r amodau hyn i fod yn fwy eglur. Byddai hyn yn gwneud bywyd yn llawer haws i'r bobl a fyddai'n darllen ac yn cynnal y cod hwn.

Rhybudd N5

V587 Dilyniant od o aseiniadau o'r math hwn: A = B; B = A;. Llinellau gwirio: 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;
      ....
  }
  ....
}

Mae'n debyg mai trwy ddadgrynhoi y cafwyd y darn cod hwn. Yna, a barnu yn Γ΄l y sylw a adawyd, tynnwyd rhan o'r cod nad oedd yn gweithio. Fodd bynnag, mae cwpl o lawdriniaethau ar Γ΄l o hyd cyrsorId, sydd hefyd ddim yn gwneud llawer o synnwyr.

Rhybudd N6

V1004 [CWE-476] Defnyddiwyd y pwyntydd 'chwaraewr' yn anniogel ar Γ΄l iddo gael ei ddilysu yn erbyn nullptr. Llinellau gwirio: 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);                    // <=
  }
  ....
}

Mae'r cod hwn yn eithaf hawdd i'w gywiro; does ond angen i chi ei wirio am y trydydd tro chwaraewr i bwyntydd null, neu ei ychwanegu at gorff y datganiad amodol. Byddwn yn awgrymu'r ail opsiwn:

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

Rhybudd N7

V547 [CWE-570] Mae'r ymadrodd 'enw == nullptr' bob amser yn ffug. 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));
    ....
  }
  ....
}

Gallwch gael gwared ar linell o god anodd ei darllen mewn un swoop syrthio a datrys y broblem gyda gwirio am nullptr. Awgrymaf newid y cod fel a ganlyn:

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

Rhybudd N8

V1048 [CWE-1164] Rhoddwyd yr un gwerth i'r newidyn 'ColumnHeaderPressedCurrentState'. libopenrct2ui CustomListView.cpp 510

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

Mae'r cod yn edrych yn eithaf rhyfedd. Mae'n ymddangos i mi fod yna deip naill ai yn y cyflwr neu wrth ail-neilltuo'r newidyn ColumnHeaderPressedCurrentState ystyron ffug.

Allbwn

Fel y gallwn weld, mae integreiddio'r dadansoddwr statig PVS-Studio i'ch prosiect TeamCity yn eithaf syml. I wneud hyn, mae'n ddigon ysgrifennu un ffeil ffurfweddu fach yn unig. Bydd gwirio'r cod yn caniatΓ‘u ichi nodi problemau yn syth ar Γ΄l y cynulliad, a fydd yn helpu i gael gwared arnynt pan fydd cymhlethdod a chost newidiadau yn dal yn isel.

PVS-Stiwdio ac Integreiddio Parhaus: TeamCity. Dadansoddiad o brosiect Open RollerCoaster Tycoon 2
Os ydych chi am rannu'r erthygl hon Γ’ chynulleidfa Saesneg ei hiaith, defnyddiwch y ddolen gyfieithu: Vladislav Stolyarov. PVS-Stiwdio ac Integreiddio Parhaus: TeamCity. Dadansoddiad o brosiect Open RollerCoaster Tycoon 2.

Ffynhonnell: hab.com

Ychwanegu sylw