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-студи — C, C++, C# болон Java кодын статик анализатор нь янз бүрийн төрлийн алдааг олж засварлах ажлыг хөнгөвчлөх зориулалттай. Уг анализаторыг Windows, Linux болон macOS дээр ашиглах боломжтой. Энэ нийтлэлд бид зөвхөн анализаторыг төдийгүй түүний түгээлтийн зарим хэрэгслийг идэвхтэй ашиглах болно.

CLMMonitor — хөрвүүлэгчийн ажиллагааг хянадаг хяналтын сервер юм. Энэ нь таны төслийг барьж эхлэхээс өмнө шууд ажиллах ёстой. Ажиглах горимд сервер бүх дэмжигдсэн хөрвүүлэгчийн ажиллагааг таслан зогсооно. Энэ хэрэгслийг зөвхөн 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 төслийн дүн шинжилгээ
Энд бид сонгоно:

  • Гүйлтийн төрөл -> Командын мөр
  • Ажиллуулах -> Тусгай скрипт

Төслийн эмхэтгэлийн явцад бид дүн шинжилгээ хийх тул угсрах, дүн шинжилгээ хийх нь нэг алхам байх ёстой тул талбарыг бөглөнө үү Захиалгат скрипт:

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

Анализатор санах ойг динамикаар хуваарилсны дараа алдаа гарсныг анзаарав Объект үүсгэх, үл хамаарах зүйл тохиолдоход санах ой арилдаггүй бөгөөд санах ойн алдагдал үүсдэг.

Анхааруулга N2

V501 '|'-ийн зүүн ба баруун талд '(1ULL << WIDX_MONTH_BOX)' ижил дэд илэрхийллүүд байна. оператор. 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),
  ....
};

Статик анализатороос өөр цөөхөн хүн энэ анхааралтай байдлын шалгалтыг давж чадна. Энэ хуулж буулгах жишээ нь яг энэ шалтгааны улмаас тохиромжтой.

Анхааруулга 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)
  {
    ....
  }
  ....
}

Илүү дэлгэрэнгүй харцгаая. Илэрхийлэл дүрсний чиглэл/8 бол худал болно зургийн чиглэл -7-оос 7-н хооронд байна. Хоёрдугаар хэсэг: (imageDirection / 8) != 3 шалгалтууд зургийн чиглэл хязгаараас гадуур байхын тулд: -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;
      ....
  }
  ....
}

Энэ кодын фрагментийг задлах замаар олж авсан байх магадлалтай. Дараа нь үлдээсэн сэтгэгдлээс харахад ажиллахгүй кодын нэг хэсгийг хассан. Гэсэн хэдий ч хэд хэдэн хагалгаа үлдээд байна курсорын дугаар, энэ нь бас нэг их утгагүй юм.

Анхааруулга 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 төслийн дүн шинжилгээ.

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх