PVS-Studio eta Etengabeko Integrazioa: TeamCity. Open RollerCoaster Tycoon 2 proiektuaren analisia

PVS-Studio eta Etengabeko Integrazioa: TeamCity. Open RollerCoaster Tycoon 2 proiektuaren analisia
PVS-Studio analizatzailea erabiltzeko egungo eszenatokietako bat CI sistemekin integratzea da. Eta PVS-Studio proiektu baten analisia etengabeko integrazio-sistema ia edozeinetik komando gutxitan eraiki daitekeen arren, prozesu hau are erosoagoa egiten jarraitzen dugu. PVS-Studio-k orain analizatzaileen irteera TeamCity - TeamCity Inspections Mota formatu batean bihurtzeko laguntza du. Ea nola funtzionatzen duen.

Erabilitako softwareari buruzko informazioa

PVS-Studioa β€” C, C++, C# eta Java kodearen analizatzaile estatikoa, hainbat akats mota aurkitzeko eta zuzentzeko lana errazteko diseinatua. Analizatzailea Windows, Linux eta macOS-en erabil daiteke. Artikulu honetan aktiboki erabiliko dugu analizatzailea bera ez ezik, bere banaketaren erabilgarritasun batzuk ere.

CLMonitor β€” konpiladoreen abiarazteak kontrolatzen dituen monitorizazio zerbitzari bat da. Zure proiektua eraikitzen hasi aurretik berehala exekutatu behar da. Snooping moduan, zerbitzariak onartutako konpilatzaile guztien exekuzioak atzemango ditu. Aipatzekoa da erabilgarritasun hau C/C++ proiektuak aztertzeko soilik erabil daitekeela.

PlogConverter – Analizatzaileen txostenak formatu ezberdinetan bihurtzeko utilitatea.

Aztergai dugun proiektuari buruzko informazioa

Proba dezagun funtzionalitate hau adibide praktiko batean; azter dezagun OpenRCT2 proiektua.

OpenRCT2 - RollerCoaster Tycoon 2 (RCT2) jokoaren inplementazio irekia, funtzio berriekin zabalduz eta akatsak konponduz. Jolasak ibilaldiak, dendak eta instalazioak dituen jolas-parke bat eraikitzea eta mantentzea da. Jokalariak irabaziak lortzen eta parkearen ospe ona mantentzen saiatu behar du gonbidatuak pozik mantenduz. OpenRCT2-k eszenatokian eta sandboxean jolasteko aukera ematen du. Eszenatokiek jokalariak zeregin zehatz bat bete behar du denbora zehatz batean, eta Sandbox-ek, berriz, parke malguagoa eraikitzeko aukera ematen dio, inolako murrizketarik edo finantzaketarik gabe.

doikuntza

Denbora aurrezteko, ziurrenik instalazio-prozesua saltatuko dut eta TeamCity zerbitzaria ordenagailuan exekutatzen dudan momentutik hasiko naiz. Hona joan behar dugu: localhost:{instalazio prozesuan zehaztutako ataka} (nire kasuan, localhost:9090) eta baimen-datuak sartu. Sartu ondoren honako hauek hartuko gaituzte:

PVS-Studio eta Etengabeko Integrazioa: TeamCity. Open RollerCoaster Tycoon 2 proiektuaren analisia
Egin klik Sortu proiektua botoian. Ondoren, hautatu Eskuz eta bete eremuak.

PVS-Studio eta Etengabeko Integrazioa: TeamCity. Open RollerCoaster Tycoon 2 proiektuaren analisia
Botoia sakatu ondoren Sortu, ezarpenak dituen leiho batek agurtzen gaitu.

PVS-Studio eta Etengabeko Integrazioa: TeamCity. Open RollerCoaster Tycoon 2 proiektuaren analisia
Egin dezagun klik Sortu konfigurazio konfigurazioa.

PVS-Studio eta Etengabeko Integrazioa: TeamCity. Open RollerCoaster Tycoon 2 proiektuaren analisia
Bete eremuak eta egin klik Sortu. Leiho bat ikusten dugu bertsio-kontrol sistema bat hautatzeko eskatzen dizuna. Iturburuak lokalean kokatuta daudenez, egin klik Salto egin.

PVS-Studio eta Etengabeko Integrazioa: TeamCity. Open RollerCoaster Tycoon 2 proiektuaren analisia
Azkenik, proiektuaren ezarpenetara joango gara.

PVS-Studio eta Etengabeko Integrazioa: TeamCity. Open RollerCoaster Tycoon 2 proiektuaren analisia
Gehitu ditzagun muntaketa-urratsak, klik hau egiteko: Eraiki urratsak -> Gehitu eraikuntza urratsa.

PVS-Studio eta Etengabeko Integrazioa: TeamCity. Open RollerCoaster Tycoon 2 proiektuaren analisia
Hemen aukeratzen dugu:

  • Korrikalari mota -> Komando-lerroa
  • Exekutatu -> Script pertsonalizatua

Proiektuaren konpilazioan analisia egingo dugunez, muntaia eta analisia urrats bat izan beharko lukete, beraz, bete eremua Script pertsonalizatua:

PVS-Studio eta Etengabeko Integrazioa: TeamCity. Open RollerCoaster Tycoon 2 proiektuaren analisia
Aurrerago urrats indibidualak aztertuko ditugu. Garrantzitsua da analizatzailea kargatu, proiektua muntatu, aztertu, txostena atera eta formateatzea hamaika kode-lerro baino ez izatea.

Egin behar dugun azken gauza ingurune-aldagaiak ezartzea da, irakurgarritasuna hobetzeko modu batzuk azaldu ditut. Horretarako, aurrera goazen: Parametroak -> Gehitu parametro berria eta gehitu hiru aldagai:

PVS-Studio eta Etengabeko Integrazioa: TeamCity. Open RollerCoaster Tycoon 2 proiektuaren analisia
Egin behar duzun guztia botoia sakatzea da Korrika egin goiko eskuineko izkinan. Proiektua muntatzen eta aztertzen ari diren bitartean, gidoiaren berri emango dizuet.

Zuzenean gidoia

Lehenik eta behin, azken PVS-Studio banaketa deskargatu behar dugu. Horretarako Chocolatey pakete kudeatzailea erabiltzen dugu. Honi buruz gehiago jakin nahi duenarentzat, dago dagokion bat artikuluan:

choco install pvs-studio -y

Ondoren, abiarazi dezagun CLMonitor proiektuaren jarraipena egiteko erabilgarritasuna.

%CLmon% monitor –-attach

Ondoren, proiektua ingurune-aldagai gisa eraikiko dugu MSB eraiki behar dudan MSBuild bertsiorako bidea da

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

Sar ditzagun PVS-Studiorako saioa hasteko eta lizentzia-gakoa:

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

Eraikuntza amaitu ondoren, exekutatu CLMonitor berriro aurreprozesatutako fitxategiak eta analisi estatikoa sortzeko:

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

Ondoren, gure banaketako beste erabilgarritasun bat erabiliko dugu. PlogConverter-ek txosten bat formatu estandar batetik TeamCity-ren formatu espezifiko batera bihurtzen du. Horri esker, zuzenean ikusi ahal izango dugu eraikuntza-leihoan.

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

Azken urratsa formateatutako txostena bistaratzea da stdout, non TeamCity analizatzaileak jasoko du.

type "C:tempptest.plog_TeamCity.txt"

Gidoi-kode osoa:

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"

Bitartean, proiektuaren muntaia eta analisia arrakastaz burutu da, fitxara joan gaitezke Proiektuak eta ziurtatu.

PVS-Studio eta Etengabeko Integrazioa: TeamCity. Open RollerCoaster Tycoon 2 proiektuaren analisia
Orain klik egin dezagun Ikuskapenak Guztiraanalizatzailearen txostena ikustera joateko:

PVS-Studio eta Etengabeko Integrazioa: TeamCity. Open RollerCoaster Tycoon 2 proiektuaren analisia
Abisuak diagnostiko-arau-zenbakien arabera multzokatzen dira. Kodean zehar nabigatzeko, abisua duen lerro-zenbakian klik egin behar duzu. Goiko eskuineko izkinan dagoen galdera ikurrean klik eginez fitxa berri bat irekiko zaizu dokumentazioarekin. Kodean zehar nabiga dezakezu analizatzailearen abisua duen lerro-zenbakian klik eginez. Erabiltzean urruneko ordenagailu batetik nabigatzea posible da SourceTreeRoot markatzailea. Analizatzailearen funtzionamendu-modu honetan interesa duen edonork dagokion atala ezagutu dezake dokumentazioa.

Analizatzailearen emaitzak ikustea

Orain, eraikuntza inplementatu eta konfiguratzen amaitu dugula, ikus ditzagun ikusten ari garen proiektuan aurkitutako abisu interesgarri batzuei.

Abisua N1

V773 [CWE-401] Salbuespena 'emaitza' erakuslea askatu gabe bota zen. Memoria ihesa posible da. 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;
}

Analizatzaileak errore bat ikusi zuen memoria dinamikoki esleitu ondoren SortuObjektua, salbuespen bat gertatzen denean, memoria ez da garbitzen eta memoria ihesa gertatzen da.

Abisua N2

V501 '(1ULL << WIDX_MONTH_BOX)' azpi-esamolde berdinak daude '|'ren ezkerraldean eta eskuinean. operadorea. 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),
  ....
};

Analizatzaile estatiko bat ez den jende gutxik gainditu lezake arreta proba hau. Kopiatu-itsatsi adibide hau ona da, hain zuzen ere arrazoi horregatik.

Abisuak N3

V703 Bitxia da 'RCT12BannerElement' klase eratorriko 'bandera' eremuak 'RCT12TileElementBase' oinarrizko klaseko eremua gainidaztea. Kontrol-lerroak: RCT12.h:570, RCT12.h:259. libopenrct2 RCT12.h 570

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

Noski, oinarrizko klasean eta ondorengoan izen bereko aldagai bat erabiltzea ez da beti errore bat. Hala ere, oinordetza-teknologiak berak suposatzen du klase nagusiaren eremu guztiak haurraren klasean daudela. Oinordetzan izen bereko eremuak deklaratuz, nahasmena sortzen dugu.

Abisua N4

V793 Bitxia da 'imageDirection / 8' adierazpenaren emaitza baldintzaren zati bat izatea. Beharbada, adierazpen hau beste zerbaitekin alderatu beharko litzateke. libopenrct2 ObservationTower.cpp 38

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

Ikus dezagun hurbilagotik. Adierazpena irudiaren Zuzendaritza/8 faltsua izango da baldin irudiaren Zuzendaritza -7tik 7ra bitartekoa da. Bigarren zatia: (irudiaNorabidea / 8) != 3 txekeak irudiaren Zuzendaritza tartetik kanpo egoteagatik: -31tik -24ra eta 24tik 31ra, hurrenez hurren. Nahiko arraroa iruditzen zait modu honetan zenbakiak tarte jakin batean sartzen diren egiaztatzea eta, kode zati honetan akatsik ez badago ere, baldintza hauek berridaztea gomendatuko nuke esplizituago izateko. Horrek bizitza askoz erraztuko luke kode hau irakurri eta mantenduko luketen pertsonei.

Abisua N5

V587 Mota honetako esleipen-segida bitxi bat: A = B; B = A;. Egiaztatu lerroak: 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;
      ....
  }
  ....
}

Kode zati hau deskonpilazio bidez lortu zen ziurrenik. Ondoren, utzitako iruzkinaren arabera, funtzionatzen ez zuen kodearen zati bat kendu zen. Hala ere, oraindik pare bat operazio geratzen dira kurtsoreId, eta horrek ere ez dauka zentzu handirik.

Abisua N6

V1004 [CWE-476] 'Jokalari' erakuslea modu seguruan erabili zen nullptr-en aurka egiaztatu ondoren. Egiaztatu lerroak: 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);                    // <=
  }
  ....
}

Kode hau nahiko erraza da zuzentzen; hirugarren aldiz egiaztatu besterik ez duzu behar Jokalari Erakusle nulu bati edo gehitu baldintzazko adierazpenaren gorputzean. Bigarren aukera proposatuko nuke:

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

Abisua N7

V547 [CWE-570] 'izena == nullptr' adierazpena beti da faltsua. 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));
    ....
  }
  ....
}

Irakurtzen zaila den kode-lerro bat kolpe bakarrean ken dezakezu eta egiaztatzearekin arazoa konpondu dezakezu. nullptr. Kodea honela aldatzea proposatzen dut:

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

Abisua N8

V1048 [CWE-1164] 'ColumnHeaderPressedCurrentState' aldagaiari balio bera esleitu zaio. libopenrct2ui CustomListView.cpp 510

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

Kodeak nahiko arraroa dirudi. Iruditzen zait akats bat egon zela egoeran edo aldagaia berriro esleitzean ColumnHeaderPressedCurrentState esanahia false.

Irteera

Ikus dezakegunez, PVS-Studio analizatzaile estatikoa zure TeamCity proiektuan integratzea nahiko erraza da. Horretarako, nahikoa da konfigurazio fitxategi txiki bakarra idaztea. Kodea egiaztatzeak muntatu eta berehala arazoak identifikatu ahal izango dituzu, eta horrek ezabatzen lagunduko du aldaketen konplexutasuna eta kostua oraindik txikia denean.

PVS-Studio eta Etengabeko Integrazioa: TeamCity. Open RollerCoaster Tycoon 2 proiektuaren analisia
Artikulu hau ingelesez hitz egiten duen publiko batekin partekatu nahi baduzu, mesedez, erabili itzulpen esteka: Vladislav Stolyarov. PVS-Studio eta Etengabeko Integrazioa: TeamCity. Open RollerCoaster Tycoon 2 proiektuaren analisia.

Iturria: www.habr.com

Gehitu iruzkin berria