Unu di i scenarii più attuali per aduprà l'analizzatore PVS-Studio hè a so integrazione cù i sistemi CI. E ancu s'è l'analisi di un prughjettu PVS-Studio da quasi ogni sistema d'integrazione cuntinuu pò esse custruitu in uni pochi di cumandamenti, cuntinuemu à fà stu prucessu ancu più còmuda. PVS-Studio hà avà supportu per cunvertisce l'output di l'analizzatore in un furmatu per TeamCity - TeamCity Inspections Type. Videmu cumu si travaglia.
Informazioni nantu à u software utilizatu
Infurmazioni nantu à u prugettu in studiu
Pruvate sta funziunalità nantu à un esempiu praticu - analizemu u prughjettu OpenRCT2.
cutter
Per risparmià u tempu, prubabilmente saltaraghju u prucessu di stallazione è cumincià da u mumentu chì aghju u servitore TeamCity in esecuzione in u mo urdinatore. Avemu bisognu à andà à: localhost:{port specificatu durante u prucessu di stallazione} (in u mo casu, localhost:9090) è inserisce dati d'autorizazione. Dopu à l'entrata seremu salutati da:
Cliccate nant'à u buttone Crea Prughjettu. Dopu, selezziunate Manually è compie i campi.
Dopu à appughjà u buttone creà, simu salutati da una finestra cù paràmetri.
Facemu cliccà Crea a cunfigurazione di custruzzione.
Riempite i campi è cliccate creà. Avemu vistu una finestra chì vi dumanda à selezziunà un sistema di cuntrollu di versione. Siccomu i fonti sò digià situatu in u locu, cliccate Skip.
Infine, andemu à i paràmetri di u prugettu.
Aghjunghjemu i passi di l'assemblea, per fà questu cliccate: Custruisce i passi -> Aggiungi un passu di custruzzione.
Quì avemu sceltu:
- Runner type -> Command Line
- Run -> Script Custom
Siccomu realiceremu analisi durante a compilazione di u prugettu, l'assemblea è l'analisi duveranu esse un passu, cusì compie u campu Scrittura Customizata:
Fighjemu i passi individuali dopu. Hè impurtante chì caricate l'analizzatore, assemblendu u prughjettu, analizà, stende u rapportu è furmàttate solu undici linee di codice.
L'ultima cosa chì avemu da fà hè di stabilisce e variabili di l'ambienti, chì aghju delineatu alcune manere di migliurà a so leghjibilità. Per fà questu, andemu avanti: Parametri -> Aggiungi un novu paràmetru è aghjunghje trè variàbili:
Tuttu ciò chì deve fà hè appughjà u buttone Run in l'angulu superiore dirittu. Mentre u prugettu hè assemblatu è analizatu, vi dicu di u script.
Scrittura diretta
Prima, avemu bisognu di scaricà l'ultima distribuzione PVS-Studio. Per questu usemu u gestore di pacchetti Chocolatey. Per quelli chì vulete sapè più nantu à questu, ci hè un currispundente
choco install pvs-studio -y
In seguitu, lanciamu l'utilità di seguimentu di u prugettu CLMonitor.
%CLmon% monitor –-attach
Allora custruiremu u prughjettu cum'è una variabile d'ambiente MSB hè a strada per a versione di MSBuild chì aghju bisognu di custruisce
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
Entremu u login è a chjave di licenza per PVS-Studio:
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
Dopu chì a custruzione hè cumpleta, eseguite CLMonitor di novu per generà fugliali preprocessati è analisi statica:
%CLmon% analyze -l "c:ptest.plog"
Allora avemu aduprà una altra utilità da a nostra distribuzione. PlogConverter converte un rapportu da un formatu standard à un formatu specificu di TeamCity. Grazie à questu, pudemu vede direttamente in a finestra di creazione.
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
L'ultimu passu hè di vede u rapportu furmatu in stdout, induve serà pigliatu da u parser TeamCity.
type "C:tempptest.plog_TeamCity.txt"
Codice di script cumpletu:
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"
Intantu, l'assemblea è l'analisi di u prugettu hè stata cumpletata cù successu, pudemu andà à a tabulazione Projects è assicuratevi.
Avà andemu à cliccà Inspeczioni totaliper andà à vede u rapportu di l'analizzatore:
L'avvertimenti sò raggruppati per numeri di regula di diagnostica. Per navigà à traversu u codice, avete bisognu di cliccà nantu à u numeru di linea cù l'avvertimentu. Cliccà nant'à u puntu d'interrogazione in l'angulu superiore destra vi apre una nova tabulazione cù documentazione. Pudete ancu navigà à traversu u codice clicchendu nantu à u numeru di linea cù l'avvertimentu di l'analizzatore. A navigazione da un computer remoto hè pussibule quandu si usa SourceTreeRoot marcatore. Qualchissia chì hè interessatu in stu modu di funziunamentu di l'analizzatore pò familiarizà cù a sezione currispondente
Vede i risultati di l'analizzatore
Avà chì avemu finitu di implementà è cunfigurà a custruzione, fighjemu un ochju à qualchi avvirtimenti interessanti truvati in u prughjettu chì guardemu.
Avvertimentu 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;
}
L'analizzatore hà rimarcatu un errore chì dopu l'assignazione dinamica di memoria in Crea un oggettu, quandu si trova una eccezzioni, a memoria ùn hè micca sguassata, è una fuga di memoria si trova.
Avvertimentu 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),
....
};
Pochi persone altru ch'è un analizzatore staticu puderia passà sta prova di attenteness. Questu esempiu di copia-incolla hè bonu per precisamente per questu mutivu.
Avvertimenti N3
struct RCT12SpriteBase
{
....
uint8_t flags;
....
};
struct rct1_peep : RCT12SpriteBase
{
....
uint8_t flags;
....
};
Di sicuru, l'usu di una variàbile cù u listessu nome in a classa di basa è in u discendenti ùn hè micca sempre un errore. In ogni casu, a tecnulugia di l'eredità stessu assume chì tutti i campi di a classa parenti sò prisenti in a classe di u zitellu. Dichjarà campi cù u listessu nome in l'eredi, intruducemu cunfusione.
Avvertimentu N4
void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
if ((imageDirection / 8) && (imageDirection / 8) != 3)
{
....
}
....
}
Fighjemu un ochju più vicinu. Spressione Direzzione image/8 serà falsu se Direzzione di l'imaghjini hè in u range da -7 à 7. Seconda parte: (direzzione di l'imaghjini / 8) != 3 cuntrolli Direzzione di l'imaghjini per esse fora di a gamma: da -31 à -24 è da 24 à 31, rispettivamente. Mi pare abbastanza stranu per verificà i numeri per l'inclusione in un certu intervallu in questu modu è, ancu s'ellu ùn ci hè micca errore in questu pezzu di codice, ricumandemu di riscrittura di sti cundizioni per esse più espliciti. Questu faria a vita assai più faciule per e persone chì leghjenu è mantene stu codice.
Avvertimentu 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;
....
}
....
}
Stu frammentu di codice hè statu più prubabilmente ottenutu da decompilation. Allora, à ghjudicà da u cumentu lasciatu, una parte di u codice chì ùn funziona micca hè stata eliminata. Tuttavia, ci sò sempre un paru di operazioni cursorId, chì ancu ùn hà micca assai sensu.
Avvertimentu 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); // <=
}
....
}
Stu codice hè abbastanza faciule da curregà; basta à verificà una terza volta jocaturi à un puntatore nulu, o aghjunghje à u corpu di a dichjarazione condicionale. Suggeriu a seconda opzione:
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);
}
}
....
}
Avvertimentu 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));
....
}
....
}
Pudete caccià una linea di codice difficiuli di leghje in un colpu è risolve u prublema cù a verificazione di nullptr. Suggeriu di cambià u codice cum'è seguente:
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);
....
}
....
}
Avvertimentu N8
void CustomListView::MouseUp(....)
{
....
if (!ColumnHeaderPressedCurrentState)
{
ColumnHeaderPressed = std::nullopt;
ColumnHeaderPressedCurrentState = false;
Invalidate();
}
}
U codice pare abbastanza stranu. Mi pari chì ci era un typo o in a cundizione o quandu ri-assignà a variàbile ColumnHeaderPressedCurrentState significatu sbagliate.
cunchiusioni
Comu pudemu vede, l'integrazione di l'analizzatore staticu PVS-Studio in u vostru prughjettu TeamCity hè abbastanza simplice. Per fà questu, hè abbastanza à scrive solu un picculu schedariu di cunfigurazione. A verificazione di u codice vi permetterà di identificà i prublemi immediatamente dopu l'assemblea, chì aiutarà à eliminà quandu a cumplessità è u costu di i cambiamenti sò sempre bassu.
Se vulete sparte stu articulu cù un publicu anglofonu, per piacè utilizate u ligame di traduzzione: Vladislav Stolyarov.
Source: www.habr.com