PVS-Studio analizatorundan istifadə üçün ən aktual ssenarilərdən biri onun CI sistemləri ilə inteqrasiyasıdır. Demək olar ki, hər hansı bir davamlı inteqrasiya sistemindən PVS-Studio layihəsinin təhlili yalnız bir neçə əmrə daxil edilə bilsə də, biz bu prosesi daha da rahatlaşdırmağa davam edirik. PVS-Studio indi analizatorun çıxışını TeamCity - TeamCity Təftiş Tipi formatına çevirmək dəstəyinə malikdir. Gəlin görək necə işləyir.
İstifadə olunan proqram təminatı haqqında məlumat
Tədqiq olunan layihə haqqında məlumat
Gəlin bu funksionallığı praktiki nümunədə sınayaq - OpenRCT2 layihəsini təhlil edək.
nizamlama
Vaxta qənaət etmək üçün yəqin ki, quraşdırma prosesini atlayacağam və kompüterimdə TeamCity serveri işlədiyi andan başlayacağam. Bizə getməliyik: localhost:{quraşdırma prosesi zamanı göstərilən port} (mənim vəziyyətimdə, localhost:9090) və avtorizasiya məlumatlarını daxil etməliyik. Girdikdən sonra bizi qarşılayacaqlar:
Layihə Yarat düyməsini basın. Sonra, Əl ilə seçin və sahələri doldurun.
Düyməni basdıqdan sonra Yaratmaq, bizi parametrləri olan bir pəncərə qarşılayır.
Gəlin klikləyək Quraşdırma konfiqurasiyası yaradın.
Sahələri doldurun və üzərinə klikləyin Yaratmaq. Versiya idarəetmə sistemini seçməyinizi xahiş edən bir pəncərə görürük. Mənbələr artıq yerli yerləşdiyindən, klikləyin Keçmək.
Nəhayət, layihə parametrlərinə keçirik.
Bunu etmək üçün montaj addımlarını əlavə edək: Quraşdırma addımları -> Quraşdırma addımı əlavə edin.
Burada seçirik:
- Qaçış növü -> Komanda xətti
- Çalıştır -> Xüsusi Skript
Layihənin tərtibi zamanı təhlil aparacağımız üçün montaj və təhlil bir addım olmalıdır, ona görə də sahəni doldurun Xüsusi skript:
Fərdi addımlara daha sonra baxacağıq. Analizatorun yüklənməsi, layihənin yığılması, təhlili, hesabatın çıxarılması və formatlaşdırılması yalnız on bir sətir kod tələb etməsi vacibdir.
Etməli olduğumuz son şey, onların oxunaqlılığını yaxşılaşdırmaq üçün bəzi yolları qeyd etdiyim mühit dəyişənlərini təyin etməkdir. Bunu etmək üçün davam edək: Parametrlər -> Yeni parametr əlavə edin və üç dəyişən əlavə edin:
Sizə lazım olan tək şey düyməni sıxmaqdır qaçış yuxarı sağ küncdə. Layihə yığılıb təhlil edilərkən mən sizə ssenari haqqında məlumat verəcəyəm.
Birbaşa skript
Əvvəlcə ən son PVS-Studio paylanmasını endirməliyik. Bunun üçün biz Chocolatey paket menecerindən istifadə edirik. Bu barədə daha çox bilmək istəyənlər üçün müvafiq var
choco install pvs-studio -y
Sonra, CLMonitor layihəsinin qurulmasını izləmə proqramını işə salaq.
%CLmon% monitor –-attach
Sonra layihəni mühit dəyişəni kimi quracağıq MSB qurmalı olduğum MSBuild versiyasına gedən yoldur
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
PVS-Studio üçün giriş və lisenziya açarını daxil edək:
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
Quraşdırma tamamlandıqdan sonra əvvəlcədən işlənmiş fayllar və statik analiz yaratmaq üçün CLMonitor-u yenidən işə salın:
%CLmon% analyze -l "c:ptest.plog"
Sonra paylamamızdan başqa bir yardım proqramı istifadə edəcəyik. PlogConverter hesabatı standart formatdan TeamCity-ə məxsus formata çevirir. Bunun sayəsində biz onu birbaşa quraşdırma pəncərəsində görə biləcəyik.
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
Son addım formatlanmış hesabatı göstərməkdir stdout, TeamCity təhlilçisi tərəfindən alınacağı yer.
type "C:tempptest.plog_TeamCity.txt"
Tam skript kodu:
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"
Bu vaxt layihənin montajı və təhlili uğurla tamamlandı, sekmeye keçə bilərik Layihələr və buna əmin olun.
İndi klikləyək Yoxlamalar Cəmianalizator hesabatına baxmaq üçün:
Xəbərdarlıqlar diaqnostik qayda nömrələrinə görə qruplaşdırılır. Kodda naviqasiya etmək üçün xəbərdarlıq ilə sətir nömrəsinə klik etməlisiniz. Yuxarı sağ küncdəki sual işarəsinə klikləsəniz, sənədlərlə yeni bir tab açılacaqdır. Siz həmçinin analizator xəbərdarlığı ilə sətir nömrəsinə klikləməklə kod arasında gedə bilərsiniz. İstifadə edərkən uzaq kompüterdən naviqasiya mümkündür SourceTreeRoot marker. Analizatorun bu iş rejimi ilə maraqlanan hər kəs müvafiq bölmə ilə tanış ola bilər
Analizatorun nəticələrinə baxmaq
Quraşdırmanı yerləşdirməyi və konfiqurasiyanı bitirdiyimizə görə, gəlin baxdığımız layihədə tapılan bəzi maraqlı xəbərdarlıqlara nəzər salaq.
Xəbərdarlıq 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 yaddaşı dinamik şəkildə yerləşdirdikdən sonra bir səhv gördü Obyekt yaradın, istisna baş verdikdə, yaddaş təmizlənmir və yaddaş sızması baş verir.
Xəbərdarlıq 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 başqa çox az adam bu diqqətlilik testindən keçə bilər. Bu kopyala-yapışdır nümunəsi məhz bu səbəbdən yaxşıdır.
Xəbərdarlıqlar N3
struct RCT12SpriteBase
{
....
uint8_t flags;
....
};
struct rct1_peep : RCT12SpriteBase
{
....
uint8_t flags;
....
};
Təbii ki, eyni adlı dəyişənin əsas sinifdə və nəsildə istifadə edilməsi həmişə səhv deyil. Bununla belə, miras texnologiyasının özü ana sinifin bütün sahələrinin uşaq sinifdə mövcud olduğunu güman edir. Eyni adlı sahələri varisdə elan etməklə, biz qarışıqlıq yaradırıq.
Xəbərdarlıq N4
void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
if ((imageDirection / 8) && (imageDirection / 8) != 3)
{
....
}
....
}
Gəlin daha yaxından nəzər salaq. İfadə imageDirection/8 olsa yalan olacaq şəkil istiqaməti -7 ilə 7 aralığındadır. İkinci hissə: (imageDirection / 8) != 3 çeklər şəkil istiqaməti diapazondan kənarda olmaq üçün: müvafiq olaraq -31-dən -24 və 24-dən 31-ə qədər. Nömrələri müəyyən diapazona daxil etmək üçün bu şəkildə yoxlamaq mənə olduqca qəribə görünür və bu kod parçasında heç bir səhv olmasa belə, daha aydın olması üçün bu şərtləri yenidən yazmağı tövsiyə edərdim. Bu, bu kodu oxuyan və saxlayan insanların həyatını çox asanlaşdırar.
Xəbərdarlıq 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;
....
}
....
}
Bu kod parçası çox güman ki, dekompilyasiya yolu ilə əldə edilmişdir. Sonra, qalan şərhə əsasən, işləməyən kodun bir hissəsi silindi. Ancaq hələ bir neçə əməliyyat var kursorİd, bu da çox məna kəsb etmir.
Xəbərdarlıq 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); // <=
}
....
}
Bu kodu düzəltmək olduqca asandır, sadəcə onu üçüncü dəfə yoxlamaq lazımdır oyunçu null göstəriciyə və ya onu şərti ifadənin gövdəsinə əlavə edin. Mən ikinci variantı təklif edərdim:
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);
}
}
....
}
Xəbərdarlıq 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));
....
}
....
}
Oxunması çətin olan kod sətirindən bir anda xilas ola və problemi yoxlayaraq həll edə bilərsiniz. nullptr. Kodu aşağıdakı kimi dəyişdirməyi təklif edirəm:
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);
....
}
....
}
Xəbərdarlıq N8
void CustomListView::MouseUp(....)
{
....
if (!ColumnHeaderPressedCurrentState)
{
ColumnHeaderPressed = std::nullopt;
ColumnHeaderPressedCurrentState = false;
Invalidate();
}
}
Kod olduqca qəribə görünür. Mənə elə gəlir ki, ya şərtdə, ya da dəyişəni yenidən təyin edərkən hərf səhvi olub ColumnHeaderPressedCurrentState mənaları saxta.
Buraxılış
Gördüyümüz kimi, PVS-Studio statik analizatorunu TeamCity layihənizə inteqrasiya etmək olduqca sadədir. Bunun üçün yalnız bir kiçik konfiqurasiya faylı yazmaq kifayətdir. Kodun yoxlanılması, montajdan dərhal sonra problemləri müəyyən etməyə imkan verəcək, bu, dəyişikliklərin mürəkkəbliyi və dəyəri hələ də aşağı olduqda onları aradan qaldırmağa kömək edəcəkdir.
Bu məqaləni ingilisdilli auditoriya ilə bölüşmək istəyirsinizsə, tərcümə linkindən istifadə edin: Vladislav Stolyarov.
Mənbə: www.habr.com