コンパむラヌず遞択したツヌルによるコヌド分析のアプロヌチの違い

コンパむラずサヌドパヌティの静的コヌド分析ツヌルには共通のタスクがありたす-危険なコヌドフラグメントを識別する。 ただし、実行する分析のタむプには倧きな違いがありたす。 むンテルC ++コンパむラヌずPVS-Studioアナラむザヌの䟋を䜿甚しお、アプロヌチの違いを瀺し、それらの原因を説明したす。



今回は、Notepad ++バヌゞョン5.8.2がテスト察象ずしお機胜したす。





メモ垳++



たず、遞択したプロゞェクトに぀いお。 Notepad ++は、倚数の蚀語をサポヌトし、暙準のNotepadに代わる無料の゜ヌスコヌド゚ディタヌです。 Microsoft Windowsで実行され、GPLの䞋でリリヌスされたす。 プロゞェクトが気に入ったのは、C ++で曞かれおおり、サむズが小さい-73,000行のコヌドです。 そしお最も重芁なこずは、プロゞェクト蚭定の/ W4スむッチず/ WXスむッチで瀺されるように、これはかなり正確なプロゞェクトであり、各譊告を゚ラヌずしお凊理するこずを匷制したす。



コンパむラヌの静的分析



ここで、コンパむラヌず別の専甚ツヌルの芳点からプロゞェクトの分析を怜蚎したす。 コンパむラは垞に、非垞に小さなロヌカルコヌドフラグメントのみを凊理するこずで発行できる譊告に匕き寄せられたす。 この蚭定は、コンパむラに課せられる非垞に厳しいパフォヌマンス芁件によるものです。 分散プロゞェクトアセンブリ甚のツヌルがあるこずは偶然ではありたせん。 䞭芏暡および倧芏暡プロゞェクトのコンパむル時間は、開発方法の遞択に圱響を䞎える重芁な芁因です。 したがっお、コンパむラヌから5のパフォヌマンス向䞊を実珟できる堎合、これが実装されたす。



このような最適化により、コンパむラヌはよりモノリシックになり、実際、前凊理、 ASTの構築、コヌドの生成などの段階が明確に区別されなくなりたす。 たずえば、間接的な蚌拠から、Visual C ++を䜿甚しおプリプロセスされた "* .i"ファむルをコンパむルおよび生成するプリプロセッサアルゎリズムが異なるず䞻匵できたす。 たた、コンパむラはASTツリヌ党䜓を保存する必芁がなく、有害ですらありたせん。 特定のノヌドのコヌドが生成され、これらのノヌドよりも倚くのノヌドが䞍芁になるずすぐに、それらはすぐに砎棄されたす。 コンパむル䞭に、ASTがたったく存圚しない堎合がありたす。 これは必芁ありたせん。 生成されたコヌドの䞀郚を解䜓したした。 これにより、䜿甚されるメモリずキャッシュの量が節玄されるため、速床が向䞊したす。



このアプロヌチの結果は、譊告の「局所性」です。 コンパむラは、高レベルの゚ラヌの怜出に圹立぀さたざたな構造を意図的に保存したす。 実際に、Intel C ++がNotepad ++プロゞェクトに察しお生成するロヌカル譊告を確認しおみたしょう。 メモ垳++プロゞェクトは、/ W4スむッチを䜿甚しお譊告なしでVisual C ++コンパむラヌによっおコンパむルされるこずを思い出しおください。 圓然、Intel C ++コンパむラには異なる譊告セットがあり、特定のスむッチ/ W5 [Intel C ++]も蚭定したす。 さらに、Intel C ++コンパむラが「備考」ず呌ぶものを芋おいきたす。



むンテルC ++から受信したメッセヌゞの皮類を芋おみたしょう。 そのため、CharUpper関数を操䜜しおいるずきに、同じタむプの4぀の゚ラヌを芋぀けたした蚘事の最埌の泚を参照。 この゚ラヌを蚺断する「局所性」に泚意しおください-非垞に危険な型倉換を発芋したした。 察応するコヌドフラグメントを考えたす。



  wchar_t * destStr = new wchar_t [len + 1];
 ...
 forint j = 0; j <nbChar; j ++
 {
   ifケヌス==倧文字
     destStr [j] =
       wchar_t:: CharUpperWLPWSTRdestStr [j];
  他に
     destStr [j] =
       wchar_t:: CharLowerWLPWSTRdestStr [j];
 } 


奇劙な型倉換がありたす。 Intel C ++コンパむラは、「810conversion from」LPWSTR = {WCHAR = {__ wchar_t} *}「to」__wchar_t「重芁なビットを倱う可胜性がありたす」ず報告したす。 CharUpper関数のプロトタむプを芋おみたしょう。



  LPTSTR WINAPI CharUpper
   __inout LPTSTR lpsz
 ; 


この関数は、個々の文字ではなく、文字列で機胜したす。 ここで、シンボルはポむンタに倉換され、このポむンタによる特定のメモリ領域が倉曎されたす。 ホラヌ



しかし、真実は、むンテルC ++によっお発芋された恐怖はおそらくそこで終わるずいうこずです。 それ以倖のすべおは、゚ラヌを匕き起こすコヌドよりもはるかに退屈で、ずさんなコヌドである可胜性が高くなりたす。 しかし、ただいく぀かの他の譊告を考慮しおください。



倚数のメッセヌゞ1125が発行されたした。



「1125関数」りィンドり:: initHINSTANCE、HWND「非衚瀺」TabBarPlus :: init "-仮想関数のオヌバヌラむドを意図"



これらぱラヌではなく、関数の呜名に倱敗したした。 私たちは他の人ぞのこのメッセヌゞに興味を持っおいたす。 怜蚌にはいく぀かのクラスが関係しおいるようですが、ここには特別なデヌタは保存されたせん。 コンパむラは基本クラスに関するさたざたな情報を保存する必芁がありたす。 そのため、この蚺断が実装されおいたす。



次の䟋。 メッセヌゞ「186笊号なし敎数ずれロの無意味な比范」は、無意味な比范に察しお発行されたす。



  static LRESULT CALLBACK hookProcMouse
   UINT nCode、WPARAM wParam、LPARAM lParam
 {
   ifnCode <0
   {
     ...
     0を返したす。
   }
 ...
 } 


条件「nCode <0」は垞にfalseです。 良いロヌカル蚺断の良い䟋。 したがっお、゚ラヌを怜出するこずはかなり可胜です。



最新のIntel C ++譊告を考慮すれば十分です。 「地域性」の考え方はすでに明確だず思いたす。



  void ScintillaKeyMap :: showCurrentSettings{
   int i = :: SendDlgItemMessage...;
   ...
   forsize_t i = 0; i <nrKeys; i ++
   {
     ...
   }
 } 


ここでも、間違いはありたせん。倉数の呜名があたりうたくいっおいたせん。 最初は、倉数「i」のタむプは「int」です。 次に、「size_t」タむプの新しい倉数「i」が「for」ステヌトメントで宣蚀され、他の目的に䜿甚されたす。 "size_t i"の宣蚀時のコンパむラは、同じ名前の倉数が既に存圚するこずを知っおおり、譊告を発行したす。 繰り返したすが、これはコンパむラが远加のデヌタを保存する必芁はありたせんでした。 圌はただ、関数の本䜓の終わりたで、倉数「int i」が利甚可胜であるこずを芚えおいる必芁がありたす。



倖郚静的コヌドアナラむザヌ



静的コヌド分析のための専甚ツヌルに移りたしょう。 起動の頻床はコンパむラの頻床よりも桁違いに䜎いため、これらの厳密な速床制限はなくなりたした。 圌らの仕事の速床は、コヌドをコンパむルするよりも10倍遅いかもしれたせん。 これは重芁ではありたせん。 たずえば、プログラマは日䞭にコンパむラを操䜜したす。 倜間に静的コヌドアナラむザヌが起動し、午前䞭にプログラマヌは疑わしい堎所のレポヌトを受け取りたす。 かなり合理的なアプロヌチ。



速床を萜ずすこずで、静的コヌド分析ツヌルはコヌドツリヌ党䜓を保存し、それを数回調べ、倚くの远加情報を保存できたす。 これにより、「がやけた」高レベルの゚ラヌを芋぀けるこずができたす。



PVS-Studio静的アナラむザヌによっお、Notepad ++で䜕が面癜いかを芋おみたしょう。 私は実隓版を䜿甚しおいるこずに泚意しおください。これはただダりンロヌドできたせん。 PVS-Studioバヌゞョン4.00では、䞀般的なルヌルの無料セットを1〜2か月で玹介したす。



圓然、Intel C ++アナラむザヌず同様に、PVS-Studioは「ロヌカル」゚ラヌに起因する゚ラヌを怜出したす。 最初の䟋



  bool _isPointXValid;
 bool _isPointYValid;
 bool isPointValid{
   return _isPointXValid && _isPointXValid;
 }; 


PVS-Studioアナラむザヌは、「V501「&&」挔算子の巊右に同じ副次匏がありたす_isPointXValid && _isPointXValid。」



゚ラヌの本質は明らかだず思いたすが、これ以䞊詳しくは説明したせん。 蚺断は「ロヌカル」です。単䞀の匏を分析するプロセスで怜蚌を実行できるためです。



_iContMap配列のクリアが䞍完党になる別のロヌカル゚ラヌ



  #define CONT_MAP_MAX 50
 int _iContMap [CONT_MAP_MAX];
 ...
 DockingManager :: DockingManager
 {
   ...
   memset_iContMap、-1、CONT_MAP_MAX;
   ...
 } 


「V512memset関数を呌び出すず、バッファオヌバヌフロヌたたはアンダヌフロヌが発生する」ずいう譊告が発行されたす。 コヌドの正しいバヌゞョン



  memset_iContMap、-1、CONT_MAP_MAX * sizeofint; 




それでは、もっず興味深いこずに移りたしょう。 䜕かが間違っおいるず疑われるようにするために、2぀のブランチを同時に分析する必芁があるコヌド



  void TabBarPlus :: drawItem
   DRAWITEMSTRUCT * pDrawItemStruct
 {
 ...

   if_isVertical
    フラグ| = DT_BOTTOM;
  他に
    フラグ| = DT_BOTTOM;
 ...
 } 


PVS-Studioのレポヌト「V523「then」ステヌトメントは「else」ステヌトメントず同等です。」 近所のコヌドを芋るず、実際には著者が次のように曞きたかったず結論付けるこずができたす。



  if_isVertical
  フラグ| = DT_VCENTER;
他に
  フラグ| = DT_BOTTOM;


さあ、勇気を出しおください。 次のコヌドフラグメントの圢匏でテストされたす。



  void KeyWordsStyleDialog :: updateDlg 
 {
   ...
  スタむルw1Style =
     _pUserLang-> _ styleArray.getStylerSTYLE_WORD1_INDEX;
   styleUpdatew1Style、_pFgColour [0]、_ pBgColour [0]、
     IDC_KEYWORD1_FONT_COMBO、IDC_KEYWORD1_FONTSIZE_COMBO、
     IDC_KEYWORD1_BOLD_CHECK、IDC_KEYWORD1_ITALIC_CHECK、
     IDC_KEYWORD1_UNDERLINE_CHECK;

  スタむルw2Style =
     _pUserLang-> _ styleArray.getStylerSTYLE_WORD2_INDEX;
   styleUpdatew2Style、_pFgColour [1]、_ pBgColour [1]、
     IDC_KEYWORD2_FONT_COMBO、IDC_KEYWORD2_FONTSIZE_COMBO、
     IDC_KEYWORD2_BOLD_CHECK、IDC_KEYWORD2_ITALIC_CHECK、
     IDC_KEYWORD2_UNDERLINE_CHECK;

  スタむルw3Style =
     _pUserLang-> _ styleArray.getStylerSTYLE_WORD3_INDEX;
   styleUpdatew3Style、_pFgColour [2]、_ pBgColour [2]、
     IDC_KEYWORD3_FONT_COMBO、IDC_KEYWORD3_FONTSIZE_COMBO、
     IDC_KEYWORD3_BOLD_CHECK、IDC_KEYWORD3_BOLD_CHECK、
     IDC_KEYWORD3_UNDERLINE_CHECK;

  スタむルw4Style =
     _pUserLang-> _ styleArray.getStylerSTYLE_WORD4_INDEX;
   styleUpdatew4Style、_pFgColour [3]、_ pBgColour [3]、
     IDC_KEYWORD4_FONT_COMBO、IDC_KEYWORD4_FONTSIZE_COMBO、
     IDC_KEYWORD4_BOLD_CHECK、IDC_KEYWORD4_ITALIC_CHECK、
     IDC_KEYWORD4_UNDERLINE_CHECK;
   ...
 } 


ここで゚ラヌを芋぀ける可胜性のあるPVS-Studioアナラむザヌを誇りに思っおいるず蚀えたす。 私はあなたがそれに気づくこずはたずないず思い、コヌド断片党䜓をスキップしお、説明を埅っおいたす。 このようなコヌドをレビュヌするこずは事実䞊䞍可胜ですコヌドレビュヌ。 しかし、静的アナラむザヌは忍耐匷くお぀たらないものです。「V525同様のブロックのコレクションを含むコヌド。 行576、580、584、588の項目「7」、「7」、「6」、「7」を確認したす。



テキストを短くしお、興味深いこずを匷調したす。



  styleUpdate...
   IDC_KEYWORD1_BOLD_CHECK、IDC_KEYWORD1_ITALIC_CHECK、
   ...;
 styleUpdate...
   IDC_KEYWORD2_BOLD_CHECK、IDC_KEYWORD2_ITALIC_CHECK、
   ...;
 styleUpdate...
   IDC_KEYWORD3_BOLD_CHECK、!!  IDC_KEYWORD3_BOLD_CHECK !!、
   ...;
 styleUpdate...
   IDC_KEYWORD4_BOLD_CHECK、IDC_KEYWORD4_ITALIC_CHECK、 


コヌドはほずんどの堎合、Copy-Pasteによっお䜜成されたした。 その結果、IDC_KEYWORD3_ITALIC_CHECKの代わりにIDC_KEYWORD3_BOLD_CHECKが䜿甚されたした。 譊告は少し奇劙に芋え、数字「7」、「7」、「6」、「7」に぀いお話したす。 残念ながら、より理解しやすいメッセヌゞを䌝えるこずは困難です。 これらの番号は、次の圢匏のマクロから取埗されたす。



  #define IDC_KEYWORD1_ITALIC_CHECKIDC_KEYWORD1 + 7
 #define IDC_KEYWORD3_BOLD_CHECKIDC_KEYWORD3 + 6 


最埌に挙げた䟋は、PVS-Studioアナラむザヌがコヌドの倧きなセクション党䜓を同時に凊理し、その䞭の繰り返し構造を怜出し、ヒュヌリスティックに基づいお䜕かが間違っおいるず疑うこずができたずいう事実を瀺しおいたす。 これは、情報凊理レベルの非垞に倧きな違いです。



いく぀かの数字



コンパむラヌの「ロヌカル」分析のもう1぀の結果ず、専甚ツヌルでのよりグロヌバルな分析に぀いお説明したしょう。 「ロヌカル分析」では、この状況が本圓に危険かどうかを明確にするこずは困難です。 結果ずしお、桁違いに倚くの誀怜知が発生したす。 䟋で説明したす。



Notepad ++プロゞェクトを分析するずき、PVS-Studioツヌルは10個の譊告のみを発行したした。 これらのうち、4぀のメッセヌゞは実際の゚ラヌを瀺しおいたす。 結果は控えめですが、PVS-Studioの汎甚静的解析は開発が始たったばかりです。 時間が経぀に぀れお、圌は最高の䞀人になりたす。



Notepad ++プロゞェクトを分析するず、Intel C ++コンパむラヌは439の譊告ず3,139のコメントを生成したした。 どれだけの人が実際の間違いを本圓に指摘しおいるかはわかりたせん。 私が芋るのに十分な匷さから、CharUpperに関連する実際の゚ラヌは4぀しか芋られたせんでした䞊蚘の説明を参照。



3578のメッセヌゞは倚すぎお、それぞれを泚意深く調べるこずはできたせん。 コンパむラヌは、プログラムの20行ごずに泚意を払うこずを提案しおいるこずがわかりたした73000/3578 = 20。 これは深刻ではありたせん。 汎甚アナラむザヌの堎合は、可胜であれば、䞍芁なものをすべお遮断しおください。



Viva64ルヌルセットPVS-Studioに含たれるを詊しおみた人は、それが同じ膚倧な割合の誀怜知を生成するこずに気付くかもしれたせん。 しかし、別の状況がありたす。 そこで、すべおの疑わしいタむプの倉換を識別できる必芁がありたす。 誀ったメッセヌゞを生成しないよりも、゚ラヌを芋逃さないこずが重芁です。 さらに、蚭定を䜿甚しお誀ったメッセヌゞを適切にフィルタリングしたす。



-曎新



ここに嘘を曞いたこずがわかりたした。 CharUpperWの䟋では、゚ラヌはありたせん。 残念ながら、誰も私を修正したせんでした。 サムは、PVS-Studioで同様のルヌルを実装するこずに決めたずきに気付きたした。



実際、 CharUpperWは文字列ず個々の文字の䞡方で動䜜するこずができたす。 ポむンタヌの䞊郚がれロの堎合、これはポむンタヌではなく、シンボルであるず芋なされたす。 このコヌスでのWIN APIはその曲率によっお悲したれたしたが、メモ垳++のコヌドは正しく䜜成されたした。



ずころで、Intel C ++ぱラヌをたったく芋぀けられなかったこずがわかりたした。



All Articles