Ett av de mest aktuella scenarierna för att använda PVS-Studio-analysatorn är dess integration med CI-system. Och även om analysen av ett PVS-Studio-projekt från nästan alla kontinuerliga integrationssystem kan byggas in i bara några få kommandon, fortsätter vi att göra denna process ännu mer bekväm. PVS-Studio har nu stöd för att konvertera analysatorns utdata till ett format för TeamCity - TeamCity Inspections Type. Låt oss se hur det fungerar.
Information om vilken programvara som används
Information om projektet som studeras
Låt oss prova den här funktionen med ett praktiskt exempel - låt oss analysera OpenRCT2-projektet.
justering
För att spara tid kommer jag förmodligen att hoppa över installationsprocessen och börja från det ögonblick då jag har TeamCity-servern igång på min dator. Vi måste gå till: localhost:{port specificerad under installationsprocessen} (i mitt fall, localhost:9090) och ange behörighetsdata. Efter inträde möts vi av:
Klicka på knappen Skapa projekt. Välj sedan Manuellt och fyll i fälten.
Efter att ha tryckt på knappen Skapa, möts vi av ett fönster med inställningar.
Låt oss klicka Skapa byggkonfiguration.
Fyll i fälten och klicka Skapa. Vi ser ett fönster som ber dig välja ett versionskontrollsystem. Eftersom källorna redan finns lokalt, klicka Hoppa.
Slutligen går vi vidare till projektinställningarna.
Låt oss lägga till monteringssteg, för att göra så här klicka: Byggsteg -> Lägg till byggsteg.
Här väljer vi:
- Löpare typ -> Kommandorad
- Kör -> Anpassat skript
Eftersom vi kommer att utföra analys under projektsammanställningen bör montering och analys vara ett steg, så fyll i fältet Anpassat skript:
Vi kommer att titta på enskilda steg senare. Det är viktigt att ladda analysatorn, sätta ihop projektet, analysera det, mata ut rapporten och formatera den bara tar elva rader kod.
Det sista vi behöver göra är att ställa in miljövariablerna, som jag har beskrivit några sätt att förbättra deras läsbarhet. För att göra detta, låt oss gå vidare: Parametrar -> Lägg till ny parameter och lägg till tre variabler:
Allt du behöver göra är att trycka på knappen Körning i det övre högra hörnet. Medan projektet håller på att monteras och analyseras kommer jag att berätta om manuset.
Manus direkt
Först måste vi ladda ner den senaste PVS-Studio-distributionen. För detta använder vi Chocolatey package manager. För den som vill veta mer om detta finns motsvarande
choco install pvs-studio -y
Låt oss sedan lansera spårningsverktyget för CLMonitor-projektet.
%CLmon% monitor –-attach
Sedan kommer vi att bygga projektet som en miljövariabel MSB är sökvägen till den version av MSBuild jag behöver bygga
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
Låt oss ange inloggnings- och licensnyckeln för PVS-Studio:
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
När konstruktionen är klar, kör CLMonitor igen för att generera förbearbetade filer och statisk analys:
%CLmon% analyze -l "c:ptest.plog"
Sedan kommer vi att använda ett annat verktyg från vår distribution. PlogConverter konverterar en rapport från ett standardformat till ett TeamCity-specifikt format. Tack vare detta kommer vi att kunna se det direkt i byggfönstret.
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
Det sista steget är att visa den formaterade rapporten i stdout, där det kommer att hämtas av TeamCity-parsern.
type "C:tempptest.plog_TeamCity.txt"
Fullständig skriptkod:
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"
Under tiden har monteringen och analysen av projektet slutförts framgångsrikt, vi kan gå till fliken Projekt och se till det.
Låt oss nu klicka vidare Besiktningar Totaltför att gå till att visa analysrapporten:
Varningar är grupperade efter diagnostiska regelnummer. För att navigera genom koden måste du klicka på radnumret med varningen. Genom att klicka på frågetecknet i det övre högra hörnet öppnas en ny flik med dokumentation. Du kan också navigera genom koden genom att klicka på radnumret med analysatorvarningen. Navigering från en fjärrdator är möjlig när du använder SourceTreeRoot markör. Alla som är intresserade av detta funktionssätt för analysatorn kan bekanta sig med motsvarande avsnitt
Visa analysatorns resultat
Nu när vi är klara med att distribuera och konfigurera bygget, låt oss ta en titt på några intressanta varningar som finns i projektet vi tittar på.
Varning 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;
}
Analysatorn märkte ett fel som efter att dynamiskt allokerat minne i Skapa objekt, när ett undantag inträffar rensas inte minnet och en minnesläcka inträffar.
Varning 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),
....
};
Få andra än en statisk analysator kunde klara detta uppmärksamhetstest. Det här copy-paste-exemplet är bra av just detta skäl.
Varningar N3
struct RCT12SpriteBase
{
....
uint8_t flags;
....
};
struct rct1_peep : RCT12SpriteBase
{
....
uint8_t flags;
....
};
Att använda en variabel med samma namn i basklassen och i descendent är naturligtvis inte alltid ett fel. Dock förutsätter arvsteknologin i sig att alla fält i föräldraklassen finns i barnklassen. Genom att deklarera fält med samma namn i arvtagaren inför vi förvirring.
Varning N4
void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
if ((imageDirection / 8) && (imageDirection / 8) != 3)
{
....
}
....
}
Låt oss ta en närmare titt. Uttryck imageDirection/8 kommer att vara falskt om bildriktning ligger i intervallet från -7 till 7. Andra delen: (imageDirection / 8) != 3 kontroller bildriktning för att ligga utanför intervallet: från -31 till -24 respektive från 24 till 31. Det förefaller mig ganska konstigt att kontrollera siffror för inkludering i ett visst intervall på det här sättet, och även om det inte finns något fel i denna kod, skulle jag rekommendera att skriva om dessa villkor för att vara mer explicita. Detta skulle göra livet mycket lättare för de människor som skulle läsa och underhålla den här koden.
Varning 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;
....
}
....
}
Detta kodfragment erhölls troligen genom dekompilering. Sedan, att döma av kommentaren som lämnades, togs en del av den icke-fungerande koden bort. Det återstår dock fortfarande ett par operationer cursorId, vilket inte heller är så vettigt.
Varning 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); // <=
}
....
}
Den här koden är ganska lätt att korrigera, du behöver bara kontrollera den en tredje gång Spelaren till en nollpekare, eller lägg till den i brödtexten i det villkorliga uttalandet. Jag skulle föreslå det andra alternativet:
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);
}
}
....
}
Varning 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));
....
}
....
}
Du kan bli av med en svårläst kodrad i ett svep och lösa problemet med att kontrollera nullptr. Jag föreslår att du ändrar koden enligt följande:
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);
....
}
....
}
Varning N8
void CustomListView::MouseUp(....)
{
....
if (!ColumnHeaderPressedCurrentState)
{
ColumnHeaderPressed = std::nullopt;
ColumnHeaderPressedCurrentState = false;
Invalidate();
}
}
Koden ser ganska konstig ut. Det verkar för mig att det fanns ett stavfel antingen i villkoret eller när variabeln tilldelades om ColumnHeaderPressedCurrentState betyder falsk.
Utgång
Som vi kan se är det ganska enkelt att integrera den statiska analysatorn PVS-Studio i ditt TeamCity-projekt. För att göra detta räcker det att bara skriva en liten konfigurationsfil. Genom att kontrollera koden kan du identifiera problem omedelbart efter montering, vilket hjälper till att eliminera dem när komplexiteten och kostnaden för ändringar fortfarande är låga.
Om du vill dela den här artikeln med en engelsktalande publik, använd gärna översättningslänken: Vladislav Stolyarov.
Källa: will.com