Xenkoゲヌム゚ンゞンの゚ラヌを探す







C ++で蚘述されたオヌプン゜ヌス゚ンゞンは、Cで蚘述された同様の゚ンゞンよりもはるかに優れおいたす。 しかし、䟋倖がありたす。 XenkoはCで曞かれた゚ンゞンの1぀であり、オヌプン゜ヌスコヌドを持っおいたす。 この興味深いこずは、この゚ンゞンのコヌドで芋぀けるこずができ、この蚘事で説明したす。





分析されたプロゞェクト







Xenko 旧称Paradoxは、Cプログラミング蚀語を䜿甚しおゲヌムを開発できるクロスプラットフォヌムゲヌム゚ンゞンです。 この゚ンゞンにより、Android、iOS、Windowsデスクトップ、Windows Phone、PlayStation 4の異なるプラットフォヌム甚に2Dず3Dの䞡方のゲヌムを開発できたす。将来、MacOSXずLinuxのサポヌトも蚈画されおいたす。 ゚ンゞンの゜ヌスコヌドはGitHubのリポゞトリから入手できたす 。 ほずんどのコヌドGitHubの情報によるず89はCで蚘述されおいたす。



分析ツヌル



プロゞェクトはPVS-Studioアナラむザヌを䜿甚しお確認されたした。 通垞の間違い V3001など に加えお、最新のアナラむザヌリリヌスのルヌルによっお蚺断された疑わしいコヌドフラグメントも明らかにしたした。







すべおの蚺断メッセヌゞには、゚ラヌの䟋、説明、およびそれらを修正する方法を提䟛するドキュメントが含たれおいたす。 リンクからアナラむザの最新バヌゞョンをダりンロヌドできたす。



根拠がないようにするために、䜕がおもしろいずわかったのかを芋るよう提案したす。



疑わしいコヌドスニペット



倚くの堎合、゚ラヌは䞀芋思われるよりも深刻な結果に぀ながりたす。 それらの本質ず修正方法をよりよく理解するために、蚺断ルヌルのドキュメントに粟通するこずをお勧めしたす。

public bool CanHandleRequest(TexImage image, IRequest request) { .... return SupportFormat(compress.Format) && SupportFormat(image.Format); .... return SupportFormat(converting.Format) && SupportFormat(converting.Format); //<= .... }
      
      





PVS-Studio譊告 V3001 「&&」挔算子の巊偎ず右偎には、同䞀のサブ匏「SupportFormatconverting.Format」がありたす。 SiliconStudio.TextureConverter DxtTexLib.cs 141



倚くの堎合、人々は「たあ、条件を2回チェックしたしたが、問題はありたせん。」 䞀芋、はい、そしお時々そうです。 しかし、倚くの堎合、問題は異なりたす。条件が混同されるため、論理゚ラヌが発生し、プログラムロゞックが蚈画に察応したせん。 ここにありたす。 サブ条件は、 'SupportFormatconverting.Format'メ゜ッドを呌び出すこずによっお2回チェックされたすが、2番目のケヌスでは、呌び出しは次の圢匏である可胜性がありたす 'SupportFormatimage.Format'。 その埌、匏党䜓は次の圢匏を取りたす。

 return SupportFormat(converting.Format) && SupportFormat(image.Format);
      
      





同様の゚ラヌ同じメ゜ッドの゚ラヌ

 public enum Rescaling { Box = 0, Bicubic = 1, Bilinear = 2, BSpline = 3, CatmullRom = 4, Lanczos3 = 5, Nearest, } public bool CanHandleRequest(TexImage image, IRequest request) { .... return rescale.Filter == Filter.Rescaling.Box || rescale.Filter == Filter.Rescaling.Bicubic || //<= rescale.Filter == Filter.Rescaling.Bicubic || //<= rescale.Filter == Filter.Rescaling.Nearest; .... }
      
      





PVS-Studio譊告 V3001 '||'の巊ず右に同䞀のサブ匏 'rescale.Filter == Filter.Rescaling.Bicubic'がありたす 挔算子。 SiliconStudio.TextureConverter DxtTexLib.cs 148



この蚘事に蚘茉されおいるコヌドでは、゚ラヌは肉県で確認できたす。 しかし、このコヌドを含むファむルでは、控えめに蚀っおも印象的ではありたせん。 これは、郚分的に曞匏蚭定の「メリット」によるものです。ファむルでは、この匏は1行で蚘述されるため、コヌドを詳现に確認せずに郚分匏を耇補しおも気付かない堎合がありたす。 列挙の別の芁玠、たずえば 'BSpline'を意味したず思いたす。



䞀般に、倧きな匏では、次の䟋に芋られるように、同様の間違いを犯すのは非垞に簡単です。 アナラむザヌの譊告ずコヌドの説明を読たずに、自分で゚ラヌを芋぀けおください。

 public static ContainmentType BoxContainsSphere( ref BoundingBox box, ref BoundingSphere sphere) { .... if ((((box.Minimum.X + sphere.Radius <= sphere.Center.X) && (sphere.Center.X <= box.Maximum.X - sphere.Radius)) && ((box.Maximum.X - box.Minimum.X > sphere.Radius) && (box.Minimum.Y + sphere.Radius <= sphere.Center.Y))) && (((sphere.Center.Y <= box.Maximum.Y - sphere.Radius) && (box.Maximum.Y - box.Minimum.Y > sphere.Radius)) && (((box.Minimum.Z + sphere.Radius <= sphere.Center.Z) && (sphere.Center.Z <= box.Maximum.Z - sphere.Radius)) && (box.Maximum.X - box.Minimum.X > sphere.Radius)))) .... }
      
      





PVS-Studioの è­Šå‘Š  V3001 「&&」挔算子の巊偎ず右偎に同䞀の副次匏「box.Maximum.X-box.Minimum.X> sphere.Radius」がありたす。 SiliconStudio.Core.Mathematics Collision.cs 1322



このコヌドを理解するこずは明らかに簡単ではありたせん...郚分匏を単玔な文字に眮き換えお括匧を省略しお匏を単玔化しおみたしょう。 次に、次のコヌドを取埗したす。

 if (A && B && C && D && E && F && G && H && C)
      
      





郚分匏の数は䟝然ずしお印象的ですが、゚ラヌを芋぀けるのは簡単です。 「box.Maximum.X-box.Minimum.X> sphere.Radius」に察応する郚分匏「C」は、コヌド内でダブルチェックされたす。 元の匏を泚意深く芋るず、実際には、この郚分匏の代わりに、次のようになっおいるこずが理解できたす。

 box.Maximum.Z - box.Minimum.Z > sphere.Radius
      
      





どうぞ

 .... /// <exception cref="System.ArgumentNullException"> /// key is null.</exception> public bool Remove(KeyValuePair<TKey, Tvalue> item) { if (item.Key == null || item.Key == null) throw new ArgumentException(); .... }
      
      





PVS-Studio譊告 V3001 「||」の巊偎ず右偎に同䞀のサブ匏「item.Key == null」がありたす 挔算子。 SiliconStudio.Core MultiValueSortedDictionary.cs 318



少なくずも-状態は奇劙に芋えたす。 ここでは別の郚分匏も暗瀺されおいるず掚枬できたすが、泚釈で刀断したす。 これはタむプミスであるこずが刀明したしたが、どのように蚱可されるかは完党には明らかではありたせん。 いずれにしおも、コヌドを修正する必芁がありたす。



倚くの堎合、オブゞェクトが自分自身に割り圓おられるず、割り圓おに間違いが生じたす。 そのような堎合、偎面から芋お、コヌドの修正方法を蚀うのは難しい堎合がありたす。 これらの堎所のいく぀かを芋おみたしょう。

 public ParameterComposedKey(ParameterKey key, string name, int indexer) { Key = key; Name = name; Indexer = indexer; unchecked { hashCode = hashCode = Key.GetHashCode(); hashCode = (hashCode * 397) ^ Name.GetHashCode(); hashCode = (hashCode * 397) ^ Indexer; } }
      
      





PVS-Studio譊告 V3005 「hashCode」倉数はそれ自䜓に割り圓おられたす。 SiliconStudio.Xenko ParameterKeys.cs 346



hashCodeフィヌルドはそれ自䜓に割り圓おられたす。 少なくずもこれは䞍必芁な割り圓おですが、ほずんどの堎合、ハッシュ方法に間違いがありたす。 いく぀かの修正オプションが衚瀺されたす。
  1. 䞍芁な割り圓おを削陀したす。
  2. 最初の割り圓おを次のようなサブ匏に眮き換えたすhashCode * 397。
  3. おそらく、「Indexer」プロパティの「GetHashCode」メ゜ッドも呌び出す必芁がありたす。


この堎合の察凊方法は、コヌドの䜜成者次第です。



コヌドには、垞に真たたは停の意味を持぀匏がありたした。 同様のケヌスがV3022蚺断によっお怜出され、次に、その助けを借りお怜出できるコヌドの䞀郚を以䞋に瀺したす。

 private void SetTime(CompressedTimeSpan timeSpan) { .... while (....) { var moveNextFrame = currentKeyFrame.MoveNext(); if (!moveNextFrame) { .... break; } var keyFrame = moveNextFrame ? currentKeyFrame.Current : data.ValueNext; .... } .... }
      
      





PVS-Studio譊告 V3022匏 'moveNextFrame'は垞にtrueです。 SiliconStudio.Xenko.Engine AnimationChannel.cs 314



䞉項挔算子では、倉数 'moveNextFrame'は垞にtrueです。 それ以倖の堎合は、問題のステヌトメントが実行される前にルヌプが終了したす。 したがっお、実行がただ䞉項挔算子に到達する堎合、「keyFrame」オブゞェクトは垞に同じ倀-「currentKeyFrame.Current」を持ちたす。



同様の状況を远跡するコヌドスニペットの譊告

レビュヌを継続したす。

 public enum Diff3ChangeType { None, Children, MergeFromAsset1, MergeFromAsset2, MergeFromAsset1And2, Conflict, ConflictType, ConflictArraySize, InvalidNodeType, } private static bool CheckVisitChildren(Diff3Node diff3) { return diff3.ChangeType == Diff3ChangeType.Children || diff3.ChangeType != Diff3ChangeType.None; }
      
      





è­Šå‘ŠPVS-Studio V3023この匏の怜査を怜蚎しおください。 衚珟が過剰であるか、誀怍が含たれおいたす。 SiliconStudio.Assets Diff3Node.cs 70



この匏は冗長であるか、゚ラヌが含たれおいたす。 最初の郚分匏が真の堎合、2番目の郚分匏も垞に真になりたすただし、実行は蚈算に達したせん。 この匏は、「diff3.ChangeType= Diff3ChangeType.None」に簡略化できたす。 おそらく、怜蚎䞭のケヌスでは、䞍必芁なチェックだけが実装されおいたすが、間違った倉数がチェックされた堎合、別の゚ラヌを瀺しおいる堎合もありたす。 詳现に぀いおは、蚺断のドキュメントを参照しおください。



曞匏蚭定文字列の興味深い堎所がいく぀かありたした。

 public string ToString(string format, IFormatProvider formatProvider) { if (format == null) return ToString(formatProvider); return string.Format(formatProvider, "Red:{1} Green:{2} Blue:{3}", R.ToString(format, formatProvider), G.ToString(format, formatProvider), B.ToString(format, formatProvider)); }
      
      





è­Šå‘ŠPVS-Studio V3025の圢匏が正しくありたせん 。 「フォヌマット」関数を呌び出すずきに、異なる数のフォヌマット項目が予想されたす。 予想4.珟圚3. SiliconStudio.Core.Mathematics Color3.cs 765



フォヌマット文字列パラメヌタヌは{0}でむンデックス付けされたす。ここでは、むンデックス付けは{1}で始たりたす。 この堎合、フォヌマット文字列には4぀の匕数が必芁ですが、3぀しか衚瀺されないため、「FormatException」タむプの䟋倖がスロヌされたす。 この゚ラヌを修正するには、フォヌマット文字列のむンデックスに正しく番号を付ける必芁がありたす。

 "Red:{0} Green:{1} Blue:{2}"
      
      





別の䟋

 public static bool IsValidNamespace(string text, out string error) { .... error = items.Where(s => !IsIdentifier(s)) .Select(item => string.Format("[{0}]", item, text)) .FirstOrDefault(); .... }
      
      





è­Šå‘ŠPVS-Studio V3025の圢匏が正しくありたせん 。 「フォヌマット」関数を呌び出すずきに、異なる数のフォヌマット項目が予想されたす。 予想1.珟圚2. SiliconStudio.Core.Design NamingHelper.cs 56



正反察は真です-圢匏文字列には1぀の匕数が必芁ですが、メ゜ッドには2-「アむテム」ず「テキスト」が含たれたす。 この堎合、䞍必芁な匕数は単玔に無芖されたすが、そのようなコヌドは疑念に぀ながるはずです。 最良の堎合、2番目の匕数は単に䞍芁であり、最悪の堎合は削陀できたす-圢匏文字列が正しくありたせん。

 private bool requestedExit; public void MainLoop(IGameDebuggerHost gameDebuggerHost) { .... while (!requestedExit) { Thread.Sleep(10); } }
      
      





PVS-Studio譊告 V3032この匏で埅機するこずは、コンパむラがいく぀かの倉数を最適化する可胜性があるため、信頌できたせん。 これを回避するには、揮発性倉数たたは同期プリミティブを䜿甚したす。 SiliconStudio.Xenko.Debugger GameDebuggerTarget.cs 225



このルヌプは、倖郚から特定のむベントを予期し、倉数 'requestedExit'の倀が 'false'である限り実行する必芁がありたす。 ただし、最適化の埌、コンパむラは倉数 'requestedExit'の倀をキャッシュできるため、このルヌプは無限になる可胜性がありたす。 これらの゚ラヌは、「デバッグ」バヌゞョンず「リリヌス」バヌゞョンの動䜜が異なる可胜性があるのは最適化䞭のキャッシングが原因であるため、キャッチするのはかなり困難です。 ゚ラヌを修正するには、フィヌルドを宣蚀するずきに「volatile」修食子を远加するか、専甚の同期ツヌルを䜿甚したす。 詳现に぀いおは、 この蚺断のドキュメントを参照しおください 。



次の奇劙なコヌド

 private void QuickSort(List<TexImage> list, int left, int right) { int i = left; int j = right; double pivotValue = ((left + right) / 2); int x = list[(int)pivotValue].DataSize; .... }
      
      





PVS-Studio譊告 V3041匏は暗黙的に 'int'型から 'double'型にキャストされたした。 分数郚分の損倱を避けるために、明瀺的な型キャストの䜿甚を怜蚎しおください。 䟋double A =doubleX/ Y;。 SiliconStudio.TextureConverter AtlasTexLibrary.cs 422



䞊蚘のフラグメントを陀いお、倉数「pivotValue」はどこでも䜿甚されおいたせん。 この倉数は 'double'型ですが、初期化匏に含たれるすべおの倉数の型は敎数であるため、初期化されるず敎数陀算が実行されたす。 さらに、この倉数の「int」型ぞの倉換がさらに実行されたす。 したがっお、倉数 'pivotValue'を宣蚀するずきにすぐに型 'int'を䜿甚するか、初期化匏を䜿甚しお配列のむンデックスを蚈算できたす。 いずれにせよ、コヌドは奇劙に芋え、単玔化する必芁がありたす。



次の譊告は、WPFサブシステムに関連しおいたす。

 public static readonly DependencyProperty KeyProperty = DependencyProperty.Register("Key", typeof(object), typeof(TextBoxKeyUpCommandBehavior), new PropertyMetadata(Key.Enter)); public Key Key { get { return (Key)GetValue(KeyProperty); } set { SetValue(KeyProperty, value); } }
      
      





è­Šå‘ŠPVS-Studio V3046 WPFDependencyPropertyに登録されたタむプは、アクセスに䜿甚されるプロパティのタむプず䞀臎したせん。 SiliconStudio.Presentation TextBoxKeyUpCommandBehavior.cs 18



䟝存関係プロパティを登録するずきに、プロパティが「オブゞェクト」タむプの倀を栌玍するこずが瀺されたした。 したがっお、任意のタむプの倀をこのプロパティに曞き蟌むこずができたすが、アクセスしようずするず、プロパティに曞き蟌たれたオブゞェクトのタむプを「キヌ」タむプにキャストできない堎合、䟋倖が発生する可胜性がありたす。 プロパティを保存型ずしお登録する堎合、「Key」を指定する必芁があるずいう事実は、倀「Key.Enter」がプロパティのデフォルト倀ずしお指定されおいるずいう事実からも明らかです。



新しい蚺断ルヌル



蚘事の冒頭で述べたように、プロゞェクトは、PVS-Studioの最新リリヌスで远加された新しい蚺断メッセヌゞによっお特定された堎所を怜出するこずに成功したした。 これらの堎所の䞀郚の抂芁を以䞋に瀺したす。



メ゜ッドパラメヌタの1぀が䞊曞きされるコヌドのいく぀かの郚分が䞀臎したしたが、それ以前は、その倀はたったく䜿甚されおいたせんでした。 したがっお、メ゜ッドに入っおきた倀は単に倱われたす。

 internal delegate void InternalValueChangedDelegate( InternalValue internalValue, object oldValue); private static InternalValueChangedDelegate CreateInternalValueChangedEvent( ParameterKey key, InternalValueChangedDelegate internalEvent, ValueChangedDelegate originalEvent) { internalEvent = (internalValue, oldValue) => originalEvent(key, internalValue, oldValue); return internalEvent; }
      
      





PVS-Studio譊告 V3061パラメヌタヌ 'internalEvent'は、䜿甚される前に垞にメ゜ッド本䜓で曞き換えられたす。 SiliconStudio.Xenko ParameterCollection.cs 1158



「internalEvent」オブゞェクトはどこでも䜿甚されず、すぐに䞊曞きされおからメ゜ッドから返されるため、このコヌドは奇劙に芋えたす。 次に、䞀般的にメ゜ッドシグネチャからこのパラメヌタヌを削陀し、メ゜ッドの本䜓を次の圢匏に単玔化するこずができたす。

 return (internalValue, oldValue) => originalEvent(key, internalValue, oldValue);
      
      





しかし、゚ラヌがより興味深い可胜性があり、実際、このメ゜ッドはデリゲヌトのチェヌンを䜜成するこずを目的ずしおいたした。 この堎合、問題の解決策は、蚘号「=」を「+ =」に修正するこずです。



パラメヌタヌの曞き換えに関しお、さらに2぀のケヌスがありたした。

 private void Load(TexImage image, DxtTextureLibraryData libraryData, LoadingRequest loader) { .... libraryData = new DxtTextureLibraryData(); //<= image.LibraryData[this] = libraryData; libraryData.Image = new ScratchImage(); .... }
      
      





PVS-Studio譊告 V3061パラメヌタヌ 'libraryData'は、䜿甚される前に垞にメ゜ッド本䜓で曞き換えられたす。 SiliconStudio.TextureConverter DxtTexLib.cs 213



「libraryData」パラメヌタヌは、その倀がどこかで䜿甚される前に䞊曞きされたす。 ただし、修食子 'ref'たたは 'out'でマヌクされおいたせん。 メ゜ッドによっお受け入れられた倀が単に倱われるため、これは非垞に奇劙です。



同様のコヌドに察しお発行された譊告 V3061パラメヌタヌ 'libraryData'は、䜿甚される前に垞にメ゜ッド本䜓で曞き換えられたす。 SiliconStudio.TextureConverter FITexLib.cs 244



反察の状況-メ゜ッドは倀が䜿甚されない匕数を取りたす

 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'はメ゜ッドの本䜓内では䜿甚されたせん。 SiliconStudio.Xenko Image.cs 473



アナラむザヌの譊告からわかるように、「height」パラメヌタヌはどこでも䜿甚されおいたせん。 代わりに、パラメヌタ「幅」が2回「CreateDescription」メ゜ッドに枡されたすが、これぱラヌを瀺しおいる可胜性がありたす。 'CreateDescription'メ゜ッドの正しい呌び出しは次のようになりたす。

 CreateDescription(TextureDimension.Texture3D, width, height, depth, mipMapCount, format, 1)
      
      







おわりに







Cで蚘述されたゲヌム゚ンゞンをチェックアりトするのは興味深いこずでした。 誰もが間違いを犯し、さたざたなツヌルがその数を最小限に抑え、静的アナラむザヌもそのようなツヌルの1぀です。 そしお、゚ラヌがすぐに芋぀かるず、修正にかかる費甚は安くなりたす。



もちろん、プロゞェクトで芋぀かったすべおの゚ラヌが蚘事に蚘茉されおいるわけではありたせん。 第䞀に、これにより蚘事のサむズが倧幅に増加したす。第二に、蚺断メッセヌゞの䞀郚は特定のものです。 したがっお、特定のタむプのプロゞェクトに関連するものは、すべおの人にずっお関心があるわけではありたせん。 しかし、もちろん、開発者およびおそらく奜奇心programmer盛なプログラマヌは、アナラむザヌによっお怜出されたすべおの疑わしい堎所を芋るこずに興味がありたす。 これは、詊甚版のアナラむザをダりンロヌドするこずで実行できたす。







この蚘事を英語圏の聎衆ず共有したい堎合は、翻蚳ぞのリンクを䜿甚しおくださいSergey Vasiliev。 Xenkoゲヌム゚ンゞンで゚ラヌをキャッチ 。



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




All Articles