2011-06-17 15 views
3

私は、Cプロジェクトで静的解析を実行して、決して呼び出されない関数やコード行を見つけようとしています。私はこのプロジェクトをVisual Studio .NET for WindowsやLinux用gccを使ってビルドすることができます。私は私のためにこれを行うことができるいくつかの合理的なツールを見つけることを試みているが、これまで私は成功していない。私はStack Overflowに関する質問を読んでいます。すなわち、thisthisです。-Wunreachable-codeをgccで使用しようとしましたが、gccの出力はあまり役に立ちません。それは次の形式静的解析によってCプロジェクトで使用されていない関数を見つける

/home/adnan/my_socket.c: In function ‘my_sockNtoH32’: 
/home/adnan/my_socket.c:666: warning: will never be executed 

のですが、私はmy_socket.cにライン666を見たとき、それは)関数my_sockNtoH32(から呼び出されていること、他の関数の内部で実際だと、この特定のインスタンスに対して実行されませんが、実行されます他のいくつかの関数から呼び出されたとき。

私が必要とするのは、決して実行されないコードを見つけることです。誰かがこれで助けてもらえますか?

PS:管理者にこのタスク用のツールを購入させることはできませんので、フリー/オープンソースのツールに固執してください。

+0

これは、.netとどのような関係がありますか? –

+0

@phresnel:私が言ったように、VS .Netまたはgccのどちらかを使ってプロジェクトをビルドすることができます.VS .Netの静的解析ツールは私のためにも使えます – binW

+2

gccが "決して実行されません"と言うと、 、決して。 「実行されることはほとんどありません」とか、そうではありません。あなたはgccによってmisanalysedと思うコードの例を投稿してください。 –

答えて

1

GCCが「決して実行されない」と言うとき、それはそれを意味します。実際には、そのデッドコードを作成するバグがあるかもしれません。例えば、のようなもの:それはもちろん、具体的にすることはできませんコードを見ずに

if (a = 42) { 
    // some code 
} else { 
    // warning: unreachable code 
} 

666行にマクロがある場合、GCCはそのマクロの一部も参照する可能性があることに注意してください。

+1

私は死んだコードを取り除くと思うことさえあります... – rubenvb

+0

はい、高い最適化レベルでは、CFGの到達不能なエッジが整理され、デッドコードが排除されます。 – bdonlan

+1

この回答の*補足*はあなたが期待するものではありません。 GCCが「決して実行されない」と言っていないなら、あなたはそれが実際には死んでいないことを知らない。 GCCはこのコンパイル単位を見てもわかりません。詳細は私の答えを見てください。 –

3

GCCがあなたのために切断しない場合は、clang(正確には、static analyzer)を試してください。それはGCCよりはるかに良い静的解析を持っています(そして、より良い出力を生成します)。 AppleのXcodeで使われていますが、オープンソースであり、別途使用することができます。

0

GCCはの中でのコードを検索するのに役立ちます。複数のコンパイル単位に渡ってデッドコードが見つかると驚いています。コンパイル単位内の関数または変数のファイルレベルの宣言は、他のコンパイル単位がそれを参照する可能性があることを意味します。だから、ファイルのトップレベルで宣言されたものは、一度に1つのコンパイルユニットしか見ることができないため、GCCは排除できません。

問題はより困難になります。コンパイル単位Aが関数aを宣言し、コンパイル単位Bがaを呼び出す関数bを持つとします。死んでいる?それに直面して、いいえ。しかし実際には、それは依存します。 bが死んでいて、aへの唯一の参照がbにある場合、aも死んでいます。もし、aが死んでいるかどうかを判断するには、システム全体にわたってポイント・ツー・アナリシスが必要であり、aへのポインタが使用されているかどうかを調べる必要があります。 どこでも

このような正確な「死んだ」情報を取得するには、コンパイルユニット全体のグローバルビューが必要であり、ポイントツー分析を計算し、それに基づいてコールグラフを構築する必要がありますポイントツー分析。関数aはコールグラフ(木として、ルートとしてメインを持つ )がどこかを参照していない場合にのみ死んでいます。 (いくつかの注意点が必要です:実際の問題としては、分析が完全であれば、完全な点で分析されても、関数が死んでいると正しく認識されない場合もあります。 C関数の集合の外側、例えば、アセンブラコードのいくつかのビットからの呼び出し)。

スレッディングはこれを悪化させます。各スレッドにはおそらくコールDAGの先頭にあるルート関数があります。スレッドがどのように起動するかはCコンパイラによって定義されていないので、マルチスレッドのCアプリケーションにデッドコードがあるかどうかを判断するには、何らかの方法でスレッドルート関数にアナウンスを伝えるか、スレッド初期化プリミティブを探します。

正しい答えを得る方法については、多くの回答が得られていません。オープンソースではありませんが、C Front EndDMS Software Reengineering Toolkitには、Cパーサーを含むすべてのマシンが含まれています。control- and dataflow- analysis, local and global points-to analysis, and global call graph construction. DMSは、アセンブラからの外部呼び出しやスレッドルーツのリストなどの追加情報を簡単にカスタマイズできます。スレッド初期化の呼び出しである特定のソースパターンが含まれています。実際には、数百万行のコードを持つ大規模な組み込みエンジンコントローラでは簡単に(簡単に)行っています。 DMSは、このような呼び出しグラフを作成する目的で、2,600万行のコード(約18,000のコンパイル単位)のシステムに適用されています。

[興味深いのは別として、個々の翻訳単位を処理する際に、スケーリングの理由からDMSは、そのコンパイル単位で使用されていないシンボルおよび関連コードを実際に削除します。驚くべきことに、インクルードファイルネストで通常隠されている氷山を考慮に入れると、これは音量の約95%を取り除きます。それは、Cソフトウェアは通常、インクルードファイルをあまり因数分解していないと言います。 GCCのようなツールは、をコンパイルしながら、デッドコードを削除します。これは参考になりますが、デッドコードはコンパイルユニットのソースコードにはまだありません。開発者の注意を払っています(デッドコードかどうかは分かります)。プログラム変換モードのDMSは、いくつかのプリプロセッサの問題をモジユールに設定して、実際にそのデッドコードをソースから削除することができます。非常に大規模なソフトウェアシステムでは、実際に手作業で行う必要はありません。

関連する問題