ビデオゲヌム業界の静的分析゜フトりェア゚ラヌのトップ10











ビデオゲヌム業界で゜フトりェアを開発しおいお、補品の品質を改善するために他に䜕ができるのか、開発プロセスを簡玠化するために、静的分析を䜿甚しないのではないかず考えおいる堎合は、始めたしょう。 疑う さお、私はあなたにこれを玍埗させようずしたす。 ビデオゲヌム業界のデベロッパヌが犯しおいる間違いに泚目したい堎合は、再び、あなたはそのアドレスに来たした-最も興味深いものがあなたのために特別に遞ばれたした。



静的解析を䜿甚する理由



ビデオゲヌムの開発には倚数の段階が含たれるずいう事実にもかかわらず、プログラミングは䟝然ずしお䞻芁な段階の1぀です。 たずえ䜕千行ものコヌドを曞かなくおも、さたざたなツヌルを䜿甚する必芁がありたす。その品質は䜿いやすさず最終結果に䟝存したす。 あなたがそのようなツヌルたずえば、ゲヌム゚ンゞンの開発者であれば、すべおがすでに明確になっおいるはずです。



静的解析が゜フトりェア開発党般に圹立぀のはなぜですか



䞻な理由はいく぀かありたす。





ずにかく、これはすべお理論であり、おそらくより実甚的な䟋に興味があるでしょう。 さお、それらを以䞋に瀺したす。



Unreal Engineの静的解析













ここたで読んだこずがあるなら、アンリアル゚ンゞンずは䜕か、゚ピックゲヌムズずはどんな䌚瀟なのかを䌝えおはいけたせん。もしこれらの人たちがあなたの暩限を楜しんでいないなら、それを䜿っおいる私に手玙を曞いおください。



PVS-Studioチヌムは、Epic Gamesチヌムず数回協力し、Unreal Engineプロゞェクトで静的解析を実装および䜿甚し、アナラむザヌによっお怜出された゚ラヌ/誀怜知を修正するのを支揎したした。 双方にずっお興味深い、そしお有益な経隓だったず確信しおいたす。



結果の1぀は、Unreal Engineに特別なフラグが远加されたこずで、静的解析をUnreal Engineプロゞェクトアセンブリシステムに簡単に統合できるようになりたした。



鍵ずなるアむデアはシンプルです-人々はコヌドの品質を気にし、これに異なるアプロヌチを䜿甚したす。その1぀は静的分析の導入でした。



静的解析に関するゞョン・カヌマック













ビデオゲヌム業界で最も有名な開発者の1人であるゞョンカヌマックは、プログラマヌずしおの䞻な業瞟の1぀ずしお、静的解析手法の積極的な䜿甚をか぀お認識しおいたした。分析。 「あなたが知っおいる誰かが静的分析は初心者のためのツヌルであるず次回蚀ったずき、圌にこの匕甚を芋せおください。 カヌマックは、 察応する蚘事で静的分析の知識を説明したした。これを読むこずを匷くお勧めしたす動機ず䞀般的な開発の䞡方に぀いお。



ゲヌムおよびゲヌム゚ンゞンで静的分析を䜿甚しお怜出された゚ラヌ













おそらく、静的分析の利点を瀺す最良の方法の1぀は、その機胜を実際に瀺すこずです。 たずえば、PVS-Studioチヌムはこれを行い、オヌプン゜ヌスプロゞェクトをチェックしたす。



誰にずっおもメリット





䞀般的に-有効性ず利益の蚌拠ではないものは䜕ですか



静的解析をすでに䜿甚しおいるコマンド













誰かが開発プロセスに静的分析を導入するかどうかを考えおいる間、䞀郚のチヌムはすでにそれを䜿甚しおおり、利益を埗おいたす たずえば、Rocksteady、Epic Games、ZeniMax Media、Oculus、Codemasters、Wargamingなど ゜ヌス 。



ビデオゲヌム業界のトップ10コヌドのバグ



これはある皮のメガグロヌバルな「トップ」ではなく、ゲヌムやゲヌム゚ンゞンでPVS-Studioアナラむザヌによっお怜出された゚ラヌであり、私にずっお最も興味深いず思われるこずをすぐに蚀及する䟡倀がありたす。



い぀ものように、興味を匕くために、たず䞊蚘のコヌドフラグメントの゚ラヌを自分で芋぀けおから、アナラむザヌの譊告ず問題の説明を読むこずをお勧めしたす。



10䜍



出兞 X-Ray Engineの異垞を探す















第10䜍は、STALKERゲヌムで䜿甚されおいるX-Ray Engineゲヌム゚ンゞンの゚ラヌですこのシリヌズのゲヌムをプレむした人は、ゲヌムプロセス䞭に発生した倚くの面癜いそうではないバグを芚えおいるでしょう。 これは特にSTALKERClear Skyに圓おはたりたす。ClearSkyは、パッチなしではプレむできたせんでした私はすべおのセヌブを「殺した」バグを今でも芚えおいたす。 ゲヌム゚ンゞンの分析が瀺したように、コヌドには本圓にバグがあり、倚くのバグがありたす。 以䞋はその1぀です。



BOOL CActor::net_Spawn(CSE_Abstract* DC) { .... m_States.empty(); .... }
      
      





PVS-Studioè­Šå‘Š  V530関数 'empty'の戻り倀を䜿甚する必芁がありたす。



問題は簡単です-返されたbooleanメ゜ッドemptyを䜿甚せず、コンテナが空かどうかを瀺したす。 䞊蚘の匏にはメ゜ッド呌び出し以倖に䜕も存圚しないずいう事実から刀断するず、開発者はコンテナヌをクリアしたかったのに、clearではなく空のメ゜ッドを呌び出しお間違えたず想定できたす。



これは、トップ10にずっおは単玔すぎる間違いだず誰かが蚀うかもしれたせん。 しかし、これは圌女の魅力です そのため、偎面から芋るず、゚ラヌは非垞に単玔で明癜であるように芋えたすが、このような「単玔な」゚ラヌはさたざたなプロゞェクトで発生するおよび怜出されるこずはありたせん。



9䜍



出兞 埅望のCryEngine Vテスト



ゲヌム゚ンゞンの゚ラヌのトピックを匕き続き明らかにしたす。 9䜍はCryEngine Vのコヌドです。この゚ンゞンのゲヌムでは、X-Ray゚ンゞンのゲヌムほど倚くのバグに気付きたせんでしたが、「剖怜」により、゚ンゞンに倚くの䞍審なコヌドフラグメントが含たれおいるこずがわかりたした。



 void CCryDXGLDeviceContext:: OMGetBlendState(...., FLOAT BlendFactor[4], ....) { CCryDXGLBlendState::ToInterface(ppBlendState, m_spBlendState); if ((*ppBlendState) != NULL) (*ppBlendState)->AddRef(); BlendFactor[0] = m_auBlendFactor[0]; BlendFactor[1] = m_auBlendFactor[1]; BlendFactor[2] = m_auBlendFactor[2]; BlendFactor[2] = m_auBlendFactor[3]; *pSampleMask = m_uSampleMask; }
      
      





PVS-Studioè­Šå‘Š  V519 「BlendFactor [2]」倉数には、連続しお2回倀が割り圓おられたす。 おそらくこれは間違いです。



私たちの蚘事で繰り返し蚀及されおいるように、タむプミスから免れる人はいたせん。 実際には、静的解析がコピヌペヌストおよびタむプミスを怜出する優れた仕事をするこずも繰り返し確認されおいたす。 m_auBlendFactor配列からBlendFactorに倀をコピヌしたしたが、誀っおそれらを封印し、 BlendFactorを 2回曞き蟌みたした[2] 。 この混乱のため、 m_auBlendFactor [3 ]の倀はBlendFactor [2]に曞き蟌たれ、倀はBlendFactor [3]で倉曎されたせん。



8䜍



゜ヌス 宇宙のナニコヌン「スペヌス゚ンゞニア」の゜ヌスコヌドの確認



コヌスを少し倉曎し、C ++からCに移行したす。 これは、スペヌス゚ンゞニアプロゞェクトのコヌドです。これは、スペヌス構造の構築ず維持に関するサンドボックスゲヌムです。 私自身はゲヌムをプレむしたせんでしたが、蚘事の解説者の䞀人が蚀ったように、「 私は結果にあたり驚いおいたせん:) 」。 さお、私は本圓に面癜い゚ラヌを芋぀けるこずができたした。以䞋はそのうちの2぀です。



 public void Init(string cueName) { .... if (m_arcade.Hash == MyStringHash.NullOrEmpty && m_realistic.Hash == MyStringHash.NullOrEmpty) MySandboxGame.Log.WriteLine(string.Format( "Could not find any sound for '{0}'", cueName)); else { if (m_arcade.IsNull) string.Format( "Could not find arcade sound for '{0}'", cueName); if (m_realistic.IsNull) string.Format( "Could not find realistic sound for '{0}'", cueName); } }
      
      





PVS-Studioの譊告 

ご芧のずおり、メ゜ッドの戻り倀を無芖する際の゚ラヌは、C ++コヌドだけでなく、Cでも芋぀かりたす。 String.Formatメ゜ッドは、フォヌマット文字列ずフォヌマットするオブゞェクトに基づいお結果の文字列を構成し、結果をメ゜ッドの戻り倀ずしお返したす。 䞊蚘のコヌドでは、 elseブランチにstring.Formatの 2぀の呌び出しがありたすが、それらの戻り倀は䜿甚されたせん。 ほずんどの堎合 、 MySandboxGame.Log.WriteLineメ゜ッドを䜿甚するifステヌトメントのthen-ブランチで行われた方法ず同様に、これらのメッセヌゞを誓玄する必芁がありたした。



7䜍



出兞 Quake III Arena GPL Design Review



静的分析はタむプミスをうたく怜出するこずを述べたしたか 以䞋の䟋は、これの別の確認です。



 void Terrain_AddMovePoint(....) { .... x = ( v[ 0 ] - p->origin[ 0 ] ) / p->scale_x; y = ( v[ 1 ] - p->origin[ 1 ] ) / p->scale_x; .... }
      
      





PVS-Studioè­Šå‘Š  V537 「scale_x」アむテムの䜿甚の正確さを確認するこずを怜蚎しおください。



倉数xずyに曞き蟌みたすが、䞡方の割り圓おで匏p-> scale_xが倀を蚈算する匏で䜿甚されたす。 それは非垞に疑わしく芋え、2番目のケヌスでは、匏p-> scale_xをp-> scale_yに眮き換える必芁があるようです 。



6䜍



゜ヌス Unity C゜ヌスコヌドの確認



Unity Technologiesは最近、独自のゲヌム゚ンゞンであるUnityの゜ヌスコヌドを公開したした。 私たちはそのようなむベントを通り抜けるこずができず、分析䞭に倚くの興味深い堎所を芋぀けたした。 以䞋はその1぀です。



 public override bool IsValid() { .... return base.IsValid() && (pageSize >= 1 || pageSize <= 1000) && totalFilters <= 10; }
      
      





PVS-Studioè­Šå‘Š  V3063評䟡される堎合、条件匏の䞀郚は垞にtrueですpageSize <= 1000。



pageSizeの無効な範囲チェックがありたす。 ほずんどの堎合、 pageSizeの倀が[1;の範囲内にあるこずを確認する予定でした。 1000]。 しかし、残念なタむプミスが行われたした。挔算子 '&&'の代わりに、プログラマヌが誀っお '||'を曞きたした。 郚分匏は実際には䜕もチェックしたせん。



5䜍



゜ヌス Unity3Dオヌプンコンポヌネントの゚ラヌの分析



隣接する堎所には、Unity3Dコンポヌネントの興味深いバグがありたす。 ゜ヌス蚘事は、Unity゚ンゞンの゜ヌスコヌドが開かれる1幎以䞊前に曞かれたした。 それでも、それでも面癜いものを芋぀けるこずができたした。



 public static CrawledMemorySnapshot Unpack(....) { .... var result = new CrawledMemorySnapshot { .... staticFields = packedSnapshot.typeDescriptions .Where(t => t.staticFieldBytes != null & t.staticFieldBytes.Length > 0) .Select(t => UnpackStaticFields(t)) .ToArray() .... }; .... }
      
      





PVS-Studioè­Šå‘Š  V3080 null参照解陀の可胜性がありたす。 「t.staticFieldBytes」の怜査を怜蚎しおください。



Whereメ゜ッドに匕数ずしお枡されたラムダ匏に泚目しおください。 コヌドから刀断するず、 typeDescriptionsコレクションには、 staticFieldBytesメンバヌがnullになる可胜性のある芁玠が含たれる堎合がありたす 。 そのため、 Lengthプロパティにアクセスする前に、 staticFieldBytes= Nullを確認したす。 挔算子は混乱しおいるだけで、「&&」の代わりに「」が䜿甚されおいたす。 これは、巊の匏の評䟡結果 true \ false に関係なく、右の匏も評䟡されるこずを意味したす。そのため、 staticFieldBytes == nullの堎合、 LengthプロパティにアクセスするずきにNullReferenceException型の䟋倖がスロヌされたす。 「&&」を䜿甚する堎合、 staticFieldBytes == nullの堎合、匏の右偎は評䟡されないため、このような状況は発生したせん。



Unityがトップ10に2床ランクむンした唯䞀の゚ンゞンであるずいう事実にもかかわらず、これはマニアが玠晎らしいゲヌムを䜜成するのを止めたせん。 含む-「バグ」ずの戊いに぀いお。











4䜍



゜ヌス Godot゚ンゞンの゜ヌスコヌド分析



欠萜しおいるキヌワヌドに関連する興味深い゚ラヌがある堎合がありたす。 䟋䟋倖オブゞェクトは䜜成されたすが、開発者がthrowキヌワヌドの指定を忘れおいるため、いかなる方法でも䜿甚されたせん。 このような゚ラヌは、CプロゞェクトおよびC ++プロゞェクトで発生し たす 。 欠萜しおいるキヌワヌドは、Godot Engineゲヌム゚ンゞンでも芋぀かりたした。



 Variant Variant::get(const Variant& p_index, bool *r_valid) const { .... if (ie.type == InputEvent::ACTION) { if (str =="action") { valid=true; return ie.action.action; } else if (str == "pressed") { valid=true; ie.action.pressed; } } .... }
      
      





PVS-Studioの è­Šå‘Š  V607所有者なしの衚珟「ie.action.pressed」。



䞊蚘のコヌドスニペットでは、 ie.typeずstrの倀に応じお、 Variant型の特定の倀を返したいこずがわかり たす 。 䞀床だけ、リタヌン匏は正垞に蚘述されたした-return ie.action.action; 、 returnステヌトメントを忘れた2回目のため、目的の倀は返されず、メ゜ッドは匕き続き実行されたす。



3䜍



゜ヌス PVS-StudioDoom 3コヌドの分析



それで、「トップ3」に到達したした。 クロヌムを閉じるこずは、Doom 3ゲヌムの゜ヌスコヌドの小さな断片です。䞊で述べたように、゚ラヌは暪から芋るず単玔に芋え、そのような間違いをどのように行うかが明確ではないずいう事実は、䜕も意味したせん-実際には、どのタむプの゚ラヌが発生しないでしょうか...



 void Sys_GetCurrentMemoryStatus( sysMemoryStats_t &stats ) { .... memset( &statex, sizeof( statex ), 0 ); .... }
      
      





PVS-Studioè­Šå‘Š  V575 「memset」関数は「0」芁玠を凊理したす。 3番目の匕数を調べたす。



問題をよりよく理解するには、 memset関数のシグネチャを思い出す䟡倀がありたす。



 void* memset(void* dest, int ch, size_t count);
      
      





関数のシグネチャずその呌び出しを比范するず、最埌の2぀の匕数が混同されおいるこずがわかりたす。 その結果、リセットが必芁な䞀郚のメモリブロックは倉曎されたせん。



2䜍



2䜍は、Xenkoゲヌム゚ンゞンのCコヌドで芋぀かった゚ラヌです。



出兞 Xenkoゲヌム゚ンゞンの゚ラヌを探しおいたす



 private static ImageDescription CreateDescription(TextureDimension dimension, int width, int height, int depth, ....) { .... } public static Image New3D(int width, int height, int depth, ....) { return new Image(CreateDescription(TextureDimension.Texture3D, width, width, depth, mipMapCount, format, 1), dataPointer, 0, null, false); }
      
      





PVS-Studioè­Šå‘Š  V3065パラメヌタヌ 'height'はメ゜ッドの本䜓内では䜿甚されたせん。



CreateDescriptionメ゜ッドに匕数を枡すこずで゚ラヌが発生したした。 そのシグネチャを芋るず、2番目、3番目、4番目のパラメヌタヌがそれぞれwidth 、 height 、 depthず呌ばれおいるこずがわかりたす。 呌び出されるず、匕数width 、 width、およびdepthが枡されたす。 疑わしい そのため、アナラむザヌは、この堎所が譊告を発するほど疑わしいず刀断したした。



䞀䜍



出兞 埅望のアンリアル゚ンゞン4怜蚌



Unreal Engineゲヌム゚ンゞンからの今日の「トップ10」゚ラヌを芋出したす。 「 2017幎のC ++プロゞェクトのトップ10゚ラヌ 」の蚘事の堎合のように、以䞋の゚ラヌを芋たずき、最も興味深い゚ラヌのリストを導くのはだれかをすぐに理解したした。



 bool VertInfluencedByActiveBone( FParticleEmitterInstance* Owner, USkeletalMeshComponent* InSkelMeshComponent, int32 InVertexIndex, int32* OutBoneIndex = NULL); void UParticleModuleLocationSkelVertSurface::Spawn(....) { .... int32 BoneIndex1, BoneIndex2, BoneIndex3; BoneIndex1 = BoneIndex2 = BoneIndex3 = INDEX_NONE; if(!VertInfluencedByActiveBone( Owner, SourceComponent, VertIndex[0], &BoneIndex1) && !VertInfluencedByActiveBone( Owner, SourceComponent, VertIndex[1], &BoneIndex2) && !VertInfluencedByActiveBone( Owner, SourceComponent, VertIndex[2]) &BoneIndex3) { .... }
      
      





PVS-Studioè­Šå‘Š  V564 「」挔算子はブヌル型の倀に適甚されたす。 括匧を含めるのを忘れおいるか、「&&」挔算子を䜿甚するこずを意図しおいる可胜性がありたす。



アナラむザヌの譊告ず䞊蚘のコヌドを比范しお、「ここで「&&」の代わりに「」を䜿甚するのはどこですか」 ただし、 VertInfluencedByActiveBone関数の最埌のパラメヌタヌにデフォルト倀があり、 ifステヌトメントの条件匏を簡玠化するこずに泚意を払うず、すべおがより明確になりたす。



 if (!foo(....) && !foo(....) && !foo(....) & arg)
      
      





最埌の郚分匏に特に泚意しおください。



 !VertInfluencedByActiveBone(Owner, SourceComponent, VertIndex[2]) &BoneIndex3
      
      





デフォルト倀を持぀パラメヌタヌはトリックを挔じたした-デフォルト倀がない堎合、このコヌドはコンパむルされたせん。 しかし、そうであるため、すべおが正垞にコンパむルされ、゚ラヌも同様に正垞にマスクされたす。 これは疑わしい堎所であり、アナラむザヌは気付きたした-䞭眮挔算 ''。巊オペランドはbool型で、右オペランドはint32です。



おわりに













静的解析がゲヌムやゲヌム゚ンゞンの開発に圹立぀こず、そしおコヌドおよび結果ずしお最終補品の品質を改善するずいう質問に察するもう1぀の答えであるこずを瀺すこずができたず思いたす。 ビデオゲヌム業界で開発しおいる堎合は、静的分析に぀いお同僚に䌝え、この蚘事を衚瀺するだけです。 どこから始めるべきか考えおいたすか PVS-Studioから始めたす。











この蚘事を英語圏の聎衆ず共有したい堎合は、翻蚳ぞのリンクを䜿甚しおくださいセルゲむノァシリ゚フ。 ビデオゲヌム開発の静的分析゜フトりェアバグのトップ10



蚘事を読んで質問がありたすか
倚くの堎合、蚘事には同じ質問が寄せられたす。 ここで回答を収集したした PVS-Studioバヌゞョン2015に関する蚘事の読者からの質問ぞの回答 。 リストをご芧ください。



All Articles