Linux甚のPVS-Studioの䜜成方法





今幎、私たちは長い間物議をかもしおきたこず、぀たりPVS-Studio補品をLinuxシステムに適応させるこずを始めたした。 この蚘事では、10幎にわたるPVS-Studioアナラむザヌfor Windowsの埌、Linuxディストリビュヌション向けの補品をどのように䜜成するかに぀いお説明したす。 残念ながら、䞀郚のプログラマヌが考えるように、これは倚くの䜜業であり、限定されたせんが、タヌゲットプラットフォヌム甚の゜ヌスコヌドのみをコンパむルしたす。



はじめに



䞀般に、 PVS-Studioアナラむザヌのコン゜ヌルカヌネルは長い間Linuxで構築されおいたした。 箄3幎間になりたす。 パブリックドメむンにそのようなバヌゞョンが存圚しないずいう質問にすぐに答えたす。既存の゜フトりェア補品をベヌスにした゜フトりェア補品を䜜成するこずは、倧きな仕事であり、倚くの工数、予期せぬ問題やニュアンスが倚くありたす。 次に、これを予芋しただけなので、Linuxシステムの公匏アナラむザヌサポヌトは開始されたせんでした。



私の同僚ずは異なり、プロゞェクト怜蚌に関する倚くの蚘事の著者である私は、Linuxプロゞェクトからむンスピレヌションを埗たした。 この環境には、Windows䞊で構築するのが非垞に難しいか、䞍可胜な倧芏暡で興味深いオヌプン゜ヌスプロゞェクトが豊富にありたす。 これは、PVS-Studio for Linuxが今日たでに開発したオヌプン゜ヌスプロゞェクトをチェックするこのようなタスクのフレヌムワヌク内にありたす。



PVS-StudioカヌネルコヌドをLinuxに移怍するのに数か月かかりたした。 システム関数ぞの耇数の呌び出しを眮き換え、Chromiumプロゞェクトでデバッグするこずにより、すでに正垞に機胜するコン゜ヌルアプリケヌションが提䟛されたした。 このバヌゞョンのアナラむザヌは、通垞の倜間ビルドに远加され、Clang Static Analyzerでもテストされたした。 開いおいるプロゞェクトずアセンブリ制埡の定期的なチェックにより、アナラむザヌは数幎間問題なく存圚し、時にはこのツヌルがすでに販売されおいるようにさえ芋えたした。 しかし、その時点で私がどのようにプロゞェクトをチェックしなければならなかったかはただわかりたせん...



静的分析ツヌルの䜿甚に぀いお

















ツヌルの開発に関する話を続ける前に、静的分析の方法論自䜓に぀いお少しお話ししたいず思いたす。 したがっお、「゚ラヌなしですぐにコヌドを蚘述し、同僚ずレビュヌを行うこずができる堎合、なぜサヌドパヌティ補ツヌルを䜿甚するのか」ずいうスタむルで質問にすぐに答えたす。 残念ながら、この質問はよく聞かれたす。



静的コヌド分析を䜿甚するず、プログラムの゜ヌスコヌドの゚ラヌや欠萜を特定できたす。 䜿甚するツヌルに関係なく、これは将来のアプリケヌションのコヌドの品質管理のための優れた方法論です。 可胜であれば、さたざたな静的解析ツヌルを組み合わせるず䟿利です。



䌚議の読者、ナヌザヌ、たたはリスナヌの䞭には、同僚ずコヌドをレビュヌするだけで、コヌド䜜成の初期段階で゚ラヌを特定できるず考える人がいたす。 そしお、そのような「怜玢」で䜕かがおそらく芋぀けられるでしょう。 しかし、今回も同じこずに぀いお話しおいる。 実際、静的分析はコヌドレビュヌの自動化されたプロセスず考えるこずができたす。 静的アナラむザヌが同僚のもう䞀人であるず想像しおください。 すべおのコヌドレビュヌに粟力的に参加し、疑わしい堎所を瀺す䞀皮の仮想人間ロボット。 それは䟿利ではありたせんか



倚くの業界では、いわゆる「人的芁因」を排陀するために自動化に頌っおいたす。 たた、コヌド品質管理も䟋倖ではありたせん。 手動のコヌドレビュヌを緎習するこずを拒吊するこずはお勧めしたせん。 静的アナラむザヌを䜿甚するだけで、初期段階でさらに倚くの゚ラヌを怜出できたす。



もう1぀の重芁なポむント-プログラムは疲れたり怠けたりしたせん。 さたざたな皮類の゚ラヌがコヌドに導入されたす。 タむプミス 目で区別するのは非垞に難しいです。 蚀語゚ラヌ 審査官の資栌に匷く䟝存しおいたす。 状況は、珟代の倧量のコヌドによっお悪化しおいたす。 倚くの機胜は、倧型モニタヌでも完党には収たりたせん。 コンテキストが䞍完党な堎合、怜査官の譊戒は䜎䞋したす。 さらに、15分間コヌドを泚意深く読んだ人は疲れ始めたす。 そしお、遠くなるほど匷くなりたす。 したがっお、毎幎増加しおいる自動分析ツヌルの人気。



PVS-StudioナヌザヌはLinuxバヌゞョンに䜕を求めたしたか

















圓瀟の補品は、プログラムの開発に䜕らかの圢で関係しおいる人々にずっお垞に興味深いものでした。 これらは、アナラむザヌをすぐに詊すこずができるWindowsナヌザヌです。 䞀般のプログラマヌでも、他のプラットフォヌムや蚀語のプログラマヌでもありたせん。 そのような泚意が期埅されおいたす 倚くの゚ラヌは倚くのプログラミング蚀語に共通しおいたす。



Linuxナヌザヌは、このプラットフォヌムのアナラむザヌに぀いお長い間匷く尋ねおきたした。 質問ず議論は次のように芁玄できたす。





さらなるストヌリヌは、ナヌザヌの声明ず圌らの期埅ずの矛盟を繰り返し確認したす。



アセンブリスクリプトを理解するずいう神話

















倧芏暡な商業プロゞェクトの人々ず話をした埌、倚くの開発者がプロ​​ゞェクトの組み立おに粟通しおいないこずが刀明したした。実際、そのような知識は必ずしも完党に必芁ではありたせん。 各開発者は、自分のプロゞェクト/モゞュヌルをビルド/デバッグする方法を知っおいたす。 しかし、通垞、この知識はすべお、プログラマヌが実行するいく぀かの魔法のコマンドのセットです。 比ur的に蚀えば、倧きなボタンがあり、クリックするだけで十分であり、出力では組み立おられたモゞュヌルを取埗したす。 しかし、これらすべおが内郚でどのように機胜するかに぀いおは、䞀般的な考えしかありたせん。 たた、アセンブリスクリプトは倚くの堎合、特別な人によっお監芖されたす。



このような堎合、少なくずもアナラむザヌに慣れるには、統合なしでプロゞェクトを怜蚌するツヌルが必芁です。



アナラむザヌのLinuxバヌゞョンは、Windowsでコンパむラヌ監芖システムを䜜成した盎埌に衚瀺され、このプラットフォヌムでプロゞェクトをチェックできたした。 埌で刀明したように、Microsoftコンパむラヌを䜿甚しお収集される倚くの深刻なプロゞェクトがありたすが、Visual Studio甚のプロゞェクトはありたせん。 そこで、Qt、Firefox、CryEngine5のチェックに関する蚘事を執筆し、さらにEpic Games ず協力しお、コヌドのバグを修正したした。 調査では、コンパむラに関する情報スタヌトアップディレクトリ、コマンドラむンパラメヌタ、環境倉数を知っおいる堎合、この情報でプリプロセッサを呌び出しお分析を実行するこずができたす。



Linuxプロゞェクトをチェックする蚈画を立おおいたずきに、特定のプロゞェクトごずにアナラむザヌの統合を理解できないこずにすぐに気づいたので、ProcFS/ proc / id'sに同様の監芖システムを䜜成したした。 Windowsプラグむンからコヌドを取埗し、モノで実行しおファむルを分析したした。 数幎にわたり、この方法はプロゞェクトのテストに䜿甚されおきたしたが、その最倧のものはLinuxカヌネルずFreeBSDです。 この方法は長期にわたっお䜿甚されおいたすが、倧量䜿甚には適しおいたせん。 補品はただ準備ができおいたせん。



監芖技術の遞択

















そのような機胜の必芁性ず重芁性を決定したので、プロトタむプを䜜成しお遞択し始めたした。





定期的なテストの登堎



゜フトりェアをテストするにはさたざたな方法がありたす。 アナラむザヌず蚺断をテストするための最も効果的な実行は、オヌプンプロゞェクトの倧芏暡なコヌドベヌスで実行されたす。 たず、玄30の䞻芁なオヌプン゜ヌスプロゞェクトを遞択したした。 先ほど、Linuxで組み立おられたアナラむザヌが1幎以䞊存圚し、蚘事のプロゞェクトが定期的にチェックされおいるこずを述べたした。 すべおがうたくいくように芋えた。 しかし、本栌的なテストを開始しただけで、アナラむザヌの欠陥の党䜓像がわかりたした。 分析を開始する前に、コヌドを解析しお必芁な構成を芋぀ける必芁がありたす。 分離䞍可胜なコヌドが分析の品質に䞎える圱響はわずかですが、状況は䟝然ずしお䞍快です。 すべおのコンパむラに非暙準の拡匵機胜がありたすが、MS Visual C / C ++で長い間サポヌトしおおり、GCCではほずんど最初からこの戊いを開始する必芁がありたした。 なぜほずんど Windowsでは、長い間GCCMinGWでの䜜業をサポヌトしおきたしたが、それほど普及しおいないため、私たちもナヌザヌも問題はありたせんでした。



コンパむラヌ拡匵



















このセクションでは、GCC拡匵機胜を䜿甚するコヌド、぀たり他のどこにも芋られないコヌドに焊点を圓おたす。 なぜ必芁なのでしょうか ほずんどのクロスプラットフォヌムプロゞェクトでは、䜿甚される可胜性は䜎いです。 たず、実践が瀺すように、それらが䜿甚されたす。 Linuxでプロゞェクトをテストするためのシステムを開発するずきに、このようなコヌドに出䌚いたした。 しかし、暙準ラむブラリのコヌドを解析するずきに䞻な問題が発生したす。拡匵機胜が最倧限に掻甚されおいたす。 プロゞェクトの前凊理枈みファむルを確認するこずはできたせん。最適化のために、䜿い慣れたmemset関数がステヌトメント匏で構成されるマクロになるこずがありたす。 しかし、たず最初に。 Linuxプロゞェクトをテストするずきに、どのような新しいデザむンに出䌚いたしたか



芋られた最初の拡匵子の1぀はむニシャラむザに指定されたした 。 それらを䜿甚しお、配列を任意の順序で初期化できたす。 これは、 enumでむンデックス付けされおいる堎合に特に䟿利です。むンデックスを明瀺的に指定するこずで、読みやすくし、将来倉曎する際の間違いの可胜性を枛らしたす。 それはずおも玠敵でシンプルに芋えたす



enum Enum { A, B, C }; int array[] = { [A] = 10, [B] = 20, [C] = 30, }
      
      





スポヌツの興味のために、この䟋を少し耇雑にしたす。



 enum Enum { A, B, C }; struct Struct { int d[3]; }; struct Struct array2[50][50] = { [A][42].d[2] = 4 };
      
      





぀たり、この構造では、むンデックス付けず構造䜓のメンバヌの呌び出しのシヌケンスを初期化子ずしお䜿甚できたす。 範囲はむンデックスずしお指定するこずもできたす



 int array[] = { [0 ... 99] = 0, [100 ... 199] = 10, }
      
      





小さいながらもセキュリティの芳点から非垞に䟿利なGCCの拡匵機胜は、nullポむンタヌに関連付けられおいたす。 NULLの䜿甚の問題に぀いおは、すでに倚くの蚀葉が蚀われおいたすが 、繰り返しはしたせん。 GCCの堎合、C ++のNULLは__nullずしお宣蚀されるため、状況はわずかに改善されたす 。 したがっお、GCCは脚のそのようなショットから私たちを保護したす。



 int foo(int *a); int foo(int a); void test() { int a = foo(NULL); }
      
      





コンパむルするず、゚ラヌが発生したす。



 test.c: In function 'void test()': test.c:20:21: error: call of overloaded 'foo(NULL)' is ambiguous int a = foo(NULL); ^ test.c:10:5: note: candidate: int foo(int*) int foo(int *a) { ^ test.c:14:5: note: candidate: int foo(int) int foo(int a) {
      
      





GCCには、__ attribute __属性を蚭定する機胜がありたす。 リンク、アラむメント、最適化、その他倚くのこずを制埡できる関数、倉数、および型の属性のリストがありたす。 興味深い属性の1぀はtransparent_unionです。 このようなナニオンを関数パラメヌタヌにするず、匕数ずしおナニオン自䜓だけでなく、この列挙からのポむンタヌも枡すこずができたす。 このコヌドは正しいでしょう



 typedef union { long *d; char *ch; int *i; } Union __attribute((transparent_union)); void foo(Union arg); void test() { long d; char ch; int i; foo(&d); //ok foo(&ch); //ok foo(&i); //ok }
      
      





transparent_unionが䜿甚する䟋は、 埅機関数です。int*たたはunion wait *を受け入れるこずができたす。 これは、POSIXおよび4.1BSDずの互換性のために行われたす。



おそらくGCCのネストされた関数に぀いお聞いたこずがあるでしょう。 関数の前に宣蚀された倉数を䜿甚できたす。 ネストされた関数をポむンタヌで枡すこずもできたすただし、明らかな理由により、メむン関数の終了埌にこのポむンタヌで呌び出すこずはできたせん。



 int foo(int k, int b, int x1, int x2) { int bar(int x) { return k * x + b; } return bar(x2) - bar(x1); } void test() { printf("%d\n", foo(3, 4, 1, 10)); //205 }
      
      





しかし、そのような関数からgotoを「芪関数」にできるこずを知っおいたしたか これは、そのような関数を別の関数に転送するこずず組み合わせお特に印象的に芋えたす。



 int sum(int (*f)(int), int from, int to) { int s = 0; for (int i = from; i <= to; ++i) { s += f(i); } return s; } int foo(int k, int b, int x1, int x2) { __label__ fail; int bar(int x) { if (x >= 10) goto fail; return k * x + b; } return sum(bar, x1, x2); fail: printf("Exceptions in my C?!\n"); return 42; } void test() { printf("%d\n", foo(3, 4, 1, 10)); //42 }
      
      





実際には、そのようなコヌドは非垞に悲しい結果をもたらす可胜性があるずいう事実です䟋倖の安党性は、Cを蚀うたでもなく、RAIIを䜿甚したC ++でもかなり耇雑なトピックです。したがっお、そうしない方が良いです。



埌藀ず蚀えば。 GCCでは、タグを保存しお、その埌にポむンタヌを眮くこずができたす。 そしお、配列に曞き蟌むず、倉換テヌブルが埗られたす



 int foo(); int test() { __label__ fail1, fail2, fail3; static void *errors[] = {&&fail1, &&fail2, &&fail3}; int rc = foo(); assert(rc >= 0 && rc < 3); if (rc != 0) goto *errors[rc]; return 0; fail1: printf("Fail 1"); return 1; fail2: printf("Fail 2"); return 2; fail3: printf("Fail 3"); return 3; }
      
      





そしお、これはClangの小さな拡匵です。 PVS-Studioは長い間このコンパむラを䜿甚するこずができたしたが、今でも蚀語ずコンパむラに登堎する新しいデザむンに驚くこずはありたせん。 それらの1぀を次に瀺したす。



 void foo(int arr[static 10]); void test() { int a[9]; foo(a); //warning int b[10]; foo(b); //ok }
      
      





このレコヌドを䜿甚しお、コンパむラは枡された配列に10個以䞊の芁玠があるこずを確認し、ない堎合は譊告を出したす。



 test.c:16:5: warning: array argument is too small; contains 9 elements, callee requires at least 10 [-Warray-bounds] foo(a); ^ ~ test.c:8:14: note: callee declares array parameter as static here void foo(int arr[static 10]) ^ ~~~~~~~~~~~
      
      





ベヌタ版のテストを終了したした。 りェヌブ1



アナラむザヌの安定したバヌゞョン、ドキュメント、および統合せずにプロゞェクトを怜蚌するためのいく぀かの方法を準備した埌、クロヌズドテストを開始したした。



最初のテスタヌに​​アナラむザヌを発行し始めたずき、アナラむザヌに実行可胜ファむルを提䟛するだけでは䞍十分であるこずがわかりたした。 「すばらしい補品があり、倚くの゚ラヌが芋぀かりたした」から「私はあなたのアプリケヌションを信甚しおいないので、/ usr / binにむンストヌルしたせん」ずいうレビュヌを受けたした。 残念ながら、埌者の方が倚かった。 したがっお、実行可胜ファむルでの独立した䜜業の可胜性に関するフォヌラムナヌザヌの議論は誇匵されたした。 この圢匏では、すべおの人がアナラむザヌを䜿甚できる、たたは䜿甚したくないずは限りたせん。 Linuxで゜フトりェアを配垃するには、いく぀かの䞀般的な方法を䜿甚する必芁がありたす。



ベヌタ版のテストを終了したした。 りェヌブ2



最初のレビュヌを受け取った埌、テストを停止し、ほが2週間にわたっおハヌドワヌクに没頭したした。 他の人のコヌドをテストするず、コンパむラに関するさらに倚くの問題が明らかになりたした。 なぜなら GCCに基づいお、さたざたなプラットフォヌム甚のコンパむラずクロスコンパむラが䜜成され、その埌、圓瀟のアナラむザヌを䜿甚しお、さたざたな鉄片の゜フトりェアさえもテストし始めたした。 原則ずしお、アナラむザヌはその任務を凊理し、感謝のフィヌドバックを受け取りたしたが、アナラむザヌは、サポヌトする必芁がある拡匵機胜のためにコヌドの䞀郚をスキップしたした。



誀怜知は静的アナラむザヌに固有のものですが、Linuxではその数がわずかに増えおいたす。 そのため、新しいプラットフォヌムずコンパむラの蚺断に取り組み始めたした。



倧きな改良点は、Deb / Rpmパッケヌゞの䜜成でした。 登堎埌、PVS-Studioのむンストヌルに察する䞍満はなくなりたした。 おそらく、sudoを䜿甚しおパッケヌゞをむンストヌルするこずに激怒した人は1人だけだったでしょう。 この方法でほずんどすべおの゜フトりェアがむンストヌルされたすが。



ベヌタ版のテストを終了したした。 りェヌブ3



たた、改蚂のために短い䌑憩を取り、次の倉曎を行いたした。



  1. 迅速な怜蚌のための構成ファむルの拒吊-Deb / Rpmパッケヌゞの導入埌、最初の堎所はアナラむザヌの構成ファむルに蚘入する問題で占められおいたした。 ラむセンスファむルぞのパスずアナラむザヌレポヌトぞのパスの2぀の必須パラメヌタヌのみを䜿甚しお、構成ファむルなしでプロゞェクトを迅速に怜蚌するためにモヌドを倉曎する必芁がありたした。 このモヌドの詳现蚭定の可胜性は残りたす。



  2. straceナヌティリティのログの凊理が改善されたした。最初は、 straceナヌティリティのログは、プロトタむプが䜜成されたPerl蚀語のスクリプトによっお凊理されおいたした。 スクリプトはゆっくりず動䜜し、分析の䞊列化が䞍十分でした。 この機胜をC ++で曞き盎した埌、ファむル凊理は加速し、1぀のプログラミング蚀語ですべおのコヌドをサポヌトするこずも容易になりたした。



  3. Deb / Rpmパッケヌゞの完成-as クむックチェックモヌドが機胜するには、 straceナヌティリティが必芁で、最初のパッケヌゞにPerl / Pythonスクリプトが含たれおいたため、すべおの䟝存関係がすぐに正しく登録されず、埌でスクリプトが完党に砎棄されたした。 埌に、グラフィカルマネヌゞャヌを䜿甚しおアナラむザヌをむンストヌルする際の譊告に぀いお䜕人かの人々が曞いたので、すぐにそれらを削陀したした。 ここで、私たちが自分甚に蚭定したテスト方法の利点に泚目したいず思いたす。数十のLinuxディストリビュヌションがDockerにデプロむされ、むンストヌルされたパッケヌゞがむンストヌルされたす。 むンストヌルされたプログラムを実行する機胜もテストされたした。 このようなテストにより、パッケヌゞに新しい倉曎をすばやく加えおテストするこずができたした。



  4. アナラむザヌずドキュメントのその他の改善。 すべおの成果をドキュメントに反映したした。 さお、アナラむザヌのファむナラむズに関する䜜業は止たりたせん。これらは新しい蚺断ず既存の蚺断の改善です。


ベヌタ版のテストを終了したした。 りェヌブ4リリヌス候補



アナラむザヌ配垃の最埌の波では、ナヌザヌはアナラむザヌのむンストヌル、開始、および構成に問題がなくなりたした。 ありがたいフィヌドバック、芋぀かった実際の゚ラヌの䟋、誀怜知の䟋がありたす。



たた、ナヌザヌはアナラむザヌの高床な蚭定に関心を持぀ようになりたした。 そのため、アナラむザヌをMakefile / CMake / QMake / QtCreator / CLionに統合する方法に぀いおのドキュメントの改善を開始したした。 それがどのように芋えるか、私はさらに瀺したす。



十分に開発された統合方法



Makefile / Makefile.amでの統合



統合せずにプロゞェクトをチェックする䟿利さにもかかわらず、アセンブリシステムに盎接統合するこずにはいく぀かの利点がありたす。





アナラむザヌがコンパむラヌず同じ堎所で呌び出されるず、環境、䜜業ディレクトリヌ、およびすべおのパラメヌタヌがアナラむザヌ甚に正しく構成されたす。 この堎合、すべおの条件が満たされ、正しい定性分析が行われたす。



Makefileでの統合は次のようになりたす。



 .cpp.o: $(CXX) $(CFLAGS) $(DFLAGS) $(INCLUDES) $< -o $@ pvs-studio --cfg $(CFG_PATH) --source-file $< --language C++ --cl-params $(CFLAGS) $(DFLAGS) $(INCLUDES) $<
      
      





CMake / CLionの統合



CMakeでのアナラむザヌの統合を怜蚎した結果、CLionでPVS-Studioを䜿甚できるようになりたした。 アナラむザヌレポヌトのファむルを受信するか、IDEで譊告を衚瀺しお問題のある領域を衚瀺できたす。







CMake / QtCreatorでの統合



QtCreatorでCMakeプロゞェクトを操䜜するには、レポヌトを保存するか、IDEでアラヌトをすぐに衚瀺するこずもできたす。 CLineずは異なり、QtCreatorはTaskList圢匏で保存されたレポヌトを衚瀺するために開くこずができたす。







QMake / QtCreatorでの統合



QMakeプロゞェクトでは、簡単な統合方法も提䟛したした。



 pvs_studio.target = pvs pvs_studio.output = true pvs_studio.license = /path/to/PVS-Studio.lic pvs_studio.cxxflags = -std=c++14 pvs_studio.sources = $${SOURCES} include(PVS-Studio.pri)
      
      





おわりに



開発䞭に䜕に到達したしたか



  1. アナラむザヌは、パッケヌゞたたはリポゞトリから簡単にむンストヌルできたす。
  2. アナラむザヌをアセンブリシステムに統合せずにテストを実行するこずにより、アナラむザヌを簡単に理解できたす。
  3. アナラむザヌを定期的に䜿甚するために、各開発者のマシンで増分分析を構成できたす。
  4. ビルドサヌバヌでフルスキャンを蚭定したす。
  5. 䞀般的なIDEずの統合。


そのような楜噚はすでに人々に芋せるこずができたす。



こちらからアナラむザヌをダりンロヌドしお詊すこずができたす。 私たちのニュヌスをフォロヌし、怜蚌のためにプロゞェクトを送信したしょう、今はLinuxで





この蚘事を英語圏の聎衆ず共有したい堎合は、翻蚳リンクSvyatoslav Razmyslov The Development History of PVS-Studio for Linuxを䜿甚しおください。



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




All Articles