PVS-Studio analizatoridan foydalanishning eng dolzarb stsenariylaridan biri uning CI tizimlari bilan integratsiyalashuvidir. Va deyarli har qanday uzluksiz integratsiya tizimidan PVS-Studio loyihasini tahlil qilish faqat bir nechta buyruqlarga o'rnatilishi mumkin bo'lsa-da, biz bu jarayonni yanada qulayroq qilishda davom etamiz. PVS-Studio endi analizator chiqishini TeamCity - TeamCity Inspections Type formatiga aylantirishni qo'llab-quvvatlaydi. Keling, bu qanday ishlashini ko'rib chiqaylik.
Amaldagi dasturiy ta'minot haqida ma'lumot
O'rganilayotgan loyiha haqida ma'lumot
Keling, ushbu funksiyani amaliy misolda sinab ko'raylik - OpenRCT2 loyihasini tahlil qilaylik.
moslashish
Vaqtni tejash uchun men o'rnatish jarayonini o'tkazib yuboraman va kompyuterimda TeamCity serveri ishlayotgan paytdan boshlayman. Bizga o'tishimiz kerak: localhost:{o'rnatish jarayonida ko'rsatilgan port} (mening holimda, localhost:9090) va avtorizatsiya ma'lumotlarini kiriting. Kirishdan so'ng bizni kutib oladi:
Loyiha yaratish tugmasini bosing. Keyin qo'lda-ni tanlang va maydonlarni to'ldiring.
Tugmani bosgandan so'ng yaratish, bizni sozlamalar bilan oyna kutib oladi.
Keling, bosing Qurilish konfiguratsiyasini yarating.
Maydonlarni to'ldiring va ustiga bosing yaratish. Biz versiyani boshqarish tizimini tanlashni so'ragan oynani ko'ramiz. Manbalar allaqachon mahalliy sifatida joylashganligi sababli, bosing Siz identifikatsiyadan o'tmadingiz.
Nihoyat, biz loyiha sozlamalariga o'tamiz.
Keling, yig'ish bosqichlarini qo'shamiz, buni amalga oshirish uchun bosing: Qurilish bosqichlari -> Qurilish bosqichini qo'shish.
Bu erda biz tanlaymiz:
- Yuguruvchi turi -> Buyruqlar qatori
- Ishga tushirish -> Maxsus skript
Loyihani tuzishda biz tahlilni amalga oshirganimiz sababli, yig'ish va tahlil qilish bir qadam bo'lishi kerak, shuning uchun maydonni to'ldiring Maxsus skript:
Keyinchalik individual qadamlarni ko'rib chiqamiz. Analizatorni yuklash, loyihani yig'ish, uni tahlil qilish, hisobotni chiqarish va uni formatlash uchun faqat o'n bir qator kod kerak bo'lishi muhimdir.
Biz qilishimiz kerak bo'lgan oxirgi narsa - atrof-muhit o'zgaruvchilarini o'rnatish, men ularni o'qishni yaxshilashning ba'zi usullarini aytib berdim. Buning uchun keling, davom etaylik: Parametrlar -> Yangi parametr qo'shish va uchta o'zgaruvchini qo'shing:
Buning uchun tugmani bosish kifoya yugurish yuqori o'ng burchakda. Loyiha yig'ilib, tahlil qilinayotganda, men sizga skript haqida gapirib beraman.
To'g'ridan-to'g'ri skript
Birinchidan, biz eng so'nggi PVS-Studio distributivini yuklab olishimiz kerak. Buning uchun biz Chocolatey paket menejeridan foydalanamiz. Bu haqda ko'proq bilmoqchi bo'lganlar uchun mos keladigan narsa mavjud
choco install pvs-studio -y
Keyinchalik, CLMonitor loyihasini kuzatish dasturini ishga tushiramiz.
%CLmon% monitor β-attach
Keyin biz loyihani muhit o'zgaruvchisi sifatida quramiz MSB men qurishim kerak bo'lgan MSBuild versiyasiga yo'l
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
PVS-Studio uchun login va litsenziya kalitini kiritamiz:
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
Qurilish tugagandan so'ng, qayta ishlangan fayllar va statik tahlillarni yaratish uchun CLMonitor-ni qayta ishga tushiring:
%CLmon% analyze -l "c:ptest.plog"
Keyin biz tarqatishimizdan boshqa yordamchi dasturdan foydalanamiz. PlogConverter hisobotni standart formatdan TeamCity-ga xos formatga o'zgartiradi. Buning yordamida biz uni to'g'ridan-to'g'ri qurilish oynasida ko'rishimiz mumkin bo'ladi.
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
Oxirgi qadam formatlangan hisobotni ko'rsatishdir stdout, u TeamCity tahlilchisi tomonidan olinadi.
type "C:tempptest.plog_TeamCity.txt"
To'liq skript kodi:
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"
Ayni paytda, loyihani yig'ish va tahlil qilish muvaffaqiyatli yakunlandi, biz tabga o'tishimiz mumkin loyihalar i ubeditsya v etom.
Endi bosing Tekshirishlar jamianalizator hisobotini ko'rish uchun:
Ogohlantirishlar diagnostika qoidalari raqamlari bo'yicha guruhlangan. Kod bo'ylab harakat qilish uchun siz ogohlantirish bilan chiziq raqamini bosishingiz kerak. Yuqori o'ng burchakdagi savol belgisini bosish sizga hujjatlar bilan yangi yorliqni ochadi. Shuningdek, analizator ogohlantirishi bilan chiziq raqamini bosish orqali kod bo'ylab harakat qilishingiz mumkin. Foydalanishda masofaviy kompyuterdan navigatsiya qilish mumkin SourceTreeRoot marker. Analizatorning ushbu ishlash rejimiga qiziqqan har bir kishi tegishli bo'lim bilan tanishishi mumkin
Analizator natijalarini ko'rish
Qurilishni joylashtirish va sozlashni tugatganimizdan so'ng, biz ko'rib chiqayotgan loyihada topilgan ba'zi qiziqarli ogohlantirishlarni ko'rib chiqaylik.
Ogohlantirish N1
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;
}
Analizator xotirani dinamik ravishda taqsimlagandan so'ng xatolikni payqadi Ob'ekt yaratish, istisno sodir bo'lganda, xotira o'chirilmaydi va xotira oqishi sodir bo'ladi.
Ogohlantirish N2
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),
....
};
Statik analizatordan tashqari kam sonli odamlar ushbu diqqatlilik testidan o'tishlari mumkin edi. Ushbu nusxa ko'chirish va joylashtirish misoli aynan shu sababga ko'ra yaxshi.
Ogohlantirishlar N3
struct RCT12SpriteBase
{
....
uint8_t flags;
....
};
struct rct1_peep : RCT12SpriteBase
{
....
uint8_t flags;
....
};
Albatta, asosiy sinfda va avlodda bir xil nomdagi o'zgaruvchidan foydalanish har doim ham xato emas. Biroq, meros texnologiyasining o'zi ota-onalar sinfining barcha sohalari bolalar sinfida mavjud deb taxmin qiladi. Vorisda bir xil nomdagi maydonlarni e'lon qilish orqali biz chalkashliklarni keltirib chiqaramiz.
Ogohlantirish N4
void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
if ((imageDirection / 8) && (imageDirection / 8) != 3)
{
....
}
....
}
Keling, batafsil ko'rib chiqaylik. Ifoda imageDirect/8 bo'lsa yolg'on bo'ladi tasvir yo'nalishi -7 dan 7 gacha bo'lgan oraliqda. Ikkinchi qism: (imageDirection / 8) != 3 cheklar tasvir yo'nalishi diapazondan tashqarida bo'lganligi uchun: mos ravishda -31 dan -24 gacha va 24 dan 31 gacha. Raqamlarni ma'lum bir diapazonga kiritish uchun shu tarzda tekshirish men uchun juda g'alati tuyuladi va agar ushbu kod qismida xato bo'lmasa ham, men ushbu shartlarni aniqroq bo'lishi uchun qayta yozishni tavsiya qilaman. Bu ushbu kodni o'qiydigan va saqlaydigan odamlar uchun hayotni ancha osonlashtiradi.
Ogohlantirish N5
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;
....
}
....
}
Ushbu kod bo'lagi katta ehtimol bilan dekompilyatsiya orqali olingan. Keyin, qolgan sharhga ko'ra, ishlamaydigan kodning bir qismi olib tashlandi. Biroq, hali bir nechta operatsiyalar bor kursor identifikatori, bu ham juda mantiqiy emas.
Ogohlantirish N6
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); // <=
}
....
}
Ushbu kodni tuzatish juda oson, siz uni uchinchi marta tekshirishingiz kerak o'yinchi null ko'rsatkichga yoki uni shartli bayonotning asosiy qismiga qo'shing. Men ikkinchi variantni taklif qilaman:
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);
}
}
....
}
Ogohlantirish N7
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));
....
}
....
}
Siz o'qish qiyin bo'lgan kod qatoridan bir zarbada xalos bo'lishingiz va muammoni tekshirish orqali hal qilishingiz mumkin. nullptr. Men kodni quyidagi tarzda o'zgartirishni taklif qilaman:
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);
....
}
....
}
Ogohlantirish N8
void CustomListView::MouseUp(....)
{
....
if (!ColumnHeaderPressedCurrentState)
{
ColumnHeaderPressed = std::nullopt;
ColumnHeaderPressedCurrentState = false;
Invalidate();
}
}
Kod juda g'alati ko'rinadi. Menimcha, shartda yoki o'zgaruvchini qayta tayinlashda xatolik yuz berdi ColumnHeaderPressedCurrentState ma'no yolg'on.
xulosa
Ko'rib turganimizdek, PVS-Studio statik analizatorini TeamCity loyihangizga integratsiya qilish juda oddiy. Buning uchun faqat bitta kichik konfiguratsiya faylini yozish kifoya. Kodni tekshirish sizni montajdan so'ng darhol muammolarni aniqlash imkonini beradi, bu esa o'zgarishlarning murakkabligi va narxi hali ham past bo'lganda ularni bartaraf etishga yordam beradi.
Agar siz ushbu maqolani ingliz tilida so'zlashuvchi auditoriya bilan baham ko'rmoqchi bo'lsangiz, tarjima havolasidan foydalaning: Vladislav Stolyarov.
Manba: www.habr.com