Een van de meest actuele scenario's voor het gebruik van de PVS-Studio-analysator is de integratie met CI-systemen. En hoewel de analyse van een PVS-Studio-project vanuit vrijwel elk continu integratiesysteem in slechts een paar commando's kan worden ingebouwd, blijven we dit proces nog handiger maken. PVS-Studio biedt nu ondersteuning voor het converteren van de uitvoer van de analyser naar een formaat voor TeamCity - TeamCity Inspections Type. Laten we kijken hoe het werkt.
Informatie over de gebruikte software
Informatie over het onderzochte project
Laten we deze functionaliteit proberen met een praktisch voorbeeld - laten we het OpenRCT2-project analyseren.
afstelling
Om tijd te besparen sla ik waarschijnlijk het installatieproces over en begin ik vanaf het moment dat ik de TeamCity-server op mijn computer heb draaien. We moeten naar: localhost:{poort gespecificeerd tijdens het installatieproces} (in mijn geval localhost:9090) en autorisatiegegevens invoeren. Na binnenkomst worden wij begroet door:
Klik op de knop Project aanmaken. Selecteer vervolgens Handmatig en vul de velden in.
Na het indrukken van de knop creëren, worden we begroet door een venster met instellingen.
Laten we klikken Maak een buildconfiguratie.
Vul de velden in en klik creëren. We zien een venster waarin u wordt gevraagd een versiebeheersysteem te selecteren. Omdat de bronnen zich al lokaal bevinden, klikt u op overslaan.
Ten slotte gaan we verder met de projectinstellingen.
Laten we montagestappen toevoegen. Klik hiervoor op: Bouwstappen -> Bouwstap toevoegen.
Hier kiezen wij:
- Runner-type -> Commandoregel
- Uitvoeren -> Aangepast script
Omdat we analyses zullen uitvoeren tijdens het samenstellen van het project, moeten assemblage en analyse één stap zijn, dus vul het veld in Aangepast script:
We zullen later naar de afzonderlijke stappen kijken. Het is belangrijk dat het laden van de analyser, het samenstellen van het project, het analyseren ervan, het uitvoeren van het rapport en het formatteren ervan slechts elf regels code vergt.
Het laatste dat we moeten doen is de omgevingsvariabelen instellen, waarvan ik enkele manieren heb geschetst om hun leesbaarheid te verbeteren. Om dit te doen, gaan we verder: Parameters -> Nieuwe parameter toevoegen en voeg drie variabelen toe:
Het enige dat u hoeft te doen, is op de knop drukken lopen in de rechterbovenhoek. Terwijl het project wordt samengesteld en geanalyseerd, zal ik je over het script vertellen.
Direct script
Eerst moeten we de nieuwste PVS-Studio-distributie downloaden. Hiervoor gebruiken we de Chocolatey pakketbeheerder. Voor degenen die hier meer over willen weten, is er een overeenkomstige
choco install pvs-studio -y
Laten we vervolgens het CLMonitor-hulpprogramma voor het volgen van projectbuilds starten.
%CLmon% monitor –-attach
Vervolgens bouwen we het project als een omgevingsvariabele MSB is het pad naar de versie van MSBuild die ik moet bouwen
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
Laten we de login- en licentiesleutel voor PVS-Studio invoeren:
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
Nadat de build is voltooid, voert u CLMonitor opnieuw uit om voorbewerkte bestanden en statische analyses te genereren:
%CLmon% analyze -l "c:ptest.plog"
Dan zullen we een ander hulpprogramma uit onze distributie gebruiken. PlogConverter converteert een rapport van een standaardformaat naar een TeamCity-specifiek formaat. Hierdoor kunnen we het rechtstreeks in het buildvenster bekijken.
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
De laatste stap is het weergeven van het opgemaakte rapport stdout, waar het zal worden opgepikt door de TeamCity-parser.
type "C:tempptest.plog_TeamCity.txt"
Volledige scriptcode:
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"
Inmiddels is de montage en analyse van het project succesvol afgerond, we kunnen naar het tabblad gaan Projecten en едиться в ом.
Laten we nu verder klikken Inspecties Totaalom naar het analyserrapport te gaan:
Waarschuwingen zijn gegroepeerd op diagnostische regelnummers. Om door de code te navigeren, klikt u op het regelnummer met de waarschuwing. Als u op het vraagteken in de rechterbovenhoek klikt, wordt een nieuw tabblad met documentatie geopend. U kunt ook door de code navigeren door op het regelnummer met de analysatorwaarschuwing te klikken. Navigatie vanaf een externe computer is mogelijk bij gebruik BronBoomwortel markeerstift. Iedereen die geïnteresseerd is in deze werkingsmodus van de analysator, kan zich vertrouwd maken met de overeenkomstige sectie
De resultaten van de analysator bekijken
Nu we klaar zijn met het implementeren en configureren van de build, gaan we eens kijken naar enkele interessante waarschuwingen in het project waar we naar kijken.
Waarschuwing 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;
}
De analysator heeft een fout opgemerkt die na het dynamisch toewijzen van geheugen in Object makenWanneer er een uitzondering optreedt, wordt het geheugen niet gewist en treedt er een geheugenlek op.
Waarschuwing 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),
....
};
Er zijn maar weinig andere mensen dan een statische analysator die deze aandachtstest kunnen doorstaan. Dit copy-paste-voorbeeld is juist om deze reden goed.
Waarschuwingen N3
struct RCT12SpriteBase
{
....
uint8_t flags;
....
};
struct rct1_peep : RCT12SpriteBase
{
....
uint8_t flags;
....
};
Natuurlijk is het gebruik van een variabele met dezelfde naam in de basisklasse en in de afstammeling niet altijd een fout. De overervingstechnologie zelf gaat er echter van uit dat alle velden van de ouderklasse aanwezig zijn in de kindklasse. Door velden met dezelfde naam bij de erfgenaam aan te geven, introduceren we verwarring.
Waarschuwing N4
void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
if ((imageDirection / 8) && (imageDirection / 8) != 3)
{
....
}
....
}
Laten we dat eens van dichterbij bekijken. Uitdrukking afbeeldingRichting/8 zal vals zijn als afbeeldingRichting ligt in het bereik van -7 tot 7. Tweede deel: (imageDirection / 8) != 3 cheques afbeeldingRichting omdat ze buiten het bereik vallen: respectievelijk van -31 tot -24 en van 24 tot 31. Het lijkt mij nogal vreemd om op deze manier getallen te controleren op opname in een bepaald bereik en zelfs als er geen fout in dit stukje code zit, zou ik aanraden deze voorwaarden te herschrijven om explicieter te zijn. Dit zou het leven veel gemakkelijker maken voor de mensen die deze code zouden lezen en onderhouden.
Waarschuwing 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;
....
}
....
}
Dit codefragment is hoogstwaarschijnlijk verkregen door decompilatie. Vervolgens werd, afgaande op de achtergelaten opmerking, een deel van de niet-werkende code verwijderd. Er resten echter nog een aantal operaties cursorId, wat ook niet veel zin heeft.
Waarschuwing 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); // <=
}
....
}
Deze code is vrij eenvoudig te corrigeren; u hoeft hem alleen maar een derde keer te controleren speler naar een null-aanwijzer, of voeg deze toe aan de hoofdtekst van de voorwaardelijke instructie. Ik zou de tweede optie voorstellen:
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);
}
}
....
}
Waarschuwing 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));
....
}
....
}
U kunt in één klap een moeilijk leesbare regel code verwijderen en het probleem oplossen met het controleren op nulptr. Ik stel voor om de code als volgt te wijzigen:
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);
....
}
....
}
Waarschuwing N8
void CustomListView::MouseUp(....)
{
....
if (!ColumnHeaderPressedCurrentState)
{
ColumnHeaderPressed = std::nullopt;
ColumnHeaderPressedCurrentState = false;
Invalidate();
}
}
De code ziet er nogal vreemd uit. Het lijkt mij dat er een typefout is gemaakt in de voorwaarde of bij het opnieuw toewijzen van de variabele ColumnHeaderPressedCurrentState betekenis vals.
Uitgang
Zoals we kunnen zien, is het vrij eenvoudig om de statische analysator van PVS-Studio in uw TeamCity-project te integreren. Om dit te doen, volstaat het om slechts één klein configuratiebestand te schrijven. Door de code te controleren, kunt u problemen onmiddellijk na de montage identificeren, waardoor u ze kunt elimineren wanneer de complexiteit en de kosten van wijzigingen nog laag zijn.
Als u dit artikel met een Engelssprekend publiek wilt delen, gebruik dan de vertaallink: Vladislav Stolyarov.
Bron: www.habr.com