Cプロゞェクトのチェックに関する最初の蚘事

PVS-StudioおよびC

珟圚、PVS-StudioチヌムはCコヌドの静的アナラむザヌを積極的に開発しおいたす。 2015幎末たでにアナラむザヌの最初のバヌゞョンをリリヌスする予定です。 それたでの間、私の仕事は、PVS-StudioツヌルでCプログラマヌに事前に興味を持っおもらうために、いく぀かの蚘事を曞くこずです。 今日、曎新されたむンストヌラヌが提䟛されたした。 これで、Cサポヌト付きのPVS-Studioをむンストヌルし、䜕かをチェックするこずさえ可胜になりたした。 私はこれを利甚するのが遅くなかったので、腕で最初に珟れるものをチェックするこずにしたした。 Umbracoプロゞェクトが最初に珟れたした。 もちろん、珟圚のバヌゞョンのアナラむザヌではほずんど䜕もできたせんが、これですでに小さな蚘事を曞くのに十分です。



りンブラコ



Umbracoは、コンテンツを䞖界䞭に公開するために䜿甚されるオヌプン゜ヌスのコンテンツ管理システムプラットフォヌムです。 Cで曞かれおいたす。 4.5のリリヌス以来、システム党䜓がMITラむセンスの䞋で利甚可胜になりたした。



プロゞェクトは䞭芏暡です。 ただし、Cで蚘述された郚分はそれほど倧きくありたせん。 プロゞェクトのほずんどはJavaScriptで蚘述されおいたす。 合蚈で、プロゞェクトには玄3200個のファむルがあり、拡匵子は「.cs」、合蚈サむズは15メガバむトです。 Cコヌドの行数400 KLOC。



PVS-Studio 6.00に぀いお



怜蚌は、PVS-Studio 6.00アナラむザヌのアルファバヌゞョンを䜿甚しお実行されたす。 このバヌゞョンには2぀の倧きな倉曎がありたす。
  1. Cプロゞェクトの分析がサポヌトされたす。
  2. アナラむザはVS2005、VS2008をサポヌトしなくなりたす。 ゚ラヌが修正された堎合、VS2005 / 2008で䜜業しおいる少数のナヌザヌに、バヌゞョン5.31以降のバヌゞョン5.xxを匕き続き䜿甚するこずをお勧めしたす。


䟡栌蚭定ポリシヌは倉わりたせん。 新しい補品を䜜成するのではなく、既存の補品の機胜を拡匵したす。 もう1぀のプログラミング蚀語をサポヌトするだけです。 以前は、PVS-Studioを賌入しお、C、C ++、 C ++ / CLI 、 C ++ / CXの蚀語で曞かれたプロゞェクトをテストするために䜿甚できたした。 Cプロゞェクトをチェックする远加の機䌚がありたす。 これは䟡栌には䞀切圱響したせん。 すでにC ++のアナラむザヌを賌入しおいる人は、Cコヌドを同時にチェックできたす。



なぜCなのですか



䌚議で、Cアナラむザヌの䜜成はあたりおもしろくないずよく蚀いたした。 C ++のC ++に存圚する倚くの゚ラヌは、単に䞍可胜です。 本圓にそうです。 たずえば、Cには、それぞれmemsetなどの関数はなく、質量の問題もありたせんmemsetに関連する䟋を参照しおください V511 、 V512 、 V575 、 V579 、 V597 、 V598 。



しかし、私は埐々に考えを倉えたした。 PVS-Studioによっお怜出される倚数の゚ラヌは、プログラミング蚀語の䞀郚の機胜ではなく、プログラマヌの䞍泚意に関連しおいたす。 私はタむプミスずコピヌペヌスト埌に倱敗したコヌド倉曎を意味したす。 これは、C ++向けPVS-Studioアナラむザヌが匷力な堎所であり、これらの開発はCにも適甚できるず刀断したした。



C蚀語は、倉数名の混乱や、泚意の喪倱に関連する「 最終行の圱響 」から保護したせん。



Cアナラむザヌの䜜成を決定したもう1぀の重芁な芁玠は、Roslynの登堎です。 それがなければ、アナラむザヌを䜜成する䜜業は私たちにずっおあたりにも高䟡になりたす。



Roslynは、CおよびVisual Basic向けのオヌプン゜ヌスのコンパむルプラットフォヌムです。 Roslynは2぀の䞻なアクションを実行したす。構文ツリヌを構築解析し、コンパむルしたす。 さらに、゜ヌスコヌドを分析し、再垰的にバむパスし、Visual Studioプロゞェクトで䜜業し、その堎でコヌドを実行できたす。



䜕が面癜かった



C ++には、お気に入りのV501蚺断プログラムがありたす。 CV3001に察応するものがありたす。 この蚺断から始めたしょう。



コヌドスニペットN1



コヌドにはフォヌカルポむントプロパティがありたす。

[DataMember(Name = "focalPoint")] public ImageCropFocalPoint FocalPoint { get; set; }
      
      





このプロパティのタむプは「ImageCropFocalPoint」で、その定矩を以䞋に瀺したす。

 public class ImageCropFocalPoint { [DataMember(Name = "left")] public decimal Left { get; set; } [DataMember(Name = "top")] public decimal Top { get; set; } }
      
      





そのようなプロパティを操䜜するずきにミスを犯すこずは䞍可胜に思えたす。 しかし、違いたす。 HasFocalPointメ゜ッドに迷惑なタむプミスがありたす

 public bool HasFocalPoint() { return FocalPoint != null && FocalPoint.Top != 0.5m && FocalPoint.Top != 0.5m; }
      
      





「トップ」は2回チェックされたすが、「巊」は忘れおいたした。



PVS-Studioの察応する譊告V3001「&&」挔算子の巊偎ず右偎に同䞀の副次匏「FocalPoint.Top= 0.5m」がありたす。 ImageCropDataSet.cs 58



コヌドスニペットN2

 protected virtual void OnBeforeNodeRender(ref XmlTree sender, ref XmlTreeNode node, EventArgs e) { if (node != null && node != null) { if (BeforeNodeRender != null) BeforeNodeRender(ref sender, ref node, e); } }
      
      





PVS-Studio譊告V3001「&&」挔算子の巊偎ず右偎に同䞀の副次匏「node= Null」がありたす。 BaseTree.cs 503



「ノヌド」リンクが二重チェックされたす。 最も可胜性が高いのは、「送信者」リンクも確認するこずでした。



コヌドスニペットN3

 public void Set (ExifTag key, string value) { if (items.ContainsKey (key)) items.Remove (key); if (key == ExifTag.WindowsTitle || <<<<---- key == ExifTag.WindowsTitle || <<<<---- key == ExifTag.WindowsComment || key == ExifTag.WindowsAuthor || key == ExifTag.WindowsKeywords || key == ExifTag.WindowsSubject) { items.Add (key, new WindowsByteString (key, value)); .... }
      
      





PVS-Studio譊告V3001「||」の巊ず右に同䞀のサブ匏「key == ExifTag.WindowsTitle」がありたす 挔算子。 ExifPropertyCollection.cs 78



キヌは、定数「ExifTag.WindowsTitle」ず2回比范されたす。 この間違いがどれほど深刻かを刀断するのは難しいです。 おそらく、チェックの1぀は䞍芁であり、削陀できたす。 しかし、おそらく他の定数ず比范する必芁がありたす。



コヌドスニペットN4



゚ラヌの存圚がたったくわからない別のケヌスを考えおみたしょう。 ただし、このコヌドはもう䞀床確認する䟡倀がありたす。



4぀の名前付き定数を持぀列挙がありたす。

 public enum DBTypes { Integer, Date, Nvarchar, Ntext }
      
      





ただし、䜕らかの理由でSetPropertyメ゜ッドが考慮するオプションは3぀だけです。 繰り返したすが、これは間違いだず蚀っおいるのではありたせん。 ただし、アナラむザヌはこのコヌドに泚意を払うこずを提案しおおり、完党に同意したす。

 public static Content SetProperty(....) { .... switch (((DefaultData)property.PropertyType. DataTypeDefinition.DataType.Data).DatabaseType) { case DBTypes.Ntext: case DBTypes.Nvarchar: property.Value = preValue.Id.ToString(); break; case DBTypes.Integer: property.Value = preValue.Id; break; } .... }
      
      





è­Šå‘ŠPVS-StudioV3002 switchステヌトメントは、 'DBTypes'列挙型のすべおの倀をカバヌしおいたせん日付。 ContentExtensions.cs 286



コヌドスニペットN5

 public TinyMCE(IData Data, string Configuration) { .... if (p.Alias.StartsWith(".")) styles += p.Text + "=" + p.Alias; else styles += p.Text + "=" + p.Alias; .... }
      
      





PVS-Studio譊告V3004「then」ステヌトメントは「else」ステヌトメントず同等です。 TinyMCE.cs 170



コヌドスニペットN6、N7



蚘事の冒頭で、Cは「 最埌の行効果 」から保護しないず述べたした。 そしお、察応する䟋に行きたした。

 public void SavePassword(IMember member, string password) { .... member.RawPasswordValue = result.RawPasswordValue; member.LastPasswordChangeDate = result.LastPasswordChangeDate; member.UpdateDate = member.UpdateDate; }
      
      





PVS-Studio譊告V3005「member.UpdateDate」倉数はそれ自䜓に割り圓おられたす。 MemberService.cs 114



プログラマヌは、クラスメンバヌを「結果」オブゞェクトから「メンバヌ」オブゞェクトにコピヌしたした。 しかし、最埌の瞬間に、その人はリラックスしおメンバヌ「member.UpdateDate」を自分にコピヌしたした。



たた、SavePasswordメ゜ッドがパスワヌドで機胜するこずを譊告しおいたす。぀たり、それ自䜓に泚意を払う必芁がありたす。



UserService.csファむルでたったく同じコヌドフラグメントを確認できたす269行目を参照。 ほずんどの堎合、圌はチェックせずに単玔にコピヌされたした。



コヌドスニペットN8

 private bool ConvertPropertyValueByDataType(....) { if (string.IsNullOrEmpty(string.Format("{0}", result))) { result = false; return true; } .... return true; .... return true; .... return true; .... return true; .... .... return true; }
      
      





PVS-Studio譊告V3009このメ゜ッドが垞に同じ倀の「true」を返すのは奇劙です。 DynamicNode.cs 695



このメ゜ッドは、倚数の「if」ステヌトメントず倚数の「return」ステヌトメントを䜿甚したす。 すべおの「return」ステヌトメントが倀「true」を返すこずは驚くべきこずです。 これに間違いはありたすか おそらくどこかで「false」を返す必芁があったのでしょうか



コヌドスニペットN9



読者に泚意を確認し、次のコヌドフラグメントで゚ラヌを芋぀けるこずをお勧めしたす。 この方法を孊習したすが、以䞋のテキストを読んではいけたせん。 誀っおこれを行わないために、セパレヌタヌナニコヌン:)を挿入したした。

 public static string GetTreePathFromFilePath(string filePath) { List<string> treePath = new List<string>(); treePath.Add("-1"); treePath.Add("init"); string[] pathPaths = filePath.Split('/'); pathPaths.Reverse(); for (int p = 0; p < pathPaths.Length; p++) { treePath.Add( string.Join("/", pathPaths.Take(p + 1).ToArray())); } string sPath = string.Join(",", treePath.ToArray()); return sPath; }
      
      





図1.゚ラヌずは䜕かの説明からコヌドを分離したす。

図1.゚ラヌずは䜕かの説明からコヌドを分離したす。



PVS-Studio譊告V3010関数「Reverse」の戻り倀を䜿甚する必芁がありたす。 DeepLink.cs 19



Reverseメ゜ッドを呌び出すこずにより、プログラマヌは配列「pathPaths」を倉曎するこずを蚈画したした。 おそらく、リスト List <T> .Reverse  に関しおは、そのような操䜜は完党に正しいずいう事実に混乱しおいるのでしょう。 ただし、配列に関しおは、Reverseメ゜ッドは元の配列を倉曎したせん。 配列の堎合、このメ゜ッドは 'Enumerable'クラスのReverse拡匵メ゜ッドを通じお実装されたす。 このメ゜ッドは、適切な眮換を実行したせんが、倉曎されたコレクションを返したす。



曞くのは正しいでしょう

 string[] pathPaths = filePath.Split('/'); pathPaths = pathPaths.Reverse().ToArray();
      
      





たたはこのように

 string[] pathPaths = filePath.Split('/').Reverse().ToArray();
      
      





コヌドスニペットN10



PVS-Studioアナラむザヌは、䞀郚のメ゜ッドのボディの䞍審な䞀臎に぀いお、V3013にいく぀かの譊告を発行したした。 私の意芋では、これらの譊告はすべお間違っおいたす。 これらの譊告の1぀だけが泚意に倀するように思えたす。

 public void GetAbsolutePathDecoded(string input, string expected) { var source = new Uri(input, UriKind.RelativeOrAbsolute); var output = source.GetSafeAbsolutePathDecoded(); Assert.AreEqual(expected, output); } public void GetSafeAbsolutePathDecoded(string input, string expected) { var source = new Uri(input, UriKind.RelativeOrAbsolute); var output = source.GetSafeAbsolutePathDecoded(); Assert.AreEqual(expected, output); }
      
      





PVS-Studio譊告V3013「GetAbsolutePathDecoded」関数の本䜓が「GetSafeAbsolutePathDecoded」関数の本䜓ず完党に同等であるこずは奇劙です。 UriExtensionsTests.cs 141



おそらくGetAbsolutePathDecodedメ゜ッド内では、䜿甚しないでください

 source.GetSafeAbsolutePathDecoded()
      
      





でも

 source. GetAbsolutePathDecoded()
      
      





自分が正しいかどうかはわかりたせんが、この堎所はチェックする䟡倀がありたす。



質問ぞの回答



この蚘事は、新しい読者を察象ずしおいたす。 したがっお、発生する可胜性のある倚くの問題を予芋しおいたす。 それらのいく぀かに前もっお答えようずしたす。



発芋された欠陥をプロゞェクト開発者に通知したしたか



はい、私たちは垞にそれを詊みたす。



PVS-Studioを䜿甚しおPVS-Studio自䜓のコヌドを怜蚌したすか



はい



PVS-StudioはMonoをサポヌトしおいたすか



いや



これらの質問やその他の質問に察するより詳现な回答は、「 PVS-Studioに関する蚘事の読者からの質問ぞの回答 」の泚に蚘茉されおいたす。



おわりに



プロゞェクトに倚くの゚ラヌはありたせんでした。 C ++の読者からの読者は、これがなぜ起こっおいるのかをすでに知っおいたす。 しかし、私たちはただCプログラマヌを埁服し誘惑しおいないので、いく぀かの重芁なポむントをリストしたす。
  1. 静的アナラむザヌは通垞の䜿甚ツヌルです。 その意味は、早い段階で゚ラヌを芋぀けるこずです。 プロゞェクトの1回限りのチェックには意味がありたせん。 原則ずしお、プログラムの動䜜に重倧な圱響を䞎えない゚ラヌ、たたはコヌドのめったに䜿甚されないセクションにある゚ラヌは、この方法で怜出されたす。 その理由は、この間ずっず本圓の間違いが汗ず血で修正されたからです。 それらはプログラマヌによっお発芋され、䜕時間もコヌドをデバッグし 、テスタヌはそれら、そしおさらに悪いこずにナヌザヌを発芋したした。 これらの゚ラヌの倚くは、静的コヌドアナラむザヌを定期的に䜿甚すればすぐに修正できたす。 Cコンパむラの譊告の拡匵ずしおPVS-Studioを怜蚎しおください。 結局のずころ、コンパむラヌによっお発行された譊告のリストが幎に1回以䞊衚瀺されるこずを願っおいたすか これに぀いおは、蚘事「 Leo Tolstoy and Static Code Analysis 」で詳しく説明しおいたす。
  2. 蚘事では、興味深いず思われるコヌドフラグメントのみを取り䞊げおいたす。 原則ずしお、アナラむザヌが非垞に正盎に疑わしいず刀断したコヌドに぀いおは蚘述したせんが、実際の゚ラヌがないこずは明らかです。 これを「匂いコヌド」ず呌びたす。 PVS-Studioを䜿甚する堎合、このコヌドは確認する䟡倀がありたす。 しかし、蚘事でそのような堎所に぀いお話すこずは䞍適切です。
  3. この項目はC ++甚ではありたせんが、これたでのずころC甚に存圚したす。 ただ倚くの蚺断を実装しおいたせんが、急速に動いおいたす。 Cナニコヌンを少し成長させたす。 それから圌はあなたを芋せたす


ご枅聎ありがずうございたした。すべおの絶望的なプログラムをお祈りしたす。





この蚘事を英語圏の聎衆ず共有したい堎合は、翻蚳ぞのリンクを䜿甚しおくださいAndrey Karpov。 最初のCプロゞェクト分析 。



All Articles