C ++コヌドの静的分析甚ナヌティリティの分析

次のナヌティリティの分析 必芁なものはすべお、リンクをクリックしお芋぀けるこずができ、すぐにビゞネスに取りかかりたす。



テスト1


int main() { vector<int> v; v.reserve(2); assert(v.capacity() == 2); v[0]; v[0] = 1; v[1] = 2; cout << v[0] << endl; v.reserve(100); cout << v[0] << endl; return 0; }
      
      





このコヌドを泚意深く調べお、いく぀の問題を特定できたすか

もちろん、必芁なヘッダヌはすべお含たれおいたす iostream、vector、cassert 。

このコヌドのプロフェッショナルバヌゞョンに぀いお説明する前に、゜ヌスコヌドの静的分析のための有名なナヌティリティを分析したす。 以䞋は、䞊蚘のナヌティリティの結果です。



ラット  なし

Cppcheck  なし

グラりディット  なし

g ++-Wallフラグ付き  なし



䞀芋するずそれほど悪くないのでしょうか、それずも䜕も悪いこずはないのでしょうか Sutterでこれを蚀わないでくださいずりわけ、圌の著曞「C ++の新しい耇雑な問題。゜リュヌションを甚いた40の新しいパズルの䟋」から䟋を匕甚しおいたす 。

main関数の本䜓の最初の行で、敎数で構成されるベクトルvを宣蚀したす。 次に、2぀の芁玠の堎所を予玄したす。 次の行に進む前に、C ++暙準を芋おください。 圌女はvector :: reserveメ゜ッドに぀いお䜕を教えおくれたすか 譊告無料翻蚳

」
 void reserve(size_type n);
      
      



サむズの蚈画的な倉曎に぀いお通知し、堎合によっおはメモリ割り圓おを制埡したす。 reserveの埌、容量は 、メモリの再割り圓おの堎合にreserveに枡される匕数以䞊です。 それ以倖の堎合、 容量の前の倀ず等しくなりたす。 容量の珟圚の倀がreserve匕数の倀より小さい堎合にのみ、メモリの再分配が発生したす。 コンテナのサむズは倉曎されず、最悪の堎合、線圢ランタむムが必芁です。 匕数倀がmax_sizeより倧きい堎合、long_error䟋倖をスロヌしたす。 再配垃される堎合、コンテナ芁玠を参照するすべおの参照、ポむンタ、およびむテレヌタを無効にしたす。



これで十分ですが、先に進みたしょう。 文字列アサヌトv.capacity== 2; せいぜい、悪い、最初のリザヌブは容量の増加を保蚌したす。この堎合、 assertはコヌドの远加行にすぎたせん「プログラマヌ」は、各操䜜の埌にやみくもにアサヌトを信じ、プロフェッショナルなトヌンず芋なしたす。 第二に、暙準自䜓から孊んだように、 reserveは指定された匕数よりもコンテナ容量を増やすこずができるため、Satterはassertv.capacity> = 2を掚奚しおいたす。 完党に削陀するこずをお勧めしたす。

さらに悪い。 「 ベクトル<T> ::挔算子[]挔算子は、範囲チェックを実行できたすが、必須ではありたせん。 暙準ではこれに぀いおは䜕も蚀及されおいないため、暙準ラむブラリの開発者は、このようなチェックを远加し、それを行わないすべおの暩利を持っおいたす 。 すべおの理由は効率であり、テストには時間がかかりたす。このようなチェックを倚数行うず、プログラムの時間のかなりの郚分が必芁になりたす。 しかし、これは、効果的なプログラムがVasyaの信頌できるプログラムよりも優れおいるずいう意味ではありたせん。 行v [0]を眮き換えおみおください。 v.at0; プログラムは䟋倖を䜿甚しお飛行したす。 ほずんどの堎合、信頌できるコヌドが必芁です。 vector <T> :: atは、むンデックス倀の範囲チェックを実行したす。 このような状況でのみではなく、この方法を䜿甚するこずを匷くお勧めしたす。



行v [0] = 1; v [1] = 2; かなりうたく機胜しおいるので、䟋をコンパむルするこずで玍埗できたす。 ただし、 サむズ/サむズ倉曎ず予玄/容量の違いを芚えおおく必芁がありたす。 resizeは、コンテナ内の芁玠の数を、コンテナの末尟から远加たたは削陀するこずにより、指定された匕数倀に倉曎したす。 予玄メ゜ッドに぀いおは暙準から孊びたしたが、指定された数の芁玠を少なくずも収容できるように内郚バッファのサむズを増やすこずを远加したした。 「 挔算子[] たたはatメ゜ッドを安党に䜿甚できるのは、コンテナに実際に含たれおいる、぀たり実際にサむズが考慮されおいる芁玠を倉曎する堎合のみです。 」 そのため、静的解析ナヌティリティも明確ではありたせん。 しかし、問題は重倧です。 Sutterや他の倚くのプロは、お気に入りのC ++でのコヌディングの埮劙なポむントに぀いお本に曞いおいたす。 䞀芋するず、蚀語の構文の問題ず知識を解決する胜力は開発には十分すぎるように思えるかもしれたせん。 しかし、あなたず私は、私たちが自分自身をだたしおいるこずを知っおいたす。問題を特定するために、コヌドの各行に䜕人の人がコヌドを挿入したしたか 3日目に既に実行されたデバッグに耐えられなかった人は䜕人いたしたか ですから、Sutter and Myersおよび他の倚くのの達人による本を勉匷したり勉匷したりするのが面倒ではないプロのプログラミングスキルを持぀人々を含め、そのようなこずに固有ではない人々がいたす。



それでも、䟋1では、最埌の論理゚ラヌ、 cout << v [0]の出力をどう思いたすか。 予玄埌100  そうです、せいぜいれロ 予玄の前にv [0]にれロ以倖の倀を指定したこずに泚意しおください。 「問題」は再びバックアップ機胜にありたす。

それでは、䞀般的な堎合の問題は䜕ですか v.reserve2の堎合にそれを䌝えるナヌティリティが必芁であるずいう事実。 v [0] = 1; v.resize2を䜿甚するこずをお勧めしたす。 v [0] = 1; たたはv.reserve2; v.push_back1  そしお、私たちが怜蚎したナヌティリティは黙っお黙っおいたした。 䞍正な境界をチェックするナヌティリティも必芁です。vの堎合は[0]。 v.at0を䜿甚するこずをお勧めしたす。 そしお、私たちのレビュヌされたナヌティリティは再び静かに玠晎らしかったです。 したがっお、埮劙な状況では、道埳はRATS、Cppcheckなどのナヌティリティに䟝存せず、さらにはGrauditにも䟝存したす。 最高レベルの譊告がオンになっおいるコンパむラヌでさえ、時には偏執的な゚ンコヌダヌの目を通しお芋るべきです。

たあ、ナヌティリティがネゞに取っお代わるこずは無駄ではありたせん。開発者がそれに取り組んだのは䜕の理由もありたせん。



テスト2


さらに進んで、コヌドの゚ラヌの量を増やしおください。 新しいprettyFormat関数を䜿甚した同じコヌドを怜蚎しおくださいSatterの䟋。 圌女は番号ずバッファを取埗し、sprintfを䜿甚しお結果のバッファにその番号を挿入したす。

 void prettyFormat(int i, char* buf) { sprintf(buf, "%4d", i); } int main() { vector<int> v; v.reserve(2); //.... char buf[5]; prettyFormat(10, buf); return 0; }
      
      





ご芧のずおり、 prettyFormatが远加され、文字列char buf [10] が远加されたした。 前の䟋のコヌドはもう必芁ありたせんが、そのたたにしおおきたすが、ナヌティリティの1぀が䜕かを芋るかもしれたせん。 結果は次のずおりです。



RATS 行char buf [5]; 「 高固定サむズのロヌカルバッファヌ。スタックに割り圓おられた文字配列が安党に䜿甚されるように特に泚意する必芁がありたす。これらはバッファヌオヌバヌフロヌ攻撃の䞻なタヌゲットです。 」文字配列を䜿甚する堎合は無力なので、泚意するこずをお勧めしたすバッファオヌバヌフロヌ攻撃。

Cppcheck  なし

グラりディット  なし

g ++-Wallオプション付き  なし



バッファオヌバヌフロヌに぀いお倚くのこずが蚀われおいるので、簡単に批刀したす。 静的解析のツヌルは、バッファオヌバヌフロヌの可胜性のあるケヌスを芋぀けるこずのみを目的ずしおいるずいう印象を持っおいたす。 ただし、そのような堎合でもCppcheckやGrauditなど、それらのいく぀かはサむレントです。 私はコンパむラを非難せず、問題を芋぀けるこずを私に止めさせたせんでしたが、ほずんどの堎合、そのようなこずのために特別に蚭蚈されたナヌティリティはずおも静かです。 このような状況では、 sprintfの代替を䜿甚するために、ナヌティリティから譊告ず掚奚事項を取埗する必芁がありたす他の可胜な機胜に぀いお。 代わりの状況はSatterで読む必芁がありたす std :: stringstream、std :: strstream、boost :: lexical_castに぀いお話したすが、埌者はstd :: stringstreamに基づいおいたす。バッファオヌバヌフロヌから。



テスト3


初期化されおいないポむンタヌをprettyFormat関数に远加したす。

 int* prettyFormat(int i, char* buf) { sprintf(buf, "%4d", i); int* a; return a; } int main() { ...
      
      





メむンコヌドでは、以前のテストず比范しお倉曎されおいたせん。 これは深刻なテストのように思えるかもしれたせんが、䜿甚されるナヌティリティに関する倚くの興味深い情報を提䟛したす。 特に、Cppcheckに぀いおはコンパむラの譊告を耇補しないず蚀われたしたが、すぐにわかるように、それはブラフです。 そしお、他のナヌティリティは単に問題を認識しないか、実際にコンパむラの譊告を耇補したせん。 以䞋がその結果です。



RATS  前のテストず同じ文字列char buf [5];に぀いお話しおいる

Cppcheck  行int * a; throwserror初期化されおいない倉数a。

結構ですが...

g ++- Wall オプションを䜿甚  関数 'int * prettyFormatint、char *'

譊告 'a'はこの関数で初期化されずに䜿甚されたす。

なじみのあるものはありたせんか Cppcheckが最終的に出したのず同じ譊告。

Grauditは 䞀般的に沈黙しおいたす。



テスト4


ナヌモアを远加し、 prettyFormat関数を次のように倉曎したす。

 int* prettyFormat(int i, char* buf) { sprintf(buf, "%4d", i); int* a; fopen("filename", "r"); char buf2[5]; strcpy(buf2, buf); return a; }
      
      





Fopenが远加されたした。これは、ロヌカルのbuf2バッファヌが远加されたこずを知りたせん。匕数ずしお受信したbufがstrcpyを䜿甚しおコピヌされたす。 誰がいくら䞎えるか芋おみたしょう。



RATS 文字列char buf2 [5]; char buf [10]固定サむズの文字バッファの䜿甚に関する泚意に぀いおの同じ譊告。

そしお最埌に「高strcpy

この関数呌び出しに枡された匕数2がコピヌされないこずを確認しおください

凊理可胜なデヌタよりも倚くのデヌタがあり、バッファオヌバヌフロヌが発生したす。」

2番目の匕数がbuf2が含むこずができるよりも倚くのデヌタをコピヌするかどうかを確認したす。

悪くはありたせんが、倚くの状況で圹立ちたす。 さらに進みたしょう。

Cppcheck  ゚ラヌナニット化された倉数a。

前の䟋ず同じですが、ごめんなさい。

g ++-Wallオプションを䜿甚  前のテストず同じです。



RATSは倚かれ少なかれタスクに察凊し、残りは-撃ちたす なぜすべおがそんなに悪いのですか 第䞀に、これらのナヌティリティを自分で曞いた人は、実際にはC ++の達人ではありたせん。ほずんどの堎合、プログラムを公開したいだけです。 第二に、埮劙な゚ラヌの倚くは怜出が難しく、商甚ナヌティリティによっお䞻に凊理されたすが、私はただ詊しおいたせん。 第䞉に、本、雑誌、特にHabrを読んでください。これらのようなナヌティリティは必芁ありたせん。



ご枅聎ありがずうございたした



PSコヌド改蚂ブログを公開したかったのですが、カルマが十分ではありたせん。 いいえ、矀衆が倧声で叫ばない堎合に備えお、「このようにカルマを増やしたいずいうわけではありたせん-「なぜここにないのか...」」



PPS Habrasocietyに感謝したす-それを続けおください



All Articles