2016年のC#プロジェクトの上位10個のバグ

アナライザーの品質を評価し、静的分析の手法を普及させるために、オープンソースプロジェクトのエラーを定期的にチェックし、それに関する記事を作成します。 過去の2016年も例外ではありませんでした。これは、C#アナライザーの一種の「成長」の時代であったことも注目に値します。 PVS-Studioは、多数の新しいC#診断、仮想値を操作するための改良されたメカニズム(シンボリック実行)などを受け取りました。 チームの作業の結果に基づいて、2016年のC#プロジェクトで見つかった最も興味深いエラーの一種のヒットパレードをまとめました。



10位:分が常に60秒ではない場合



Orchard CMSプロジェクトの確認中に見つかったエラーでヒットパレードを開始します。 エラーの説明は記事にあります。 一般に、プロジェクトの検証に関するすべての記事はこちらにあります



TimeSpanのV3118秒コンポーネントが使用されますが、これは完全な時間間隔を表していません。 代わりに「TotalSeconds」値が意図されていた可能性があります。 AssetUploader.cs 182



void IBackgroundTask.Sweep() { .... // Don't flood the database with progress updates; // Limit it to every 5 seconds. if ((_clock.UtcNow - lastUpdateUtc).Seconds >= 5) { .... } }
      
      





TotalSecondsの代わりに、この場合、開発者は誤ってSecondsを使用しました。 したがって、プログラマーが計算したように、日付_clock.UtcNowlastUpdateUtcの間の合計秒数ではなく、範囲の残りの値のみが取得されます。 たとえば、範囲値が1分4秒の場合、結果は64ではなく4秒になります。 信じられないほど、経験豊富な開発者でさえそのような間違いを犯します。



9位:式は常に真



次のエラーは、GitExtensionsプロジェクトのチェックに関する記事にあります。



V3022式 'string.IsNullOrEmpty(rev1)|| string.IsNullOrEmpty(rev2) 'は常に真です。 GitUI FormFormatPatch.cs 155



 string rev1 = ""; string rev2 = ""; var revisions = RevisionGrid.GetSelectedRevisions(); if (revisions.Count > 0) { rev1 = ....; rev2 = ....; .... } else if (string.IsNullOrEmpty(rev1) || string.IsNullOrEmpty(rev2)) // <= { MessageBox.Show(....); return; }
      
      





elseキーワードに注意してください。 おそらく彼はここにまったく場所がありません。 リファクタリング中またはプログラマーの平凡な疲労中の不注意。ここでは、プログラムのロジックに根本的な変化が生じ、予測不可能な動作につながります。 静的アナライザーが決して疲れないのは良いことです。



8位:誤字の可能性



FlashDevelopのソースコード検証の記事には、興味深いタイプミスがあります。



V3056 「a1」アイテムの使用の正確さを検討することを検討してください。 LzmaEncoder.cs 225



 public void SetPrices(....) { UInt32 a0 = _choice.GetPrice0(); UInt32 a1 = _choice.GetPrice1(); UInt32 b0 = a1 + _choice2.GetPrice0(); // <= UInt32 b1 = a1 + _choice2.GetPrice1(); .... }
      
      





アナライザーと記事の著者に同意します。 変数a1の代わりに、 a0を使用すると、マークされた行でそれ自体が示唆されます。 いずれにせよ、変数にわかりやすい名前を付けても害はありません。



7位:論理エラー



Umbracoプロジェクトの再検討に基づいて、 記事も執筆されました。 私の意見では、この記事の興味深いエラーの例です。



V3022式 'name!= "Min" || name!= "Max" 'は常に真です。 ここでは、おそらく「&&」演算子を使用する必要があります。 DynamicPublishedContentList.cs 415



 private object Aggregate(....) { .... if (name != "Min" || name != "Max") { throw new ArgumentException( "Can only use aggregate min or max methods on properties which are datetime"); } .... }
      
      





name変数の値については、 ArgumentException型の例外がスローされます。 そしてすべては、条件で||演算子を誤って使用したためです。 &&の代わりに。



6位:ループを終了するための誤った条件



Accord.Netプロジェクトのレビュー記事には、いくつかの興味深いバグが含まれています。 私は2つを選択しましたが、そのうち1つはタイプミスに関連しています。



V3015 「for」演算子内で間違った変数が比較されている可能性があります。 'i' Accord.Audio SampleConverter.cs 611の検討を検討してください。



 public static void Convert(float[][] from, short[][] to) { for (int i = 0; i < from.Length; i++) for (int j = 0; i < from[0].Length; j++) to[i][j] = (short)(from[i][j] * (32767f)); }
      
      





エラーは、カウンターが変数jである2番目のforループの条件に含まれています。 カウンターにフォームijの変数名を使用することは、ある意味では、このジャンルの古典です。 残念ながら、これらの変数の記述は非常に似ており、開発者はしばしばこのコードにタイプミスをします。 この場合、より意味のある名前の使用を推奨する価値はないと思います。 とにかく、誰もこれをしません:)。 したがって、別の推奨事項を示します:静的アナライザーを使用してください!









5位:ブール値の代わりにビット演算子を使用する



Accord.Netプロジェクトのチェックに関する記事からの別の興味深いかなり一般的な間違い。



V3093 「&」演算子は両方のオペランドを評価します。 おそらく、代わりに短絡「&&」演算子を使用する必要があります。 Accord.Math JaggedSingularValueDecompositionF.cs 461



 public JaggedSingularValueDecompositionF(....) { .... if ((k < nct) & (s[k] != 0.0)) .... }
      
      





明らかに、最初の条件が満たされない場合でも、 &&の代わりに演算子を誤って使用すると、2番目の条件が検証され、配列を超えることになります。



4位:1回引用、2回引用



4番目は、Xamarin.Formsプロジェクトのチェックに関する記事のエラーです。



V3038 'Replace'関数の最初の引数は2番目の引数と同じです。 ICSharpCode.Decompiler ReflectionDisassembler.cs 349



 void WriteSecurityDeclarationArgument(CustomAttributeNamedArgument na) { .... output.Write("string('{0}')", NRefactory.CSharp .TextWriterTokenWriter .ConvertString( (string)na.Argument.Value).Replace("'", "\'")); .... }
      
      





この場合、引用は...に置き換えられます。 これがまさに開発者が求めていたとは思いません。









そしてアナライザー-よくやった!



3位:ThreadStatic



記事が書かれている検証であるMonoプロジェクトは、興味深いエラーが豊富にあることが判明しました。 そしてそのうちの一人は本当に珍しいゲストです。



V3089 [ThreadStatic]属性でマークされたフィールドの初期化子は、最初にアクセスするスレッドで1回呼び出されます。 このフィールドには、異なるスレッドのデフォルト値があります。 System.Data.Linq-net_4_x Profiler.cs 16



 static class Profiler { [ThreadStatic] private static Stopwatch timer = new Stopwatch(); .... }
      
      





つまり、 ThreadStatic属性でマークされたフィールドの不正な初期化が実行されます。 診断のドキュメントには、状況の詳細な説明と、そのようなエラーを回避する方法に関するアドバイスが記載されています。 従来の方法で見つけて修正するのはそれほど簡単ではない間違いの素晴らしい例です。



2位:コピーペースト、リファレンス!



私の意見では、標準の1つは、すでに説明したMonoプロジェクトのチェックに関する記事に Copy-Pasteのようなエラーの例が含まれています。



V3012 「?:」演算子は、その条件式に関係なく、常に同じ値Color.FromArgb(150、179、225)を返します。 ProfessionalColorTable.cs 258



エラーが見つかった短いコードを次に示します。



 button_pressed_highlight = use_system_colors ? Color.FromArgb (150, 179, 225) : Color.FromArgb (150, 179, 225);
      
      





あなたは尋ねます:「それは何ですか?」ヒットパレードの2位にそのような明らかな間違いを置く価値がありましたか? 実際には、上記のコードの断片は、明確にするためにさらにフォーマットされています。 ここで、準備を整えて、ツールを使用せずにコード内で同様のエラーを見つけるタスクに直面していることを想像してください。 そのため、心の弱い人のために、次のスクリーンショットは、エラーのある完全なコードフラグメントを含むものです。









明らかに、プログラマは資格に関係なく、このような間違いを犯す可能性があります。 このようなエラーの検索が成功すれば、静的分析の力がすべて発揮されます。



1位:PVS-Studio



はい、そうは思いませんでした。 本当に「PVS-Studio」と書かれています。 そして、彼はチャートの最初の場所にいます。 それは、優れた静的アナライザーであるためだけではありません。 また、私たちのチームでは、コードに普通の人為的ミスを犯す普通の人々が働いているためです。 記事が一度書かれたのこれについてでした。 エラー、またはPVS-Studioを使用してPVS-Studioコードで発見された2つだけ。



V3022式 'RowsCount> 100000'は常にfalseです。 ProcessingEngine.cs 559



V3022式 'RowsCount> 200000'は常にfalseです。 ProcessingEngine.cs 561



 public void ProcessFiles(....) { .... int RowsCount = DynamicErrorListControl.Instance.Plog.NumberOfRows; if (RowsCount > 20000) DatatableUpdateInterval = 30000; //30s else if (RowsCount > 100000) DatatableUpdateInterval = 60000; //1min else if (RowsCount > 200000) DatatableUpdateInterval = 120000; //2min .... }
      
      





このコードフラグメントの結果( RowsCount> 20000の場合 )は、常に30000のDatatableUpdateInterval値になります。



幸いなことに、私たちはすでにこの方向でいくつかの作業を行っています。









私たちのチームではインクリメンタル分析が広く使用されているため、今後PVS-Studioを使用してPVS-Studioでエラーを検出することに関する記事が登場することはほとんどありません。



おわりに



PVS-Studio静的アナライザーを無料で使用して自分のプロジェクトをチェックすることで、発見したエラーのヒットチャートを作成できるようになりました。



PVS-Studioをダウンロードして試してください: http : //www.viva64.com/en/pvs-studio/



商用ライセンスの取得に関する質問については、メールでお問い合わせください。 デモバージョンの制限を削除する場合は、PVS-Studioの包括的な研究の一時的なライセンスを取得するために私たちに書き込むこともできます。







この記事を英語圏の聴衆と共有したい場合は、翻訳へのリンクを使用してください:Sergey Khrenov。 2016年に見つかった上位10個のC#プロジェクトエラー



記事を読んで質問がありますか?
多くの場合、記事には同じ質問が寄せられます。 ここで回答を収集しました: PVS-Studioバージョン2015に関する記事の読者からの質問への回答 。 リストをご覧ください。



All Articles