Viens no aktuÄlÄkajiem PVS-Studio analizatora izmantoÅ”anas scenÄrijiem ir tÄ integrÄcija ar CI sistÄmÄm. Un, lai gan PVS-Studio projekta analÄ«zi no gandrÄ«z jebkuras nepÄrtrauktas integrÄcijas sistÄmas var iebÅ«vÄt tikai dažÄs komandÄs, mÄs turpinÄm padarÄ«t Å”o procesu vÄl ÄrtÄku. PVS-Studio tagad atbalsta analizatora izvades pÄrveidoÅ”anu TeamCity formÄtÄ ā TeamCity Inspections Type. ApskatÄ«sim, kÄ tas darbojas.
InformÄcija par izmantoto programmatÅ«ru
InformÄcija par pÄtÄmo projektu
IzmÄÄ£inÄsim Å”o funkcionalitÄti praktiskÄ piemÄrÄ ā analizÄsim OpenRCT2 projektu.
koriÄ£ÄÅ”ana
Lai ietaupÄ«tu laiku, es, iespÄjams, izlaidÄ«Å”u instalÄÅ”anas procesu un sÄkÅ”u no brīža, kad manÄ datorÄ darbojas TeamCity serveris. Mums jÄiet uz vietni localhost:{instalÄÅ”anas procesÄ norÄdÄ«tais ports} (manÄ gadÄ«jumÄ localhost:9090) un jÄievada autorizÄcijas dati. PÄc ieieÅ”anas mÅ«s sagaidÄ«s:
NoklikŔķiniet uz pogas Izveidot projektu. PÄc tam atlasiet ManuÄli un aizpildiet laukus.
PÄc pogas nospieÅ”anas izveidot, mÅ«s sagaida logs ar iestatÄ«jumiem.
NoklikŔķinÄsim Izveidojiet bÅ«vÄjuma konfigurÄciju.
Aizpildiet laukus un noklikŔķiniet uz izveidot. Tiek parÄdÄ«ts logs ar aicinÄjumu izvÄlÄties versiju kontroles sistÄmu. TÄ kÄ avoti jau atrodas lokÄli, noklikŔķiniet uz Izlaist.
Visbeidzot, mÄs pÄrejam pie projekta iestatÄ«jumiem.
Pievienosim montÄžas soļus, lai to izdarÄ«tu, noklikŔķiniet: BÅ«vÄÅ”anas soļi ā> Pievienot bÅ«vÄÅ”anas soli.
Å eit mÄs izvÄlamies:
- SkrÄjÄja veids -> Komandrinda
- Palaist -> PielÄgots skripts
TÄ kÄ mÄs veiksim analÄ«zi projekta apkopoÅ”anas laikÄ, montÄžai un analÄ«zei jÄbÅ«t vienam solim, tÄpÄc aizpildiet lauku PielÄgots skripts:
AtseviŔķus soļus apskatÄ«sim vÄlÄk. Ir svarÄ«gi, lai analizatora ielÄde, projekta salikÅ”ana, analÄ«ze, atskaites izvadÄ«Å”ana un formatÄÅ”ana aizÅem tikai vienpadsmit koda rindiÅas.
PÄdÄjÄ lieta, kas mums jÄdara, ir vides mainÄ«go iestatÄ«Å”ana, un esmu aprakstÄ«jis dažus veidus, kÄ uzlabot to lasÄmÄ«bu. Lai to izdarÄ«tu, turpinÄsim: Parametri -> Pievienot jaunu parametru un pievienojiet trÄ«s mainÄ«gos:
Viss, kas jums jÄdara, ir jÄnospiež poga skrÄjiens augÅ”ÄjÄ labajÄ stÅ«rÄ«. KamÄr projekts tiek montÄts un analizÄts, es jums pastÄstÄ«Å”u par scenÄriju.
TieŔi skripts
PirmkÄrt, mums ir jÄlejupielÄdÄ jaunÄkÄ PVS-Studio izplatÄ«Å”ana. Å im nolÅ«kam mÄs izmantojam Chocolatey pakotÅu pÄrvaldnieku. Tiem, kas vÄlas uzzinÄt vairÄk par Å”o, ir atbilstoÅ”s
choco install pvs-studio -y
PÄc tam palaidÄ«sim CLMonitor projekta bÅ«vÄÅ”anas izsekoÅ”anas utilÄ«tu.
%CLmon% monitor ā-attach
Tad mÄs veidosim projektu kÄ vides mainÄ«go MSB ir ceļŔ uz MSBuild versiju, kas man jÄveido
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
IevadÄ«sim PVS-Studio pieteikÅ”anÄs un licences atslÄgu:
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
Kad izveide ir pabeigta, vÄlreiz palaidiet CLMonitor, lai Ä£enerÄtu iepriekÅ” apstrÄdÄtus failus un statisko analÄ«zi:
%CLmon% analyze -l "c:ptest.plog"
Tad mÄs izmantosim citu utilÄ«tu no mÅ«su izplatÄ«Å”anas. PlogConverter pÄrveido atskaiti no standarta formÄta uz TeamCity specifisku formÄtu. Pateicoties tam, mÄs to varÄsim skatÄ«t tieÅ”i bÅ«vÄÅ”anas logÄ.
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
PÄdÄjais solis ir parÄdÄ«t formatÄto pÄrskatu stdout, kur to paÅems TeamCity parsÄtÄjs.
type "C:tempptest.plog_TeamCity.txt"
Pilns skripta kods:
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"
Pa to laiku projekta montÄža un analÄ«ze ir veiksmÄ«gi pabeigta, varam doties uz cilni AKTIVITÄTES un pÄrliecinieties par to.
Tagad noklikŔķiniet uz PÄrbaudes KopÄlai pÄrietu uz analizatora atskaites apskati:
BrÄ«dinÄjumi ir sagrupÄti pÄc diagnostikas noteikumu numuriem. Lai pÄrvietotos pa kodu, jums jÄnoklikŔķina uz rindas numura ar brÄ«dinÄjumu. NoklikŔķinot uz jautÄjuma zÄ«mes augÅ”ÄjÄ labajÄ stÅ«rÄ«, tiks atvÄrta jauna cilne ar dokumentÄciju. Varat arÄ« pÄrvietoties pa kodu, noklikŔķinot uz rindas numura ar analizatora brÄ«dinÄjumu. Lietojot, ir iespÄjama navigÄcija no attÄlÄ datora SourceTreeRoot marÄ·ieris. Ikviens, kurÅ” interesÄjas par Å”o analizatora darbÄ«bas režīmu, var iepazÄ«ties ar atbilstoÅ”o sadaļu
Analizatora rezultÄtu apskate
Tagad, kad esam pabeiguÅ”i bÅ«vÄjuma izvietoÅ”anu un konfigurÄÅ”anu, apskatÄ«sim dažus interesantus brÄ«dinÄjumus, kas atrodami aplÅ«kotajÄ projektÄ.
BrÄ«dinÄjums 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;
}
Analizators pamanÄ«ja kļūdu, kas radÄs pÄc dinamiskas atmiÅas pieŔķirÅ”anas CreateObject, kad notiek izÅÄmums, atmiÅa netiek notÄ«rÄ«ta un rodas atmiÅas noplÅ«de.
BrÄ«dinÄjums 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),
....
};
Tikai daži cilvÄki, izÅemot statisko analizatoru, varÄtu izturÄt Å”o uzmanÄ«bas pÄrbaudi. Å is kopÄÅ”anas un ielÄ«mÄÅ”anas piemÄrs ir labs tieÅ”i Ŕī iemesla dÄļ.
BrÄ«dinÄjumi N3
struct RCT12SpriteBase
{
....
uint8_t flags;
....
};
struct rct1_peep : RCT12SpriteBase
{
....
uint8_t flags;
....
};
Protams, mainÄ«gÄ ar tÄdu paÅ”u nosaukumu izmantoÅ”ana pamatklasÄ un pÄcnÄcÄjÄ ne vienmÄr ir kļūda. TomÄr pati mantojuma tehnoloÄ£ija pieÅem, ka visi vecÄku klases lauki atrodas bÄrnu klasÄ. DeklarÄjot laukus ar tÄdu paÅ”u nosaukumu mantiniekÄ, mÄs radÄm neskaidrÄ«bas.
BrÄ«dinÄjums N4
void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
if ((imageDirection / 8) && (imageDirection / 8) != 3)
{
....
}
....
}
ApskatÄ«sim tuvÄk. Izteiksme imageDirection/8 bÅ«s nepatiess, ja imageDirection ir diapazonÄ no -7 lÄ«dz 7. OtrÄ daļa: (imageDirection / 8) != 3 pÄrbaudes imageDirection par atraÅ”anos Ärpus diapazona: attiecÄ«gi no -31 lÄ«dz -24 un no 24 lÄ«dz 31. Man Ŕķiet diezgan dÄ«vaini Å”ÄdÄ veidÄ pÄrbaudÄ«t, vai skaitļi ir iekļauti noteiktÄ diapazonÄ, un, pat ja Å”ajÄ koda daÄ¼Ä nav kļūdu, es ieteiktu Å”os nosacÄ«jumus pÄrrakstÄ«t, lai tie bÅ«tu skaidrÄki. Tas padarÄ«tu dzÄ«vi daudz vieglÄku cilvÄkiem, kuri lasÄ«tu un uzturÄtu Å”o kodu.
BrÄ«dinÄjums 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;
....
}
....
}
Å is koda fragments, visticamÄk, tika iegÅ«ts dekompilÄcijas ceļÄ. Tad, spriežot pÄc atstÄtÄ komentÄra, daļa no nestrÄdÄjoÅ”Ä koda tika izÅemta. TomÄr atlikuÅ”as vÄl pÄris operÄcijas kursora ID, kam arÄ« nav lielas jÄgas.
BrÄ«dinÄjums 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); // <=
}
....
}
Å o kodu ir diezgan viegli labot; jums tas tikai jÄpÄrbauda treÅ”o reizi atskaÅotÄjs uz nulles rÄdÄ«tÄju vai pievienojiet to nosacÄ«juma priekÅ”raksta pamattekstam. Es ieteiktu otro variantu:
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);
}
}
....
}
BrÄ«dinÄjums 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));
....
}
....
}
Varat vienÄ rÄvienÄ atbrÄ«voties no grÅ«ti salasÄmas koda rindas un atrisinÄt problÄmu, pÄrbaudot, vai nullptr. Es iesaku mainÄ«t kodu Å”Ädi:
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);
....
}
....
}
BrÄ«dinÄjums N8
void CustomListView::MouseUp(....)
{
....
if (!ColumnHeaderPressedCurrentState)
{
ColumnHeaderPressed = std::nullopt;
ColumnHeaderPressedCurrentState = false;
Invalidate();
}
}
Kods izskatÄs diezgan dÄ«vains. Man Ŕķiet, ka bija drukas kļūda vai nu nosacÄ«jumÄ, vai arÄ« mainot mainÄ«go ColumnHeaderPressedCurrentState nozÄ«me nepatiess.
secinÄjums
KÄ redzam, PVS-Studio statiskÄ analizatora integrÄÅ”ana TeamCity projektÄ ir pavisam vienkÄrÅ”a. Lai to izdarÄ«tu, pietiek ar vienu nelielu konfigurÄcijas failu. Koda pÄrbaude ļaus identificÄt problÄmas uzreiz pÄc montÄžas, kas palÄ«dzÄs tÄs novÄrst, ja izmaiÅu sarežģītÄ«ba un izmaksas joprojÄm ir zemas.
Ja vÄlaties dalÄ«ties ar Å”o rakstu ar angliski runÄjoÅ”u auditoriju, lÅ«dzu, izmantojiet tulkoÅ”anas saiti: Vladislavs Stoļarovs.
Avots: www.habr.com