Unu el la plej aktualaj scenaroj por uzi la analizilon PVS-Studio estas ĝia integriĝo kun CI-sistemoj. Kaj kvankam la analizo de projekto de PVS-Studio el preskaŭ ajna kontinua integriga sistemo povas esti konstruita en nur kelkajn komandojn, ni daŭre faras ĉi tiun procezon eĉ pli oportuna. PVS-Studio nun havas subtenon por konverti analizilproduktaĵon en formaton por TeamCity - TeamCity Inspections Type. Ni vidu kiel ĝi funkcias.
Informoj pri la uzata programaro
Informoj pri la studata projekto
Ni provu ĉi tiun funkcion sur praktika ekzemplo - ni analizu la projekton OpenRCT2.
alĝustigo
Por ŝpari tempon, mi verŝajne preterlasos la instalan procezon kaj komencos de la momento, kiam mi havas la TeamCity-servilon funkciantan en mia komputilo. Ni devas iri al: localhost:{porto specifita dum la instala procezo} (en mia kazo, localhost:9090) kaj enigi rajtigajn datumojn. Post la eniro ni estos salutitaj de:
Alklaku la butonon Krei Projekton. Poste, elektu Mane kaj plenigu la kampojn.
Post premado de la butono krei, nin salutas fenestro kun agordoj.
Ni klaku Krei konstruan agordon.
Plenigu la kampojn kaj alklaku krei. Ni vidas fenestron, kiu petas vin elekti version-kontrolsistemon. Ĉar la fontoj jam troviĝas loke, alklaku Preterpasi.
Fine, ni transiru al la projektaj agordoj.
Ni aldonu asembleajn paŝojn, por fari ĉi tion klaku: Konstrupaŝoj -> Aldonu konstrupaŝon.
Ĉi tie ni elektas:
- Kura tipo -> Komandlinio
- Run -> Propra Skripto
Ĉar ni faros analizon dum projekta kompilo, muntado kaj analizo devus esti unu paŝo, do plenigu la kampon Propra Skribo:
Ni rigardos individuajn paŝojn poste. Gravas, ke ŝarĝi la analizilon, kunmeti la projekton, analizi ĝin, eligi la raporton kaj formati ĝin bezonas nur dek unu liniojn de kodo.
La lasta afero, kiun ni devas fari, estas agordi la mediajn variablojn, kiujn mi skizis kelkajn manierojn plibonigi ilian legeblecon. Por fari tion, ni pluiru: Parametroj -> Aldonu novan parametron kaj aldonu tri variablojn:
Ĉio, kion vi devas fari, estas premi la butonon Kuri en la supra dekstra angulo. Dum la projekto estas kunvenita kaj analizata, mi rakontos al vi pri la skripto.
Rekte skripto
Unue, ni devas elŝuti la plej novan distribuadon de PVS-Studio. Por tio ni uzas la pakaĵadministrilon Chocolatey. Por tiuj, kiuj volas scii pli pri tio, ekzistas koresponda
choco install pvs-studio -y
Poste, ni lanĉu la konstruan spuran ilon de la projekto CLMonitor.
%CLmon% monitor –-attach
Tiam ni konstruos la projekton kiel mediovariablo MSB estas la vojo al la versio de MSBuild, kiun mi bezonas konstrui
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
Ni enigu la ensaluton kaj permesilon ŝlosilon por PVS-Studio:
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
Post kiam la konstruo finiĝos, rulu CLMonitor denove por generi antaŭprilaboritajn dosierojn kaj statikan analizon:
%CLmon% analyze -l "c:ptest.plog"
Tiam ni uzos alian ilon de nia distribuo. PlogConverter konvertas raporton de norma formato al TeamCity-specifa formato. Dank' al ĉi tio, ni povos rigardi ĝin rekte en la konstrua fenestro.
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
La lasta paŝo estas montri la formatitan raporton en stdout, kie ĝi estos prenita de la analizanto de TeamCity.
type "C:tempptest.plog_TeamCity.txt"
Plena skriptokodo:
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"
Intertempe, la asembleo kaj analizo de la projekto finiĝis sukcese, ni povas iri al la langeto projektoj kaj certigu pri tio.
Nun ni alklaku Inspektadoj Sumopor iri al rigardado de la analizilo-raporto:
Avertoj estas grupigitaj per diagnozaj regulnombroj. Por navigi tra la kodo, vi devas alklaki la linionumeron kun la averto. Alklakante la demandosignon en la supra dekstra angulo malfermos al vi novan langeton kun dokumentado. Vi ankaŭ povas navigi tra la kodo alklakante la linionumeron kun la analizilo averto. Navigado de fora komputilo eblas dum uzado FontoTreeRoot markilo. Ĉiu, kiu interesiĝas pri ĉi tiu operacia maniero de la analizilo, povas konatiĝi kun la responda sekcio
Vidante la rezultojn de la analizilo
Nun kiam ni finis deploji kaj agordi la konstruon, ni rigardu kelkajn interesajn avertojn trovitajn en la projekto, kiun ni rigardas.
Averto 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;
}
La analizilo rimarkis eraron, kiu post dinamike asignado de memoro en KreiObjekton, kiam okazas escepto, la memoro ne estas malbarita, kaj memorfuĝo okazas.
Averto 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),
....
};
Malmultaj homoj krom senmova analizilo povus trapasi ĉi tiun atentecteston. Ĉi tiu kopi-alglua ekzemplo estas bona ĝuste pro tio.
Avertoj N3
struct RCT12SpriteBase
{
....
uint8_t flags;
....
};
struct rct1_peep : RCT12SpriteBase
{
....
uint8_t flags;
....
};
Kompreneble, uzi variablon kun la sama nomo en la baza klaso kaj en la posteulo ne ĉiam estas eraro. Tamen, hereda teknologio mem supozas ke ĉiuj kampoj de la gepatra klaso ĉeestas en la infanklaso. Deklarante kampojn kun la sama nomo en la kronprinco, ni enkondukas konfuzon.
Averto N4
void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
if ((imageDirection / 8) && (imageDirection / 8) != 3)
{
....
}
....
}
Ni rigardu pli detale. Esprimo bildoDirekto/8 estos malvera se bildoDirekto estas en la intervalo de -7 ĝis 7. Dua parto: (bildoDirekto / 8) != 3 ĉekoj bildoDirekto por esti ekster la intervalo: de -31 ĝis -24 kaj de 24 ĝis 31, respektive. Ŝajnas al mi sufiĉe strange kontroli nombrojn por inkluziviĝo en certa intervalo tiamaniere kaj, eĉ se ne estas eraro en ĉi tiu kodo, mi rekomendus reverki ĉi tiujn kondiĉojn por esti pli eksplicita. Ĉi tio multe plifaciligus la vivon por la homoj, kiuj legus kaj konservus ĉi tiun kodon.
Averto 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;
....
}
....
}
Tiu ĉi kodfragmento estis plej verŝajne akirita per malkompilo. Tiam, juĝante laŭ la lasita komento, parto de la nefunkcianta kodo estis forigita. Tamen restas ankoraŭ kelkaj operacioj cursorId, kiuj ankaŭ ne havas multe da senco.
Averto 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); // <=
}
....
}
Ĉi tiu kodo estas sufiĉe facile korektebla; vi nur bezonas kontroli ĝin trian fojon ludanton al nula montrilo, aŭ aldonu ĝin al la korpo de la kondiĉa deklaro. Mi sugestus la duan eblon:
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);
}
}
....
}
Averto 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));
....
}
....
}
Vi povas forigi malfacile legeblan linion de kodo per unu paŝo kaj solvi la problemon per kontrolo de nullptr. Mi proponas ŝanĝi la kodon jene:
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);
....
}
....
}
Averto N8
void CustomListView::MouseUp(....)
{
....
if (!ColumnHeaderPressedCurrentState)
{
ColumnHeaderPressed = std::nullopt;
ColumnHeaderPressedCurrentState = false;
Invalidate();
}
}
La kodo aspektas sufiĉe strange. Ŝajnas al mi, ke estis mistajpo aŭ en la kondiĉo aŭ dum reasignado de la variablo ColumnHeaderPressedCurrentState valoroj falsa.
konkludo
Kiel ni povas vidi, integri la statikan analizilon PVS-Studio en vian TeamCity-projekton estas sufiĉe simpla. Por fari tion, sufiĉas skribi nur unu malgrandan agordan dosieron. Kontroli la kodon permesos vin identigi problemojn tuj post asembleo, kio helpos forigi ilin kiam la komplekseco kaj kosto de ŝanĝoj ankoraŭ estas malaltaj.
Se vi volas dividi ĉi tiun artikolon kun anglalingva publiko, bonvolu uzi la tradukan ligilon: Vladislav Stolyarov.
fonto: www.habr.com