コンピュータ科学において、プログラム解析[ 1 ]とは、コンピュータプログラムの正当性、堅牢性、安全性、活性などの特性に関して、プログラムの動作を分析するプロセスです。プログラム解析は、プログラムの最適化とプログラムの正当性という2つの主要な領域に焦点を当てています。前者は、リソース使用量を削減しながらプログラムのパフォーマンスを向上させることに焦点を当てており、後者は、プログラムが本来の目的どおりに動作することを保証することに焦点を当てています。
プログラム解析は、プログラムを実行せずに(静的プログラム解析)、実行時に(動的プログラム解析)、または両方を組み合わせて行うことができます。
プログラムの正確性の観点から、静的解析はプログラムの開発段階で脆弱性を発見することができます。[ 2 ]静的解析は脆弱性の根本原因にたどり着くため、これらの脆弱性はテスト段階で発見される脆弱性よりも修正が容易です。
静的解析の多くの手法は計算上決定不能であるため、その実行メカニズムが常に正しい結果で終了するとは限りません。これは、実際にはコードに問題があるにもかかわらず「問題なし」と表示される偽陰性、偽陽性、あるいは誤った結果を返すことはないものの決して終了しないといった事態につながる可能性があります。こうした制約があるにもかかわらず、静的解析は依然として有用です。前者のメカニズムは脆弱性の数を減らす可能性があり、後者のメカニズムは特定の種類の脆弱性が存在しないことを強く保証できる場合があるからです。
不適切な最適化は非常に望ましくない。そのため、プログラム最適化の文脈では、計算上決定不可能な解析に対処するための主な戦略が2つある。
しかし、 C言語のように仕様が完全に定められていない言語には、第三の戦略が適用される場合もあります。最適化コンパイラは、使用されている言語標準で意味論が規定されていないソースコードに遭遇した場合、実行時にクラッシュするなど、あらゆる動作をするコードを生成する自由があります。
制御フロー解析の目的は、プログラム実行中の様々な時点でどの関数が呼び出されるかに関する情報を取得することです。収集された情報は制御フローグラフ(CFG)で表され、ノードはプログラムの命令、エッジは制御の流れを表します。CFGはコードブロックとループを特定することで、コンパイラによる最適化の出発点となります。
データフロー解析は、プログラムの各ポイントにおける値とその時間経過に伴う変化に関する情報を収集するために設計された手法です。この手法は、コンパイラがコードを最適化する際によく使用されます。データフロー解析の最もよく知られた例の1つは、汚染チェックです。これは、ユーザーが提供したデータを含むすべての変数(「汚染されている」、つまり安全でないとみなされる)を考慮し、それらの変数がサニタイズされるまで使用できないようにするものです。この手法は、 SQLインジェクション攻撃を防ぐためによく使用されます。汚染チェックは、静的または動的に実行できます。
抽象解釈を用いることで、プログラムを実際に実行することなく、プログラムの実行結果に関する情報を抽出することが可能になります。この情報は、コンパイラが最適化の可能性を探したり、特定の種類のバグに対するプログラムの安全性を検証したりするために利用できます。
型システムは、特定の要件を満たすプログラムに型を関連付けます。その目的は、ある特性に基づいて正しいとみなされる言語のプログラム群を選択することです。
型チェックは、プログラミングオブジェクトの使用方法や実行可能な動作を制限するためにプログラミングで使用されます。これはコンパイラまたはインタプリタによって行われます。型チェックは、符号付き値が符号なし変数に割り当てられないようにすることで、脆弱性の防止にも役立ちます。型チェックは、静的(コンパイル時)、動的(実行時)、またはその両方の組み合わせで行うことができます。
静的な型情報(推論されたもの、またはソースコード内の型注釈によって明示的に提供されたもの)は、ボックス化された配列をボックス化されていない配列に置き換えるなどの最適化を行うためにも使用できます。
効果システムとは、関数やメソッドの実行によって生じる効果を表現するために設計された形式システムです。効果は、何が実行され、何を用いて実行されるかをコード化します。これらは通常、それぞれ効果の種類と効果領域と呼ばれます。
モデル検査とは、モデル(この文脈ではコードの形式モデルを指しますが、他の文脈ではハードウェアのモデルを指す場合もあります)が与えられた仕様に準拠しているかどうかを、厳密かつ形式的で自動化された方法でチェックする手法です。コードは本質的に有限状態であり、仕様とコードの両方が論理式に変換可能であるため、効率的なアルゴリズム的手法を用いてシステムが仕様に違反していないかどうかをチェックすることが可能です。
動的解析は、プログラムの実行時情報を利用して解析の精度を高めるとともに、実行時保護も提供できるが、問題の単一の実行しか解析できず、実行時チェックのためにプログラムのパフォーマンスが低下する可能性がある。
ソフトウェアは、その品質と、期待どおりに確実に動作すること、そして他のソフトウェアと競合しないことを保証するためにテストされるべきです。テストは、入力を与えてプログラムを実行し、その動作と出力を評価することによって行われます。セキュリティ要件が指定されていない場合でも、攻撃者がソフトウェアを改ざんして情報を盗み出したり、ソフトウェアの正常な動作を妨害したり、ソフトウェアを足がかりとしてユーザーを攻撃したりできないように、追加のセキュリティテストを実施する必要があります。
プログラム監視は、リソース使用量、イベント、相互作用など、プログラムに関するさまざまな情報を記録・ログ化し、異常動作の原因を特定するためにレビューできるようにします。さらに、セキュリティ監査にも利用できます。プログラムの自動監視は、ランタイム検証と呼ばれることもあります。
プログラムの動作の特定部分集合に対して、プログラムスライシングとは、選択した動作を依然として生成する最小限の形式にプログラムを縮小することです。縮小されたプログラムは「スライス」と呼ばれ、指定された動作部分集合の範囲内で元のプログラムを忠実に表現したものです。一般的に、スライスを見つけることは解決不可能な問題ですが、一連の変数の値によって対象となる動作部分集合を指定することで、データフローアルゴリズムを使用して近似スライスを取得することが可能です。これらのスライスは通常、開発者がデバッグ中にエラーの原因を特定するために使用します。