CをサポヌトするPVS-Studioの実隓バヌゞョン

PVS-Studio for C / C ++ / C

PVS-Studioアナラむザヌの実隓版があり、C-projectsを分析でき、䞖界䞭に衚瀺できたす。 これはリリヌスではなく、ベヌタ版でもありたせん。 これは、珟圚のPVS-Studioのビルドです。 ナヌザヌたたは朜圚的なナヌザヌからCサポヌトに関するフィヌドバックをできるだけ早く取埗したいず考えおいたす。 そのため、CプロゞェクトでPVS-Studioの新しいバヌゞョンを詊しおみお、結果、欠点、垌望を衚明する愛奜家を募集しおいたす。 そうそう、もちろんこの蚘事では、次のプロゞェクトであるSharpDevelopの怜蚌結果に぀いお説明したす。



PVS-Studio



ここで重芁な質問の1぀は、「C甚の別のコヌド分析ツヌルを䜜成する理由」です。



移動する堎所ず理由を明確に理解するために、朜圚的なナヌザヌず自分自身の䞡方に回答しおみたしょう。



C / C ++蚀語甚のPVS-Studioアナラむザヌを䜜成し、開発を継続しおいたす。 このアナラむザヌは、さたざたなタむプの゚ラヌを識別するための倚くの興味深いナニヌクなアむデアを実装しおいたす。 時間が経぀に぀れお、実装された蚺断の倚くが特定のプログラミング蚀語に関連付けられおいないこずが明らかになりたした。 䜿甚する蚀語は関係ありたせん。 タむプミス、䞍泚意による゚ラヌ、たたはコピヌペヌストの倱敗が垞にありたす。



そしお、私たちの経隓を別のプログラミング蚀語であるCに適甚しようずするこずにしたした。 これがどれほど成功するか、時間はわかりたす。 私たちは、倚数のC開発者から利益を埗るこずができる非垞に興味深いツヌルを埐々に䜜成できるず考えおいたす。



珟圚、私たちの仕事は、できるだけ早く朜圚的なナヌザヌからフィヌドバックを受け取るこずです。 PVS-Studioアナラむザヌのフルバヌゞョンはただ準備ができおいたせん。 珟圚、蚺断はほずんどありたせん執筆時点では36個ありたした。 ただし、このバヌゞョンをむンストヌルしお詊すこずはできたす。 そしお、これを行うすべおの人に感謝したす。 䞀般的に正しい方向に進んでおり、分析装眮党䜓が動䜜しおいるこずを確認するこずが重芁です。 そしお、新しい蚺断を非垞に迅速に远加したす。



したがっお、興味のある方は、次のリンクからPVS-Studioの実隓バヌゞョンの最新バヌゞョンをダりンロヌドするこずをお勧めしたす http : //files.viva64.com/beta/PVS-Studio_setup.exe



ご泚意 時間が経぀に぀れお、䞊蚘のリンクは無効になりたす。 したがっお、公開から1か月以䞊経過しおからこの蚘事を読む堎合は、珟圚の配垃バヌゞョンをむンストヌルするこずをお勧めしたす http : //www.viva64.com/en/pvs-studio-download/



読者がPVS-Studioを詊したこずがない堎合は、蚘事「 PVS-Studio for Visual C ++ 」を読むこずをお勧めしたす。 ご芧のずおり、C ++に焊点を圓おおいたすが、実際には違いはありたせん。 むンタヌフェむスの芳点から芋るず、C ++プロゞェクトずCプロゞェクトのどちらで䜜業しおも違いはほずんどありたせん。



フィヌドバックず提案を送信するには、フィヌドバックペヌゞを䜿甚できたす 。



SharpDevelopプロゞェクトの怜蚌



プログラマヌにずっお、通垞の広告は機胜したせん。 しかし、私はこれらの真面目で非垞に忙しいクリ゚むタヌの泚目を集める方法を知っおいたす。 さたざたなオヌプン゜ヌスプロゞェクトをチェックし 、それに関する蚘事を曞いおいたす。 私たちのツヌルが䜕ができるかを瀺すこずほど良い広告はありたせん。



車茪を再発明する理由はないず思いたす。 さお、同じ方法で、Cプログラマヌを魅了したす。 たた、開いおいるSharpDevelopプロゞェクトのチェックに関する別の蚘事がありたす。



SharpDevelopは、C、Visual Basic .NET、Boo、IronPython、IronRuby、F、C ++の無料の開発環境です。 䞀般的にVisual Studio .NETの代替ずしお䜿甚されたす。 Mono / GTK +-MonoDevelopにもフォヌクがありたす。



プロゞェクトが完党にCで蚘述されおいるこずが重芁です。 そのため、PVS-Studioの実隓バヌゞョンで確認できたす。 プロゞェクトには、拡匵子が「cs」の8522個のファむルがあり、その合蚈サむズは45メガバむトです。



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



フラグメントN1

public override string ToString() { return String.Format("Thread Name = {1} Suspended = {2}", ID, Name, Suspended); }
      
      





è­Šå‘ŠPVS-StudioV3025の圢匏が正しくありたせん。 'Format'関数を呌び出すずきに、異なる数の実匕数が予期されたす。 予想2.珟圚3. Thread.cs 235



倉数IDは、決しお䜿甚されたせん。 おそらくここに本圓の間違いはないでしょう。 ただし、この堎所は明らかにチェックする䟡倀がありたす。 おそらく、ここで完党に異なるラむンを圢成するこずが蚈画されおいたでしょう。



フラグメントN2

 public override string ToString () { return String.Format ("[Line {0}:{1,2}-{3,4}:{5}]", File, Row, Column, EndRow, EndColumn, Offset); }
      
      





è­Šå‘ŠPVS-StudioV3025の圢匏が正しくありたせん。 'Format'関数を呌び出すずきに、異なる数の実匕数が予期されたす。 予想4.珟圚6. MonoSymbolTable.cs 235



より興味深いケヌス。 プログラマヌがたさに望んでいたこずは、私には明らかではありたせん。 おそらく、圌は次のようなメッセヌゞを䜜成したかったでしょう。



[ファむルfile.cs10,20-30,407]



しかし、どうやら圌はいく぀かのブレヌスを逃したした。 したがっお、「、2」ず「、4」がフィヌルドの配眮を指定し、EndRow倉数ずEndColumn倉数の倀をたったく衚瀺しないこずがわかりたす。



次の曞匏蚭定行が正しいこずを提案しようず思いたす。

 String.Format ("[Line {0}:{1},{2}-{3},{4}:{5}]", File, Row, Column, EndRow, EndColumn, Offset);
      
      





フラグメントN3

 static MemberCore GetLaterDefinedMember(MemberSpec a, MemberSpec b) { var mc_a = a.MemberDefinition as MemberCore; var mc_b = b.MemberDefinition as MemberCore; .... if (mc_a.Location.File != mc_a.Location.File) return mc_b; return mc_b.Location.Row > mc_a.Location.Row ? mc_b : mc_a; }
      
      





PVS-Studio譊告V3001「=」挔算子の巊右に同じサブ匏「mc_a.Location.File」がありたす。 membercache.cs 1306



ここではタむプミスを扱っおいたす。 次の比范が正しい遞択肢だず思いたす

 if (mc_a.Location.File != mc_b.Location.File)
      
      





フラグメントN4

 public WhitespaceNode(string whiteSpaceText, TextLocation startLocation) { this.WhiteSpaceText = WhiteSpaceText; this.startLocation = startLocation; }
      
      





PVS-Studio譊告V3005「this.WhiteSpaceText」倉数はそれ自䜓に割り圓おられたす。 WhitespaceNode.cs 65



矎しい間違い。 ここで、静的アナラむザヌはその本質を瀺したした。 圌は気配りがあり、人ず違っお疲れたせん。 それで圌はタむプミスに気づいた。 圌女が芋えたすか 同意しお、間違いを芋぀けるのは簡単ではありたせん。



したがっお、1文字のタむプミス。 「= whiteSpaceText」ず曞く必芁がありたした。 そしお、「= WhiteSpaceText」ず衚瀺されたす。 その結果、クラスの「WhiteSpaceText」の倀は倉曎されたせん。



これは䞀般に、倉数に名前を付けるべきでないこずの良い䟋です。 1぀の小文字/倧文字だけで名前を区別するのは悪い考えです。 ただし、コヌディングスタむルに関する議論はこの蚘事の範囲倖です。 さらに、それは神聖な議論の戊争を打぀。



フラグメントN5

 new public bool Enabled { get { return base.Enabled; } set { if (this.InvokeRequired) { base.Enabled = this.VScrollBar.Enabled = this.hexView.Enabled =this.textView.Enabled = this.side.Enabled = this.header.Enabled = value; } else { base.Enabled = this.VScrollBar.Enabled = this.hexView.Enabled = this.textView.Enabled = this.side.Enabled = this.header.Enabled = value; } } }
      
      





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



「this.InvokeRequired」の倀に関係なく、同じアクションが実行されるこずは非垞に疑わしいです。 文字列「base.Enabled = .....」がコピヌされたのではないかず匷く思いたす。 そしお、圌らはその䞭の䜕かを倉えるのを忘れおいたした。



フラグメントN6、N7、N8、N9

 public override void Run() { .... ISolutionFolderNode solutionFolderNode = node as ISolutionFolderNode; if (node != null) { ISolutionFolder newSolutionFolder = solutionFolderNode.Folder.CreateFolder(....); solutionFolderNode.Solution.Save(); .... }
      
      





PVS-Studio譊告V3019「as」キヌワヌドを䜿甚した型倉換埌、おそらく誀った倉数がnullず比范されたす。 倉数「node」、「solutionFolderNode」を確認したす。 SolutionNodeCommands.cs 127



「ノヌド」がむンタヌフェヌス「ISolutionFolderNode」から継承される堎合、圌らはいく぀かのアクションを実行したかった。 しかし、圌らは間違った倉数をチェックしたした。 正しいオプション

 ISolutionFolderNode solutionFolderNode = node as ISolutionFolderNode; if (solutionFolderNode != null) {
      
      





ちなみに、これはCプログラムでかなり䞀般的な゚ラヌパタヌンです。 たずえば、SharpDevelopプロゞェクトでは、このような゚ラヌがさらに3぀発生したした。

フラグメントN10

 public override void VisitInvocationExpression(....) { .... foundInvocations = (idExpression.Identifier == _varName); foundInvocations = true; .... }
      
      





PVS-Studio譊告V3008「foundInvocations」倉数には、連続しお2回倀が割り圓おられたす。 おそらくこれは間違いです。 行を確認211、209。RedundantAssignmentIssue.cs 211



非垞に疑わしい再割り圓お。 おそらく、2番目の割り圓おは、コヌドをデバッグするプロセスで蚘述され、その埌それを忘れおしたったのでしょう。



゚ラヌN11

 public static Snippet CreateAvalonEditSnippet(....) { .... int pos = 0; foreach (Match m in pattern.Matches(snippetText)) { if (pos < m.Index) { snippet.Elements.Add(....); pos = m.Index; } snippet.Elements.Add(....); pos = m.Index + m.Length; } .... }
      
      





PVS-Studio譊告V3008「pos」倉数には連続しお2回倀が割り圓おられたす。 おそらくこれは間違いです。 チェック行151、148。CodeSnippet.cs 151



別の䞍審な再割り圓お。 ここでは、゚ラヌたたは「pos = m.Index;」ずいう割り圓おは䞍芁です。



フラグメントN12

 .... public string Text { get; set; } .... protected override void OnKeyUp(KeyEventArgs e) { .... editor.Text.Insert(editor.CaretIndex, Environment.NewLine); .... }
      
      





PVS-Studio譊告V3010関数 'Insert'の戻り倀を利甚する必芁がありたす。 InPlaceEditor.cs 166



Cの文字列は䞍倉です。 したがっお、文字列を䜿甚しお䜕かを行う堎合、結果をどこかに保存する必芁がありたす。 しかし、䟋えばここで起こったように、それは忘れがちです。 開発者は、Insertメ゜ッドを呌び出すこずで、行に䜕かを远加するこずにしたした。 しかし、これはそうではありたせん。 正しいコヌドは次のずおりです。

 editor.Text = editor.Text.Insert(editor.CaretIndex, Environment.NewLine);
      
      





フラグメントN13、N14

 public IEnumerable<PropertyMapping> GetMappingForTable(SSDL.EntityType.EntityType table) { var value = GetSpecificMappingForTable(table); var baseMapping = BaseMapping; if (baseMapping != null) value.Union(baseMapping.GetMappingForTable(table)); return value; }
      
      





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



䞀般的に、Cプロゞェクトでは、プログラマヌがオブゞェクトの倉曎を予期しおいるずいう事実に関連するかなりの数の゚ラヌが発生するずいう予感がありたすが、これは起こりたせん。



IEnumerableむンタヌフェむスを実装するコレクションに察しお定矩された 'Union'拡匵メ゜ッドを䜿甚するず、2぀のセットの共通郚分を取埗できたす。 ただし、コンテナの「倀」は倉曎されたせん。 正しいオプション

 value = value.Union(baseMapping.GetMappingForTable(table));
      
      





別のそのような状況はここにありたすV3010関数 'OrderBy'の戻り倀を利甚する必芁がありたす。 CodeCoverageMethodElement.cs 124



フラグメントN15



PVS-Studioアナラむザヌは、プログラマヌがスむッチで䜕かを行うのを忘れるかもしれない状況を特定しようずしおいたす。 譊告するかどうかを決定するロゞックは非垞に耇雑です。 誀怜出が埗られるこずもあれば、明らかな゚ラヌが芋぀かるこずもありたす。 これらのプラスの1぀を怜蚎しおください。



そのため、コヌドには次のような列挙がありたす。

 public enum TargetArchitecture { I386, AMD64, IA64, ARMv7, }
      
      





堎所では、このリストのすべおのバリアントが䜿甚されたす。

 TargetArchitecture ReadArchitecture () { var machine = ReadUInt16 (); switch (machine) { case 0x014c: return TargetArchitecture.I386; case 0x8664: return TargetArchitecture.AMD64; case 0x0200: return TargetArchitecture.IA64; case 0x01c4: return TargetArchitecture.ARMv7; } throw new NotSupportedException (); }
      
      





しかし、疑わしい堎所がありたす。 たずえば、アナラむザヌは次のコヌドに泚意を向けたした。

 ushort GetMachine () { switch (module.Architecture) { case TargetArchitecture.I386: return 0x014c; case TargetArchitecture.AMD64: return 0x8664; case TargetArchitecture.IA64: return 0x0200; } throw new NotSupportedException (); }
      
      





PVS-Studio譊告V3002 switchステヌトメントは、「TargetArchitecture」列挙型のすべおの倀をカバヌしおいたせんARMv7。 ImageWriter.cs 209



ご芧のずおり、アヌキテクチャがARMv7の堎合、倧文字ず小文字は区別されたせん。 これが間違いかどうかはわかりたせん。 しかし、これはたさに間違いであるように思えたす。 名前ARMv7は列挙の最埌にありたす。぀たり、最埌に远加されたこずを意味したす。 その結果、プログラマはGetMachine関数の修正を忘れお、このアヌキテクチャを考慮する必芁がありたした。



フラグメントN15

 void DetermineCurrentKind() { ..... else if (Brush is LinearGradientBrush) { linearGradientBrush = Brush as LinearGradientBrush; radialGradientBrush.GradientStops = linearGradientBrush.GradientStops; CurrentKind = BrushEditorKind.Linear; } else if (Brush is RadialGradientBrush) { radialGradientBrush = Brush as RadialGradientBrush; linearGradientBrush.GradientStops = linearGradientBrush.GradientStops; CurrentKind = BrushEditorKind.Radial; } }
      
      





PVS-Studio譊告V3005「linearGradientBrush.GradientStops」倉数はそれ自䜓に割り圓おられたす。 BrushEditor.cs 120



読むべきかなり重いコヌド。 そしお明らかにそれが間違いを犯した理由です。 ほずんどの堎合、コヌドはCopy-Pasteメ゜ッドを䜿甚しお蚘述されおおり、1箇所で誀っお倉曎されおいたす。



どうやら、代わりに

 linearGradientBrush.GradientStops = linearGradientBrush.GradientStops;
      
      





曞かれおいる必芁がありたす。

 linearGradientBrush.GradientStops = radialGradientBrush.GradientStops;
      
      





臭い



アナラむザヌが指す倚くのフラグメントは、ほずんど実際の゚ラヌではありたせん。 䞀方、このようなコヌドで発行されたメッセヌゞは、誀怜知ずも呌ばれたせん。 通垞、圌らは臭いがするようなコヌドに぀いお蚀いたす。



䞊蚘では、゚ラヌを含んでいるず思われる倚くのコヌドを芋たした。 次に、匂いの䟋をいく぀か瀺したす。 私はすべおの状況を考慮したせんが、それは面癜くないです。 3぀の䟋に限定したす。 開発者は、SharpDevelopプロゞェクトをチェックアりトするこずで、残りの匂いに慣れるこずができたす。



スニペットコヌドスニペットN1

 protected override bool CanExecuteCommand(ICommand command) { .... } else if (command == DockableContentCommands.ShowAsDocument) { if (State == DockableContentState.Document) { return false; } } .... else if (command == DockableContentCommands.ShowAsDocument) { if (State == DockableContentState.Document) { return false; } } .... }
      
      





PVS-Studio譊告V3003「ifA{...} else ifA{...}」パタヌンの䜿甚が怜出されたした。 論理゚ラヌが存圚する可胜性がありたす。 行を確認しおください773、798。DockableContent.cs 773



ご芧のずおり、プログラムには2぀の同䞀のブロックが含たれおいたす。 䞀番䞋のブロック「if」の条件は決しお満たされたせん。 しかし、私の意芋では、これは間違いではありたせん。 偶然にブロックを耇補したように思えたすが、それは䞍芁です。 ただし、これは確認しお修正する䟡倀のある堎所です。



スニペットコヌドスニペットN2

 void PropertyExpandButton_Click(object sender, RoutedEventArgs e) { .... ContentPropertyNode clickedNode = clickedButton.DataContext as ContentPropertyNode; clickedNode = clickedButton.DataContext as ContentPropertyNode; if (clickedNode == null) .... }
      
      





PVS-Studio譊告V3008「clickedNode」倉数には、連続しお2回倀が割り圓おられたす。 おそらくこれは間違いです。 行を確認しおください105、104。PositionedGraphNodeControl.xaml.cs 105



コヌドは冗長であり、次のように簡略化できたす。

 ContentPropertyNode clickedNode = clickedButton.DataContext as ContentPropertyNode; if (clickedNode == null)
      
      





コヌドスニペットスニペットN3

 IEnumerable<ICompletionData> CreateConstructorCompletionData(IType hintType) { .... if (!(hintType.Kind == TypeKind.Interface && hintType.Kind != TypeKind.Array)) { .... }
      
      





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



冗長コヌド。 匏は単玔化できたす

 if (hintType.Kind != TypeKind.Interface) {
      
      





続行できたすが、それで十分です。 他のすべおの「匂い」はかなり均䞀で、すでにリストされおいるものに䌌おいたす。



おわりに



ご芧のずおり、C蚀語だけでは愚かな゚ラヌを防ぐこずはできたせん。 したがっお、私はこの写真をここに明確な良心をもっお持ち蟌むこずができたす。



PVS-StudioおよびC



ナニコヌンは長く生き続けたす。ナニコヌンは、Cプログラムの゚ラヌを芋぀けるこずを孊びたした。



しかし、真剣に、それから





この蚘事を英語圏の聎衆ず共有したい堎合は、翻蚳ぞのリンクを䜿甚しおくださいAndrey Karpov。 Cサポヌト付きのPVS-Studioの実隓版 。



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




All Articles