Hur statisk kodanalys hjälper i GameDev-industrin

( 4 dec 2020)

Spelindustrin utvecklas ständigt och utvecklas snabbare än en snabbkula. Tillsammans med branschens tillväxt ökar också komplexiteten i utvecklingen: kodbasen blir större och antalet buggar växer också. Därför måste moderna spelprojekt ägna särskild uppmärksamhet åt kodkvaliteten. Idag kommer vi att täcka ett av sätten att göra din kod mer anständig, vilket är statisk analys, samt hur PVS-Studio i praktiken hjälper till med att utveckla spelprojekt i olika storlekar.

“Det viktigaste jag har gjort som programmerare de senaste åren är att aggressivt bedriva analys av statisk kod. Ännu mer värdefullt än de hundratals allvarliga buggar jag har förhindrat med det är tankesättet om hur jag ser programvarans tillförlitlighet och kodkvalitet. ”- John Carmack

Vi har arbetat med stora spelutvecklare i många år och under den här tiden lyckades vi göra många intressanta och användbara saker för spelindustrin. Det är inte mycket överraskande med tanke på listan över våra kunder från spelbranschen. Vi stöder aktivt våra kunder: att integrera PVS-Studio i deras egen utvecklingsprocess, fixa fel som analysatorn har hittat, och till och med göra specialanpassade funktioner.

Dessutom gör vi en hel del oberoende utveckling av analysatorn i GameDev-riktningen, samt främja PVS-Studio och berätta för människor om intressanta fel som de har hittat i olika videospel.

Visst, vi har några intressanta historier att berätta. Den här artikeln kommer att täcka flera sådana fall.

PVS-Studio and Unity

Ett av sätten vi marknadsför vår produkt är genom att skriva artiklar om att kontrollera öppna projekt. Alla har nytta av dessa artiklar: en läsare får chansen att kolla in några ovanliga fel i ett välbekant projekt och lära sig något nytt. När det gäller PVS-Studio-teamet får vi möjlighet att visa arbetet med verklig kod, så att projektutvecklare kan lära sig om fel och fixa dem i förväg.

Vår första stora bekantskap med Unity ägde rum. 2016, när utvecklarna av den här spelmotorn öppnade källkoden för flera komponenter, bibliotek och demos i deras officiella arkiv. Inte konstigt, vi kunde inte passera ett sådant lockande fall och ville skriva en artikel om att kontrollera den postade koden.

Sedan fick vi reda på att Unity3D-koden (vid den tiden kallades motorn så) var av mycket hög kvalitet. Men ändå kunde vi hitta en hel del allvarliga fel i den. Det fanns tillräckligt med dem för att skriva en artikel .

Två år senare hände en annan sak – enhetsutvecklare öppnade motorns kod och själva redaktören. Och precis som förra gången kunde vi inte ta del av det och kontrollerade motorns källkod. Och det var inte för ingenting – vi hittade också ett gäng med fängslande brister.

Samtidigt går våra avsikter långt utöver att bara skriva artiklar. Vi fortsätter att arbeta med PVS-Studio, och GameDev är ett av de viktigaste områdena för vår utveckling. Därför vill vi att Unity-spelutvecklare ska kunna få bästa möjliga analys av sina projekt.

Ett av stegen för att förbättra kvaliteten på Unity-projektanalysen var att skriva anteckningar för metoder som definierats i Unity Scripting API .

Metodanteckningar är en speciell mekanism som används i PVS-Studio. Det tillåter en användare att förse analysatorn med all nödvändig information om en viss metod. Den är skriven i specialkod av analysatorutvecklarna själva (dvs. av oss).

Denna information kan vara av helt olika slag. Till exempel: hur metoden kan påverka parametrarna som skickas till den, om den kan allokera minne och om den returnerar ett värde som måste hanteras. Annotering gör det således möjligt för analysatorn att bättre förstå metodiken och göra det möjligt att upptäcka nya och mer komplexa fel.

Vi har redan skrivit ett stort antal olika anteckningar (till exempel för metoder från systemet namespace), och vi lade gärna till metodkommentarer från Unity Scripting API till dem.

Vi började utvidga listan med anteckningar med en bedömning. Hur många metoder finns det totalt? Vilka bör antecknas först? Det fanns många metoder totalt, så vi bestämde oss för att börja med att kommentera de mest använda metoderna.

Så här letade vi efter populära metoder: först samlade vi en pool av projekt från GitHub som använder Unity-funktioner och sedan använde vi ett självskrivet verktyg (baserat på Roslyn) för att beräkna samtal till de metoder vi var intresserade av. Som ett resultat fick vi en lista över klasser vars metoder oftast användes:

  • UnityEngine.Vector3
  • UnityEngine.Mathf
  • UnityEngine.Debug
  • UnityEngine.GameObject
  • UnityEngine.Material
  • UnityEditor.EditorGUILayout
  • UnityEngine.Component
  • UnityEngine.Object
  • UnityEngine.GUILayout
  • UnityEngine.Quaternion

Därefter förblev det att kommentera metoderna för dessa klasser. Vi skapade ett testprojekt och grävde i dokumentationen för att få så mycket information om dessa metoder som möjligt. Till exempel försökte vi skicka null som olika argument för att se hur programmet skulle fungera.

Under sådana kontroller upptäckte vi då och då lite intressant odokumenterad information. Vi hittade till och med ett par anmärkningsvärda buggar i motorn. När vi till exempel kör följande kod:

MeshRenderer renderer = cube.GetComponent();
Material m = renderer.material;
List<int> outNames = null;
m.GetTexturePropertyNameIDs(outNames);

själv kraschar Unity-redigeraren (åtminstone i version 2019.3.10f1). Naturligtvis är det osannolikt att någon kommer att skriva sådan kod. Det faktum att Unity-redigeraren kan krascha genom att köra ett sådant manus är fortfarande nyfiken.

Så vi hade skrivit anteckningarna. Efter att ha kört analysen hittade vi omedelbart nya utlösningar. Analysatorn upptäckte till exempel ett konstigt samtal till metoden GetComponent :

void OnEnable()
{
GameObject uiManager = GameObject.Find("UIRoot"); if (uiManager)
{
uiManager.GetComponent();
}
}

Analysatorvarning: V3010 Returvärdet för funktionen GetComponent krävs för att användas. – YTTERLIGARE I LÖPANDE UIEditorWindow.cs 22

Metoden GetComponent innebär att ett visst värde returneras till och med på grund av till dess namn. Det är logiskt att anta att detta värde ska användas på något sätt. Tack vare den nya anteckningen vet analysatorn att ett sådant ”obevakat” samtal till den här metoden kan indikera ett logiskt fel och varnar för det.

Detta är inte den enda varningen som uppträdde i uppsättningen av vår testa projekt efter att ha lagt till nya kommentarer. Jag kommer inte att citera resten för att inte göra den här artikeln för stor. Huvudsaken är att utvecklingen av Unity-projekt med PVS-Studio nu låter dig skriva mycket säkrare och renare kod utan buggar.

Om du vill läsa mer om vårt arbete med kommentarer för Unity-metoder, här är artikeln: Hur PVS-Studio-analysatorn började hitta ännu fler fel i Unity-projekt .

Unreal Engine 4

När, tillbaka 2014, utvecklarna av Unreal Motor 4 öppnade källkoden för motorn, vi kunde helt enkelt inte komma förbi det projektet och skrev också en artikel om det. Motorutvecklarna gillade artikeln och fixade de fel vi hittade. Men detta räckte inte för oss och vi bestämde oss för att försöka sälja licensen för vår analysator till Epic Games.

Epic Games var intresserade av att förbättra sin motor med PVS-Studio, så vi kom överens om följande : vi fixar Unreal Engine-koden på egen hand så att analysatorn inte ger några varningar och killar från Epic Games köper vår licens och belönar oss dessutom för det utförda arbetet.

Varför alla varningar måste vara fast? Faktum är att man kan få maximal nytta av statisk analys genom att korrigera fel direkt när de visas . När du kontrollerar ditt projekt för första gången får du vanligtvis flera hundra (och ibland tusentals) varningar. Bland alla dessa analysatorutlösare är det lätt att förlora varningar som utfärdats för nyskriven kod.

Vid en första anblick kan detta problem lösas ganska enkelt: du behöver bara sitta ner och gå igenom hela rapporten , gradvis korrigera fel. Men även om denna metod är mer intuitiv kan det ta tid. Det är mycket bekvämare och snabbare att använda undertryckningsfiler.

Undertrycksfiler är en specialfunktion i PVS-Studio som gör att du kan dölja analysatorvarningar i en speciell fil. Dolda varningar visas dock inte i efterföljande loggar: du kan visa dem separat.

Efter att ha haft många utlösningar efter den första kontrollen kan du lägga till alla upptäckta varningar i undertryckningsfilen med ett par klick och du får en ren logg utan en enda post efter nästa kontroll.

Nu när de gamla varningarna inte längre ingår i loggen kan du enkelt upptäcka en ny varning omedelbart när den visas. Här är åtgärdens ordning: skriv koden -> kontrollera den med analysatorn -> upptäck en ny varning -> åtgärda felet. Så här kommer du att få ut mesta möjliga av att använda analysatorn.

Glöm inte varningarna i undertryckningsfilen samtidigt: de kan fortfarande innehålla varningar om större fel och sårbarheter, precis som tidigare. Därför bör man återgå till dessa varningar och minska antalet regelbundet.

Inga tvivel, detta scenario är bekvämt, men utvecklare från Epic Games ville att deras kod skulle fixas direkt, så de passerade uppgift för oss.

Och vi började jobba. Efter att ha kontrollerat projektkoden hittade vi 1821 varningar för Level_1 och Level_2. Att analysera en så stor mängd varningar kräver seriöst arbete, och för att underlätta hela processen har vi ställt in kontinuerlig kodanalys på vår CI-server.

Det såg ut så här: varje natt på vår server, den nuvarande version av Unreal Engine 4 byggdes och omedelbart efter byggandet startades analysen automatiskt. Således, när våra killar kom till jobbet på morgonen, hade de alltid en ny rapport från analysatorn, som hjälpte dem att spåra utvecklingen av att eliminera varningar. Dessutom tillät detta system oss att kontrollera byggstabiliteten när som helst genom att köra den på servern manuellt.

Hela processen tog oss 17 arbetsdagar. Schemat för att åtgärda fel var som följer:

I själva verket återspeglar detta schema inte vårt arbete. Efter att vi fixat alla varningar väntade vi ytterligare två dagar på att de skulle acceptera våra senaste dragförfrågningar. Hela den här tiden kontrollerades den senaste versionen av Unreal Engine automatiskt, som i sin tur fortsatte att uppdateras med ny kod. Så vad tror du hände? Under de två dagarna hittade PVS-Studio ytterligare fyra fel i koden! En av dem var avgörande och kan potentiellt leda till odefinierat beteende.

Naturligtvis fixade vi också dessa fel. Vid den tidpunkten hade utvecklare av Unreal Engine bara en sak kvar: ställa in automatisk analys på sin egen plats, precis som vi har gjort. Från det ögonblicket började de se varningar varje dag som utfärdades för den kod de just hade skrivit. Detta gjorde det möjligt för dem att fixa fel i koden precis när de uppträdde – i de tidigaste utvecklingsstadierna .

Du kan läsa mer om hur vi arbetade med Unreal Engine-koden i officiell Unreal Engine-blogg eller på vår webbplats .

Analys av olika spel

Nämnde jag att vi kolla olika öppna projekt och skriva artiklar om dem? Så vi har nu en hel del liknande artiklar om spelprojekt! Vi skrev om spel som VVVVVV , Space Engineers , Kommando & Conque r, osu! och till och med (en mycket tidig artikel) Doom 3 . Vi har också sammanställt topp 10 av mest intressanta programvarufel från videospelsindustrin.

Så vi kollade förmodligen det mesta av välkända öppen källkodsmotorer. Förutom Unity och Unreal Engine 4, projekt som Godot , Bullet , Amazon Lumberyard , Cry Engine V och många andra har kommit under vår syn.

Det bästa med allt detta är att många av de buggar som vi beskrev fixades senare av projektutvecklarna själva. Det är trevligt att känna att verktyget du utvecklar ger verkliga, synliga och påtagliga fördelar för världen.

Du kan visa en lista över alla våra artiklar relaterade till videospelutveckling på ett eller annat sätt på en specialsida i vår blogg.

Slutsats

Vid denna punkt slutar min artikel. Jag önskar dig ren och korrekt fungerande kod utan fel och fel!

Intresserad av ämnet statisk analys? Vill du kontrollera ditt projekt för fel? Försök med PVS-Studio .

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *