PVS-Studio жана үзгүлтүксүз интеграция: TeamCity. Open RollerCoaster Tycoon 2 долбоорунун анализи

PVS-Studio жана үзгүлтүксүз интеграция: TeamCity. Open RollerCoaster Tycoon 2 долбоорунун анализи
PVS-Studio анализаторун колдонуунун эң учурдагы сценарийлеринин бири анын CI системалары менен интеграциясы болуп саналат. PVS-Studio долбоорун талдоо дээрлик бардык үзгүлтүксүз интеграция тутумунан бир нече буйруктарга курулса да, биз бул процессти ого бетер ыңгайлуу кылууну улантабыз. PVS-Studio азыр анализатордун чыгышын TeamCity - TeamCity Inspections Type форматына айландырууну колдойт. Келгиле, анын кантип иштээрин карап көрөлү.

Колдонулган программалык камсыздоо жөнүндө маалымат

PVS-Studio — C, C++, C# жана Java коддорунун статикалык анализатору, каталардын ар кандай түрлөрүн табуу жана оңдоо тапшырмасын жеңилдетүү үчүн иштелип чыккан. Анализаторду Windows, Linux жана macOS системаларында колдонсо болот. Бул макалада биз анализатордун өзүн гана эмес, аны жайылтуудан кээ бир утилиталарды да активдүү колдонобуз.

CLMonitor — компилятордун ишке киришин көзөмөлдөгөн мониторинг сервери. Долбооруңузду курууну баштоодон мурун аны дароо иштетүү керек. Көзөмөл режиминде сервер бардык колдоого алынган компиляторлордун иштөөсүн токтотот. Белгилей кетсек, бул утилитаны C/C++ долбоорлорун талдоо үчүн гана колдонсо болот.

PlogConverter – анализаторлордун отчетторун ар кандай форматтарга айландыруу үчүн программа.

изилденип жаткан долбоор жөнүндө маалымат

Келгиле, бул функцияны практикалык мисалда сынап көрөлү - OpenRCT2 долбоорун талдап көрөлү.

OpenRCT2 - RollerCoaster Tycoon 2 (RCT2) оюнунун ачык ишке ашырылышы, аны жаңы функциялар менен кеңейтүү жана мүчүлүштүктөрдү оңдоо. Оюн ойноо аттракциондор, дүкөндөр жана объектилерди камтыган оюн-зоок паркын курууга жана тейлөөгө айланат. Оюнчу конокторду бактылуу кылып, киреше табууга жана парктын жакшы репутациясын сактоого аракет кылышы керек. OpenRCT2 сценарийде да, кум чөйрөдө да ойноого мүмкүндүк берет. Сценарийлер оюнчудан белгилүү бир тапшырманы белгиленген убакыттын ичинде аткарууну талап кылат, ал эми Sandbox оюнчуга эч кандай чектөөсүз же каржысыз ийкемдүү парк курууга мүмкүндүк берет.

тууралоо

Убакытты үнөмдөө үчүн, балким, орнотуу процессин өткөрүп жиберип, компьютеримде TeamCity сервери иштеп баштагандан баштап баштайм. Бизге барышыбыз керек: localhost:{орнотуу процессинде көрсөтүлгөн порт} (менин учурда, localhost:9090) жана авторизация дайындарын киргизишибиз керек. Киргенден кийин бизди тосуп алат:

PVS-Studio жана үзгүлтүксүз интеграция: TeamCity. Open RollerCoaster Tycoon 2 долбоорунун анализи
Долбоор түзүү баскычын чыкылдатыңыз. Андан кийин, Кол менен тандап, талааларды толтуруңуз.

PVS-Studio жана үзгүлтүксүз интеграция: TeamCity. Open RollerCoaster Tycoon 2 долбоорунун анализи
кнопкасын баскандан кийин түзүү, бизди орнотуулары бар терезе тосуп алат.

PVS-Studio жана үзгүлтүксүз интеграция: TeamCity. Open RollerCoaster Tycoon 2 долбоорунун анализи
келгиле Куруу конфигурациясын түзүү.

PVS-Studio жана үзгүлтүксүз интеграция: TeamCity. Open RollerCoaster Tycoon 2 долбоорунун анализи
Талааларды толтуруңуз жана басыңыз түзүү. Биз версияны башкаруу тутумун тандоону суранган терезени көрөбүз. Булактар ​​мурунтан эле жергиликтүү жайгашкандыктан, чыкылдатыңыз секирүү.

PVS-Studio жана үзгүлтүксүз интеграция: TeamCity. Open RollerCoaster Tycoon 2 долбоорунун анализи
Акыр-аягы, биз долбоордун жөндөөлөрүнө өтүү.

PVS-Studio жана үзгүлтүксүз интеграция: TeamCity. Open RollerCoaster Tycoon 2 долбоорунун анализи
Бул чыкылдатуу үчүн, монтаждоо кадамдарын кошолу: Куруу кадамдары -> Куруу кадамын кошуу.

PVS-Studio жана үзгүлтүксүз интеграция: TeamCity. Open RollerCoaster Tycoon 2 долбоорунун анализи
Бул жерде биз тандайбыз:

  • Runner түрү -> Command Line
  • Run -> Ыңгайлаштырылган скрипт

Биз долбоорду түзүү учурунда талдоо жүргүзө тургандыктан, чогултуу жана талдоо бир кадам болушу керек, андыктан талааны толтуруңуз Көнүмүш Script:

PVS-Studio жана үзгүлтүксүз интеграция: TeamCity. Open RollerCoaster Tycoon 2 долбоорунун анализи
Биз кийинчерээк жеке кадамдарды карап чыгабыз. Анализаторду жүктөө, долбоорду чогултуу, аны талдоо, отчетту чыгаруу жана аны форматтоо үчүн он бир гана сап код талап кылынышы маанилүү.

Биз кылышыбыз керек болгон акыркы нерсе - бул чөйрө өзгөрмөлөрүн коюу, мен алардын окулушун жакшыртуунун бир нече жолдорун белгиледим. Бул үчүн, келгиле, уланталы: Параметрлер -> Жаңы параметр кошуу жана үч өзгөрмө кошуу:

PVS-Studio жана үзгүлтүксүз интеграция: TeamCity. Open RollerCoaster Tycoon 2 долбоорунун анализи
Болгону баскычты бассаңыз болот Run жогорку оң бурчунда. Долбоор чогултулуп, талданып жатканда, мен сценарий тууралуу айтып берем.

Түздөн-түз скрипт

Биринчиден, биз акыркы PVS-Studio бөлүштүрүүнү жүктөп алышыбыз керек. Бул үчүн биз Chocolatey пакет менеджерин колдонобуз. Бул тууралуу көбүрөөк билгиси келгендер үчүн тиешелүү макала:

choco install pvs-studio -y

Андан кийин, CLMonitor долбоорунун курулушуна көз салуу программасын ишке киргизели.

%CLmon% monitor –-attach

Андан кийин биз долбоорду айлана-чөйрө өзгөрмө катары курабыз MSB Мен курушум керек MSBuild версиясына жол

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

PVS-Studio үчүн логин жана лицензия ачкычын киргизели:

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

Куруу аяктагандан кийин, алдын ала иштетилген файлдарды жана статикалык анализди түзүү үчүн CLMonitorду кайра иштетиңиз:

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

Андан кийин биз бөлүштүрүүдөн башка утилитаны колдонобуз. PlogConverter отчетту стандарттуу форматтан TeamCity үчүн атайын форматка которот. Мунун аркасында биз аны түз эле куруу терезесинде көрө алабыз.

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

Акыркы кадам форматталган отчетту көрсөтүү болуп саналат stdout, ал жерден TeamCity талдоочу тарабынан тандалат.

type "C:tempptest.plog_TeamCity.txt"

Толук скрипт коду:

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"

Ошол эле учурда, долбоордун монтаждоо жана талдоо ийгиликтүү аяктады, биз кошумча барагына өтүүгө болот долбоорлор жана ага ынаныңыз.

PVS-Studio жана үзгүлтүксүз интеграция: TeamCity. Open RollerCoaster Tycoon 2 долбоорунун анализи
Эми басыңыз Текшерүүлөрдүн бардыгыанализатордун отчетун көрүү үчүн:

PVS-Studio жана үзгүлтүксүз интеграция: TeamCity. Open RollerCoaster Tycoon 2 долбоорунун анализи
Эскертүүлөр диагностикалык эреженин номерлери боюнча топтоштурулган. Код аркылуу өтүү үчүн эскертүүсү бар саптын номерин басышыңыз керек. Жогорку оң бурчтагы суроо белгисин чыкылдатуу сизге документтер менен жаңы өтмөктү ачат. Ошондой эле анализатордун эскертүүсү бар саптын номерин чыкылдатуу менен код менен чабыттасаңыз болот. Колдонуу учурунда алыскы компьютерден навигация мүмкүн SourceTreeRoot маркер. Анализатордун иштөө режимине кызыккан ар бир адам тиешелүү бөлүм менен тааныша алат документтер.

Анализатордун натыйжаларын көрүү

Эми биз курууну жайгаштырууну жана конфигурациялоону бүтүргөндөн кийин, биз карап жаткан долбоордо табылган кээ бир кызыктуу эскертүүлөрдү карап көрөлү.

Эскертүү N1

V773 [CWE-401] Өзгөчө жагдай "натыйжа" көрсөткүчүн чыгарбастан ташталды. Эс тутумдун агып кетиши мүмкүн. 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;
}

Анализатор эстутумду динамикалык бөлүштүргөндөн кийин катаны байкады CreateObject, өзгөчө кырдаал болгондо, эс тазаланбайт жана эс тутумдун агып кетиши пайда болот.

Эскертүү N2

V501 "|' оператор. libopenrct1ui Cheats.cpp 2

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

Статикалык анализатордон башка бир нече адам бул кунт коюп сыноодон өтө алган. Бул көчүрүп чаптоо мисалы дал ушул себептен жакшы.

Эскертүү N3

V703 "RCT12BannerElement" туунду классындагы "желек" талаасы "RCT12TileElementBase" базалык классындагы талаанын үстүнөн жазышы таң калыштуу. Текшерүү саптары: RCT12.h:570, RCT12.h:259. libopenrct2 RCT12.h 570

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

Албетте, негизги класста жана тукумда бирдей аталыштагы өзгөрмө колдонуу дайыма эле ката эмес. Бирок, тукум куучулук технологиясы өзү ата-энелер классынын бардык талаалары бала класста бар деп болжолдойт. Бир эле аталыштагы талааларды мураскордо жарыялоо менен биз башаламандыкка жол ачабыз.

Эскертүү N4

V793 'imageDirection / 8' операторунун натыйжасы шарттын бир бөлүгү экендиги таң калыштуу. Балким, бул сөздү башка нерсе менен салыштыруу керек болчу. libopenrct2 ObservationTower.cpp 38

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

Келгиле, кененирээк карап көрөлү. Экспресс imageDirection/8 болсо жалган болот imageDirection -7ден 7ге чейинки диапазондо. Экинчи бөлүк: (imageDirection / 8) != 3 чектер imageDirection диапазондон тышкары болгондугу үчүн: тиешелүүлүгүнө жараша -31ден -24кө чейин жана 24төн 31ге чейин. Мага ушундай жол менен сандарды белгилүү бир диапазонго киргизүү абдан кызыктай сезилет жана коддун бул бөлүгүндө эч кандай ката жок болсо дагы, мен бул шарттарды ачык-айкын болушу үчүн кайра жазууну сунуштайм. Бул кодду окуп, сактаган адамдардын жашоосун бир топ жеңилдетет.

Эскертүү N5

V587 Бул түрдөгү тапшырмалардын так ырааттуулугу: A = B; B = A;. Текшерүү саптары: 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;
      ....
  }
  ....
}

Бул код фрагменти, кыязы, декомпиляция жолу менен алынган. Андан кийин, калтырылган комментарийге караганда, иштебеген коддун бир бөлүгү алынып салынды. Бирок дагы бир нече операция калды cursorId, бул да көп мааниге ээ эмес.

Эскертүү N6

V1004 [CWE-476] "Оюнчу" көрсөткүчү nullptr менен текшерилгенден кийин кооптуу колдонулган. Текшерүү саптары: 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);                    // <=
  }
  ....
}

Бул кодду оңдоо оңой, сиз аны үчүнчү жолу текшеришиңиз керек оюнчу нөл көрсөткүчкө же аны шарттуу билдирүүнүн негизги бөлүгүнө кошуңуз. Мен экинчи вариантты сунуштайм:

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

Эскертүү N7

V547 [CWE-570] 'name == nullptr' туюнтмасы дайыма жалган. 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));
    ....
  }
  ....
}

Сиз окууга кыйын болгон код саптарынан бир заматта кутулсаңыз жана маселени текшерүү менен чече аласыз nullptr. Мен кодду төмөнкүдөй өзгөртүүнү сунуштайм:

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

Эскертүү N8

V1048 [CWE-1164] 'ColumnHeaderPressedCurrentState' өзгөрмөсүнө бирдей маани ыйгарылган. libopenrct2ui CustomListView.cpp 510

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

Код абдан кызыктай көрүнөт. Мага шартта же өзгөрмөнү кайра дайындоодо ката бар окшойт ColumnHeaderPressedCurrentState маани жалган.

жыйынтыктоо

Көрүнүп тургандай, PVS-Studio статикалык анализаторун сиздин TeamCity долбооруна интеграциялоо абдан жөнөкөй. Бул үчүн, бир эле кичинекей конфигурация файлын жазуу жетиштүү. Кодду текшерүү көйгөйлөрдү чогулткандан кийин дароо аныктоого мүмкүндүк берет, бул өзгөртүүлөрдүн татаалдыгы жана баасы дагы эле төмөн болгон учурда аларды жоюуга жардам берет.

PVS-Studio жана үзгүлтүксүз интеграция: TeamCity. Open RollerCoaster Tycoon 2 долбоорунун анализи
Бул макаланы англис тилдүү аудитория менен бөлүшкүңүз келсе, котормо шилтемесин колдонуңуз: Владислав Столяров. PVS-Studio жана үзгүлтүксүз интеграция: TeamCity. Open RollerCoaster Tycoon 2 долбоорунун анализи.

Source: www.habr.com

Комментарий кошуу