以下、本実施の形態を図面を参照して説明する。
[第1の実施の形態]
第1の実施の形態を説明する。
図1は、第1の実施の形態のプログラム分析装置の例を説明する図である。
第1の実施の形態のプログラム分析装置10は、シンボリック実行により分析対象プログラム13を分析し、実行パスのパス条件とパス出力の対応関係を示す全体ロジック情報19を生成する。プログラム分析装置10を、情報処理装置やコンピュータと言うこともできる。プログラム分析装置10は、クライアント装置でもよいしサーバ装置でもよい。
プログラム分析装置10は、記憶部11および処理部12を有する。記憶部11は、RAM(Random Access Memory)などの揮発性半導体メモリでもよいし、HDD(Hard Disk Drive)やフラッシュメモリなどの不揮発性ストレージでもよい。処理部12は、例えば、CPU(Central Processing Unit)、GPU(Graphics Processing Unit)、DSP(Digital Signal Processor)などのプロセッサである。ただし、処理部12は、ASIC(Application Specific Integrated Circuit)やFPGA(Field Programmable Gate Array)などの特定用途の電子回路を含んでもよい。プロセッサは、メモリ(記憶部11でもよい)に記憶されたプログラムを実行する。複数のプロセッサの集合を「マルチプロセッサ」または単に「プロセッサ」と言うことがある。
記憶部11は、分析対象プログラム13を記憶する。分析対象プログラム13は、高水準言語で記述されたソースコードでもよいし、ソースコードから変換されて中間言語で記述された中間コードでもよいし、機械可読なオブジェクトコードでもよい。
分析対象プログラム13は、モジュール14(第1のモジュール)とモジュール15(第2のモジュール)を含む。第2のモジュールは2つ以上あってもよい。モジュール15は、他のプログラム部品から呼び出し可能なプログラム部品であればよく、サブルーチン、関数、手続き、メソッドなどと呼ばれるものであってもよい。モジュール14は、呼び出し命令14a,14bなどの複数の呼び出し命令を含む。各呼び出し命令は、何れか1つの第2のモジュールを呼び出す命令である。呼び出し命令14a,14bは、同一の第2のモジュールを呼び出す命令でもよいし、異なる第2のモジュールを呼び出す命令でもよい。図1では、呼び出し命令14a,14bの呼び出し先はモジュール15である。呼び出し命令14aが先に実行され、その後に呼び出し命令14bが実行される。
処理部12は、シンボリック実行により、モジュール14の実行パスをモジュール15の処理部分も含めて分析する。ただし、モジュール14とモジュール15に跨がる実行パスを直接的に追跡しようとすると、多数の分岐命令によって多数の実行パスの候補が発生し、パス爆発によってシンボリック実行の計算量が非常に大きくなるおそれがある。そこで、処理部12は、分析対象プログラム13を複数の部分に分けてシンボリック実行を行い、複数の部分的結果を事後的に合成して全体の実行パスを再現する。
具体的には、処理部12は、呼び出し元のモジュール14と呼び出し先のモジュール15とを分けてシンボリック実行を行う。例えば、処理部12は、モジュール14の入力変数に対して、抽象的な入力値を示す入力シンボルを割り当て、その入力シンボルを用いてモジュール14の分析を開始する。また、処理部12は、モジュール15の入力変数に対して、モジュール14とは異なる抽象的な入力値を示す入力シンボルを割り当て、その入力シンボルを用いてモジュール15の分析を開始する。
モジュール14のシンボリック実行において、処理部12は、呼び出し命令14a,14bの実行結果それぞれに対して中間シンボルを割り当てる。例えば、処理部12は、呼び出し命令14aの実行結果に中間シンボルstubAを割り当て、呼び出し命令14bの実行結果に中間シンボルstubBを割り当てる。中間シンボルは、入力シンボルとは異なる一時的シンボルであり、スタブ値と言うこともできる。中間シンボルを用いることで、処理部12は、モジュール14の実行パスの続きとしてモジュール15を分析せずに、モジュール14のシンボリック実行を継続することができる。ある呼び出し命令の後は、その呼び出し命令の実行結果を示す中間シンボルを使用することができる。
このような複数の中間シンボルを含むシンボル群を用いたシンボリック実行を通じて、処理部12は、実行パスのパス条件とパス出力との対応関係を示す複数の部分ロジック情報を生成する。各部分ロジック情報は、分析対象プログラム13の1つの位置までの実行パスを表す。パス条件は、その実行パスが選択される条件であり、入力シンボルおよび中間シンボルの少なくとも一部を用いて記述されることがある。パス出力は、その実行パスが選択された場合のその位置における変数の値であり、入力シンボルおよび中間シンボルの少なくとも一部を用いて記述されることがある。
具体的には、処理部12は、呼び出し命令14a,14bの位置に対応する部分ロジック情報16a,16b(第1の部分ロジック情報)を生成する。例えば、部分ロジック情報16aは呼び出し命令14aの直前に対応し、部分ロジック情報16bは呼び出し命令14bの直前に対応する。例えば、部分ロジック情報16aでは、モジュール14の入力シンボルが用いられる。このシンボルを用いて、モジュール14の先頭から呼び出し命令14aの直前までの実行パスのパス条件と、呼び出し命令14aの直前での変数の値であるパス出力とが記述される。部分ロジック情報16bでは、モジュール14の入力シンボルと呼び出し命令14aの中間シンボルstubAの少なくとも1つが用いられる。このシンボルを用いて、モジュール14の先頭から呼び出し命令14bの直前までの実行パスのパス条件と、呼び出し命令14bの直前での変数の値であるパス出力とが記述される。
また、処理部12は、モジュール14の終了位置に対応する部分ロジック情報16c(第2の部分ロジック情報)を生成する。例えば、部分ロジック情報16cでは、モジュール14の入力シンボルと呼び出し命令14aの中間シンボルstubAと呼び出し命令14bの中間シンボルstubBの少なくとも1つが用いられる。このシンボルを用いて、モジュール14の先頭から終了位置までの実行パスのパス条件と、モジュール14の終了位置での変数の値であるパス出力とが記述される。また、処理部12は、モジュール15の終了位置に対応する部分ロジック情報17(第3の部分ロジック情報)を生成する。例えば、部分ロジック情報17では、モジュール15の入力シンボルが用いられる。このシンボルを用いて、モジュール15の先頭から終了位置までの実行パスのパス条件と、モジュール15の終了位置での変数の値であるパス出力とが記述される。
部分ロジック情報16cは、実行パスを抽出したいモジュール14の終了位置に対応するものの、最終的な分析結果から消去したい中間シンボルを含んでいることがある。そこで、処理部12は、以下のようにして中間シンボルを消去する。
処理部12は、部分ロジック情報16cで使用されている中間シンボルを検出する。例えば、部分ロジック情報16cでは、パス条件とパス出力の少なくとも一方の記述に、呼び出し命令14bの実行結果を示す中間シンボルstubBが使用されている。すると、処理部12は、検出した中間シンボルに対応するパス出力を含むシンボル定義ロジック情報18bを生成する。シンボル定義ロジック情報18bのパス出力は、検出した中間シンボルの定義に相当し、検出した中間シンボルに対して代入することが可能である。
シンボル定義ロジック情報18bの生成にあたり、処理部12は、検出した中間シンボルによって実行結果が表現された呼び出し命令14bに対応する部分ロジック情報16bを選択する。また、処理部12は、その呼び出し命令14bによって呼び出されるモジュール15に対応する部分ロジック情報17を選択する。処理部12は、選択した部分ロジック情報16bと部分ロジック情報17を合成することで、シンボル定義ロジック情報18bを生成する。部分ロジック情報16bのパス出力である変数の値は、部分ロジック情報17の入力シンボルである入力変数の値に相当する。また、部分ロジック情報17の出力パスである変数の値は、呼び出し命令14bの実行結果を示す中間シンボルに相当する。そこで、例えば、処理部12は、部分ロジック情報16bのパス出力を部分ロジック情報17の入力シンボルに代入することで、シンボル定義ロジック情報18bを生成する。
次に、処理部12は、シンボル定義ロジック情報18bで他の中間シンボルが使用されているか判定する。例えば、呼び出し命令14bよりも前に呼び出し命令14aが実行されるため、部分ロジック情報16bでは、呼び出し命令14aの実行結果を示す中間シンボルstubAが使用されている可能性がある。そのため、シンボル定義ロジック情報18bでは、中間シンボルstubAが使用されている可能性がある。
シンボル定義ロジック情報18bで他の中間シンボルが使用されている場合、処理部12は、シンボル定義ロジック情報18bと同様に、他の中間シンボルの検出と他のシンボル定義ロジック情報の生成とを繰り返す。例えば、処理部12は、他の中間シンボルが使用されていないシンボル定義ロジック情報が得られるまで、上記を再帰的に実行する。
例えば、シンボル定義ロジック情報18bでは、パス条件とパス出力の少なくとも一方の記述に、呼び出し命令14aの実行結果を示す中間シンボルstubAが使用されている。すると、処理部12は、中間シンボルstubAに対応するパス出力を含むシンボル定義ロジック情報18aを生成する。シンボル定義ロジック情報18aのパス出力は、中間シンボルstubAの定義に相当し、中間シンボルstubAに対して代入することが可能である。このとき、処理部12は、中間シンボルstubAによって実行結果が表現された呼び出し命令14aに対応する部分ロジック情報16aを選択する。また、処理部12は、その呼び出し命令14aによって呼び出されるモジュール15に対応する部分ロジック情報17を選択する。処理部12は、選択した部分ロジック情報16aと部分ロジック情報17を合成することで、シンボル定義ロジック情報18aを生成する。
次に、処理部12は、複数のシンボル定義ロジック情報を用いて、部分ロジック情報16cを、中間シンボルを含まない全体ロジック情報19に変換する。このとき、処理部12は、ある中間シンボルに、その中間シンボルを定義するシンボル定義ロジック情報のパス出力を代入することを、複数の中間シンボルについて連鎖的に行う。
例えば、処理部12は、シンボル定義ロジック情報18aのパス出力を、シンボル定義ロジック情報18bの中間シンボルstubAに代入する。これにより、シンボル定義ロジック情報18bから中間シンボルstubAが消去される。そして、処理部12は、中間シンボルstubAが消去されたシンボル定義ロジック情報18bのパス出力を、部分ロジック情報16cの中間シンボルstubBに代入する。これにより、部分ロジック情報16cから中間シンボルstubBが消去され、全体ロジック情報19になる。その結果、全体ロジック情報19は、中間シンボルstubA,stubBを用いずに、モジュール14の入力と出力の関係を表すロジック情報となる。
第1の実施の形態のプログラム分析装置10によれば、シンボリック実行によって、分析対象プログラム13の入力と出力の関係を表す全体ロジック情報19が生成される。よって、具体的な数値や文字などの具体的な入力値を次々に分析対象プログラム13に入力する動的分析よりも、分析対象プログラム13の挙動を効率的に分析することができる。
また、モジュール14がモジュール15を呼び出す場合に、モジュール14とモジュール15に対して独立にシンボリック実行が行われ、複数の部分ロジック情報が事後的に結合されて全体ロジック情報19が再現される。よって、モジュール14とモジュール15に跨がる実行パスを直接追跡する場合よりも、シンボリック実行で探索すべき実行パスが減少し、パス爆発を抑制してシンボリック実行の計算量を削減できる。
また、モジュール14の終了位置の部分ロジック情報16cを基点として、呼び出し命令14bの実行結果を示す中間シンボルが探索され、その中間シンボルを定義するシンボル定義ロジック情報18bが生成される。シンボル定義ロジック情報18bが他の中間シンボルを含む場合、他の中間シンボルに対応するシンボル定義ロジック情報が再帰的に生成される。そして、複数のシンボル定義ロジック情報を用いた代入処理により中間シンボルが消去され、部分ロジック情報16cから中間シンボルが消去される。
これにより、後の呼び出し命令の実行の有無が前の呼び出し命令の実行結果に依存するなど、複数の呼び出し命令の間に複雑な依存関係がある場合についても、事後的に複数の部分ロジック情報を合成して全体ロジック情報19を再現することが可能となる。
例えば、呼び出し命令の直前の部分ロジック情報を、呼び出し先のモジュールの部分ロジック情報と結合し、更に呼び出し命令の後の部分ロジック情報と結合するというように、モジュール14の実行順序に沿って結合を繰り返す方法も考えられる。しかし、複数の呼び出し命令の間に複雑な依存関係があると、そのような単純な合成方法ではモジュール14の終了位置において未消去の中間シンボルが残ってしまうことがある。これに対して、第1の実施の形態では、モジュール14の実行順序とは逆順に遡って、未解消の中間シンボルに対応するシンボル定義ロジック情報の生成が繰り返される。よって、中間シンボルを全て消去し、分析対象プログラム13の挙動を効率的に分析することが可能となる。
[第2の実施の形態]
次に、第2の実施の形態を説明する。
第2の実施の形態のプログラム分析装置は、シンボリック実行によってプログラムから実行パスを抽出し、入力と出力の関係を示すロジック表を生成する。第2の実施の形態のプログラム分析装置を、情報処理装置やコンピュータと言うこともできる。第2の実施の形態のプログラム分析装置は、クライアント装置でもよいしサーバ装置でもよい。
図2は、プログラム分析装置のハードウェア例を示すブロック図である。
プログラム分析装置100は、CPU101、RAM102、HDD103、画像インタフェース104、入力インタフェース105、媒体リーダ106および通信インタフェース107を有する。プログラム分析装置100の上記ユニットは、バスに接続されている。なお、プログラム分析装置100は、第1の実施の形態のプログラム分析装置10に対応する。CPU101は、第1の実施の形態の処理部12に対応する。RAM102またはHDD103は、第1の実施の形態の記憶部11に対応する。
CPU101は、プログラムの命令を実行するプロセッサである。CPU101は、HDD103に記憶されたプログラムやデータの少なくとも一部をRAM102にロードし、プログラムを実行する。なお、CPU101は複数のプロセッサコアを備えてもよく、プログラム分析装置100は複数のプロセッサを備えてもよい。複数のプロセッサの集合を「マルチプロセッサ」または単に「プロセッサ」と言うことがある。
RAM102は、CPU101が実行するプログラムやCPU101が演算に使用するデータを一時的に記憶する揮発性の半導体メモリである。なお、プログラム分析装置100は、RAM以外の種類のメモリを備えてもよく、複数のメモリを備えてもよい。
HDD103は、OS(Operating System)やミドルウェアやアプリケーションソフトウェアなどのソフトウェアのプログラム、および、データを記憶する不揮発性ストレージである。なお、プログラム分析装置100は、フラッシュメモリやSSD(Solid State Drive)など他の種類のストレージを備えてもよく、複数のストレージを備えてもよい。
画像インタフェース104は、CPU101からの命令に従って、プログラム分析装置100に接続された表示装置111に画像を出力する。表示装置111として、CRT(Cathode Ray Tube)ディスプレイ、液晶ディスプレイ(LCD:Liquid Crystal Display)、有機EL(OEL:Organic Electro-Luminescence)ディスプレイ、プロジェクタなど、任意の種類の表示装置を使用することができる。また、プログラム分析装置100に、プリンタなど表示装置111以外の出力デバイスが接続されてもよい。
入力インタフェース105は、プログラム分析装置100に接続された入力デバイス112から入力信号を受け付ける。入力デバイス112として、マウス、タッチパネル、タッチパッド、キーボードなど、任意の種類の入力デバイスを使用することができる。また、プログラム分析装置100に複数種類の入力デバイスが接続されてもよい。
媒体リーダ106は、記録媒体113に記録されたプログラムやデータを読み取る読み取り装置である。記録媒体113として、フレキシブルディスク(FD:Flexible Disk)やHDDなどの磁気ディスク、CD(Compact Disc)やDVD(Digital Versatile Disc)などの光ディスク、半導体メモリなど、任意の種類の記録媒体を使用することができる。媒体リーダ106は、例えば、記録媒体113から読み取ったプログラムやデータを、RAM102やHDD103などの他の記録媒体にコピーする。読み取られたプログラムは、例えば、CPU101によって実行される。なお、記録媒体113は可搬型記録媒体であってもよく、プログラムやデータの配布に用いられることがある。また、記録媒体113やHDD103を、コンピュータ読み取り可能な記録媒体と言うことがある。
通信インタフェース107は、ネットワーク114に接続され、他の情報処理装置と通信する。通信インタフェース107は、スイッチやルータなどの有線通信装置に接続される有線通信インタフェースでもよいし、基地局やアクセスポイントなどの無線通信装置に接続される無線通信インタフェースでもよい。
次に、シンボリック実行によるプログラムの分析について説明する。
図3は、プログラムの例を示す図である。
プログラム131は、分析対象のプログラムの一例である。プログラム131は、変数「性別」の値として2文字の文字列を受け取り、変数「出力」の値として1文字を出力する。プログラム131は、14行目に1番目の条件分岐を含み、19行目に2番目の条件分岐を含む。14行目の条件分岐では、変数「性別」の値が「男性」であるか判定される。変数「性別」の値が「男性」である場合には変数「出力」の値が「M」に更新され、そうでない場合には変数「出力」の値が「 」(空白)に更新される。19行目の条件分岐では、変数「性別」の値が「女性」であるか判定される。変数「性別」の値が「女性」である場合には変数「出力」の値が「F」に更新され、そうでない場合には変数「出力」の値は変化しない。そして、プログラム131が終了する。
プログラム131には3つの実行パスが存在する。入力である変数「性別」の値に応じて、これら3つの実行パスのうちの何れか1つが実行される。変数「性別」の値が「男性」である場合、14行目の条件判定がYESとなり、19行目の条件判定がNOとなる。この実行パスでは、変数「出力」の値は「M」になる。変数「性別」の値が「女性」である場合、14行目の条件判定がNOとなり、19行目の条件判定がYESとなる。この実行パスでは、変数「出力」の値は「F」になる。変数「性別」の値が「男性」でも「女性」でもない場合、14行目の条件判定と19行目の条件判定の両方がNOとなる。この実行パスでは、変数「出力」の値は「 」(空白)になる。
プログラム131は直列の2つの条件分岐を含むため、条件の内容を無視すれば、実行パスの候補は4つ存在する。しかし、変数「性別」の値が「男性」であることと変数「性別」の値が「女性」であることは矛盾するため、14行目の条件判定と19行目の条件判定の両方がYESになることはない。よって、4つの実行パスの候補のうち、実行される可能性のある有効な実行パスは3つである。
条件分岐において、ある分岐方向(YES方向またはNO方向)に進むための条件を満たす変数の値が少なくとも1つ存在するとき、その分岐方向は「充足可能である」と言うことができる。一方、ある分岐方向に進むための条件を満たす変数の値が1つも存在しないとき、その分岐方向は「充足可能でない」と言うことができる。
プログラム131において、14行目の条件分岐では変数「性別」の値は制約されていないため、2つの分岐方向は共に充足可能である。一方、19行目の条件分岐における充足可能性は、14行目の条件分岐で選択した分岐方向に依存する。14行目のYES方向を選択した場合、19行目のYES方向は充足可能でなくNO方向のみ充足可能となる。14行目のNO方向を選択した場合、19行目の2つの分岐方向は共に充足可能である。
ここで、プログラム131に対するシンボリック実行の例を説明する。プログラム分析装置100は、プログラム131の入力を示す変数「性別」に、具体的な文字ではなく任意の定数を示す抽象的なシンボル(記号値)を割り当てる。ここでは、変数名と同じ「性別」をシンボルとして用いる。プログラム分析装置100は、シンボルを用いてプログラム131の命令を擬似的に実行していく。
プログラム131の始点から14行目の条件分岐の前までは、実行パスの分岐は存在しない。14行目の条件分岐について、この時点ではその実行パスが選択される条件(パス条件)は存在せず、2つの分岐方向は共に充足可能である。よって、プログラム分析装置100は、14行目の条件分岐において実行パスを分割し、一方の実行パスを選択する。ここでは、プログラム分析装置100はYES方向の実行パスを選択したとする。
次に、19行目の条件分岐について、この時点におけるパス条件はシンボル「性別」が「男性」であることであるため、YES方向は充足可能でなくNO方向は充足可能である。よって、プログラム分析装置100はNO方向を選択する。その後、この1番目の実行パスは終了する。プログラム分析装置100は、1番目の実行パスのパス条件を、シンボル「性別」が「男性」でありかつシンボル「性別」が「女性」でないと判定する。また、プログラム分析装置100は、1番目の実行パスの処理結果(パス出力)を、変数「出力」の値が「M」であると判定する。
1番目の実行パスが終了すると、プログラム分析装置100は、実行パスの直近の分割点まで戻り、未選択の実行パスを選択する。ここでは、プログラム分析装置100は、14行目の条件分岐まで戻ってNO方向の実行パスを選択する。
19行目の条件分岐について、この時点におけるパス条件はシンボル「性別」が「男性」でないことであるため、YES方向とNO方向の何れも充足可能である。よって、プログラム分析装置100は、19行目の条件分岐文において実行パスを更に分割し、一方の実行パスを選択する。ここでは、プログラム分析装置100はYES方向の実行パスを選択したとする。その後、この2番目の実行パスは終了する。プログラム分析装置100は、2番目の実行パスのパス条件を、シンボル「性別」が「男性」でなくかつシンボル「性別」が「女性」であると判定する。また、プログラム分析装置100は、2番目の実行パスのパス出力を、変数「出力」の値が「F」であると判定する。
2番目の実行パスが終了すると、プログラム分析装置100は、19行目の条件分岐まで戻ってNO方向の実行パスを選択する。その後、この3番目の実行パスは終了する。プログラム分析装置100は、3番目の実行パスのパス条件を、シンボル「性別」が「男性」でなくかつシンボル「性別」が「女性」でないと判定する。また、プログラム分析装置100は、3番目の実行パスのパス出力を、変数「出力」の値が「 」(空白)であると判定する。そして、未選択の実行パスが存在しないためシンボリック実行が終了する。
なお、プログラム分析装置100は、実行パスの分割点において、その時点のパス条件と各変数の値を保存しておく。プログラム分析装置100は、1つの実行パスが終了して分割点までバックトラックしたとき、保存しておいたパス条件と各変数の値を引き継いで、未選択の分岐方向に対応する他の実行パスの探索を続ける。
図4は、ロジック表の例を示す図である。
プログラム分析装置100は、プログラム131のシンボリック実行の結果として、ロジック表132を生成する。プログラム分析装置100は、例えば、生成したロジック表132を、プログラム分析装置100が有する表示装置111に表示する。
ロジック表132は、プログラム131の入力とプログラム131の出力との関係(ロジック)を示す。ロジック表132は、パス番号、パス条件およびパス出力の項目を含む。パス番号の項目には、シンボリック実行によって検出された実行パスの識別番号が登録される。パス条件の項目には、実行パスが選択されるための入力の条件が記載される。パス出力の項目には、実行パスの終点における出力変数の値が記載される。パス条件およびパス出力は、シンボルを用いて表されることがある。
前述のように、1番目の実行パスのパス条件は、「性別が男性である」かつ「性別が女性でない」ことである。これは、「性別が男性である」と簡約化できる。1番目の実行パスのパス出力は、「出力がMである」ことである。2番目の実行パスのパス条件は、「性別が男性でない」かつ「性別が女性である」ことである。これは、「性別が女性である」と簡約化できる。2番目の実行パスのパス出力は、「出力がFである」ことである。3番目の実行パスのパス条件は、「性別が男性でない」かつ「性別が女性でない」ことである。3番目の実行パスのパス出力は、「出力が空白である」ことである。
なお、条件分岐における充足可能性の判定やパス条件の簡約化には、数式処理技術を利用することができる。プログラム分析装置100は、SMT(Satisfiability Modulo Theories)ソルバやSAT(Satisfiability)ソルバを利用してもよい。パス条件は、例えば、シンボルを含む式をシンボルについて解くことで簡約化できる。
次に、サブルーチン呼び出しを含むプログラムの分析について説明する。
図5は、サブルーチンを含むプログラムの例を示す図である。
プログラム133は、分析対象のプログラムの一例である。プログラム133は、セクション1およびセクション2の2つのモジュールを含む。セクション1は、セクション2を呼び出す呼び出し元モジュールであり、セクション2は、セクション1から呼び出される呼び出し先モジュールである。第2の実施の形態では、セクション1を呼び出し元ルーチンと言うことがあり、セクション2をサブルーチンと言うことがある。なお、セクション1やセクション2を、関数、手続き、メソッドなどと言うこともできる。
セクション1は、実行開始時に「変数」に格納されている数値を入力として受け取り、「変数」を更新することで出力としての数値を「変数」に格納する。セクション2は、呼び出された時点で「変数」に格納されている数値を入力として受け取り、「変数」を更新することで出力としての数値を「変数」に格納する。
セクション1は、17行目に条件分岐を含む。17行目の条件分岐では、その時点の「変数」が1000より大きいか判定される。「変数」が1000より大きければ「変数」に1が加算され、「変数」が1000以下であれば「変数」から1が減算される。また、セクション1は、23行目にセクション2を呼び出すサブルーチン呼び出しを含む。
また、セクション1は、25行目に条件分岐を含み、26行目にセクション2を呼び出すサブルーチン呼び出しを含む。25行目の条件分岐では、その時点の「変数」が3000未満か判定される。「変数」が3000未満であれば、26行目のサブルーチン呼び出しが実行され、その後に「変数」に2が加算される。「変数」が3000以上であれば、「変数」から2が減算される。そして、セクション1が終了する。
セクション2は、35行目に条件分岐を含む。35行目の条件分岐では、その時点の「変数」が2000より大きいか判定される。「変数」が2000より大きければ「変数」に3が加算され、「変数」が2000以下であれば「変数」から3が減算される。
プログラム133のセクション1が分析範囲に指定された場合、セクション1のパス出力はセクション2の実行結果に依存することから、プログラム分析装置100は、セクション1と共にセクション2も分析することになる。セクション1とセクション2を通じたロジックは以下のようになる。入力値が1000以下の場合、出力値は入力値-5である。入力値が1000より大きく1999以下の場合、出力値は入力値-3である。入力値が1999より大きく2996未満の場合、出力値は入力値+9である。入力値が2996以上の場合、出力値は入力値+2である。
ここで、サブルーチン呼び出しを含むプログラムのロジック表をシンボリック実行により生成しようとする場合、単純な方法として、呼び出し元ルーチンとサブルーチンに跨がって一続きに実行パスを追跡する方法が考えられる。しかし、実行パスの候補は条件分岐の数に対して指数関数的に増加するため、このような単純なシンボリック実行では実行パスの候補が非常に多くなるパス爆発の問題が生じる。
そこで、プログラム分析装置100は、分析対象のプログラムを複数の部分に分けてシンボリック実行を行い、複数のシンボリック実行の結果を示す複数の部分ロジック表を事後的に合成して本来のロジック表を再現する。
具体的には、プログラム分析装置100は、呼び出し元ルーチンの始点からシンボリック実行を開始し、次のサブルーチン呼び出しの直前で、その時点のパス条件とパス出力を示す部分ロック表を生成する。このとき、プログラム分析装置100は、呼び出し元ルーチンとサブルーチンの分析を分離するため、サブルーチンによって更新され得る変数に新たなシンボルとしてスタブ値を割り当てる。プログラム分析装置100は、スタブ値を用いることで、サブルーチンを実行せずに呼び出し元ルーチンのシンボリック実行を継続することができる。プログラム分析装置100は、サブルーチン呼び出しに到達する毎に、その時点の部分ロック表の生成とスタブ値の割り当てを行う。最後に、プログラム分析装置100は、呼び出し元ルーチンの終点の部分ロック表を生成する。また、プログラム分析装置100は、呼び出し元ルーチンとは独立にサブルーチンに対してシンボリック実行を行い、サブルーチンの終点の部分ロック表を生成する。
図6は、部分ロジック表の例を示す図である。
前述のプログラム133からは、部分ロジック表134-1,134-2,134-3,134-4の4つの部分ロジック表が生成される。
プログラム分析装置100は、セクション1の始点で、「変数」に格納される入力値を表すシンボルを割り当てる。第2の実施の形態では、セクション1の始点のシンボルとして、変数名と同じ「変数」を用いている。プログラム分析装置100は、セクション1の始点から23行目のサブルーチン呼び出しの直前までシンボリック実行を行い、その途中点のロジックを示す部分ロジック表134-1を生成する。部分ロジック表134-1のパス出力は、23行目のサブルーチン呼び出しの直前の「変数」の値を示す。部分ロジック表134-1は、入力値が1000より大きい場合はパス出力が入力値+1であり、入力値が1000以下の場合はパス出力が入力値-1であることを示している。
また、プログラム分析装置100は、23行目のサブルーチン呼び出しによって更新され得る「変数」に、スタブ値として「変数_Perform_23_セクション2_1」を割り当てる。第2の実施の形態では、スタブ値は、変数名と呼び出し命令名と行番号と呼び出し先サブルーチン名と呼び出し回数とを結合した文字列である。呼び出し回数は、サブルーチン呼び出しがループに属する場合に、同じ呼び出し命令の複数回の実行を互いに区別するための数字である。ただし、これらの情報を後で特定することができればよく、スタブ値のフォーマットはこれに限定されない。
次に、プログラム分析装置100は、23行目のスタブ値を用いてセクション1のシンボリック実行を継続する。プログラム分析装置100は、26行目のサブルーチン呼び出しの直前までシンボリック実行を行い、その途中点のロジックを示す部分ロジック表134-2を生成する。部分ロジック表134-2のパス出力は、26行目のサブルーチン呼び出しの直前の「変数」の値を示す。部分ロジック表134-2は、23行目のスタブ値が3000未満の場合はパス出力が当該スタブ値のままであることを示している。また、プログラム分析装置100は、26行目のサブルーチン呼び出しによって更新され得る「変数」に、スタブ値「変数_Perform_26_セクション2_1」を割り当てる。
次に、プログラム分析装置100は、23行目のスタブ値および26行目のスタブ値を用いてセクション1のシンボリック実行を継続する。呼び出し元ルーチンのシンボリック実行では、実行箇所より前で定義された始点のシンボルおよび全てのスタブ値を使用することが可能である。プログラム分析装置100は、セクション1の終点までシンボリック実行を行い、終点のロジックを示す部分ロジック表134-3を生成する。部分ロジック表134-3は、23行目のスタブ値が3000以上の場合は、パス出力が23行目のスタブ値-2であり、23行目のスタブ値が3000未満の場合は、パス出力が26行目のスタブ値+2であることを示している。
また、プログラム分析装置100は、セクション2の始点で、「変数」に格納されている入力値を表すシンボルを割り当てる。プログラム分析装置100は、セクション2の始点から終点までシンボリック実行を行い、終点のロジックを示す部分ロジック表134-4を生成する。部分ロジック表134-4は、入力値が2000より大きい場合はパス出力が入力値+3であり、入力値が2000以下の場合はパス出力が入力値-3であることを示している。セクション2のシンボリック実行は、セクション1のシンボリック実行の後で行ってもよいし、セクション1のシンボリック実行の前で行ってもよいし、セクション1のシンボリック実行の途中で割り込んで行うこともできる。
このようにして生成された複数の部分ロジック表を合成することで、本来のロジック表を再現することができる。あるサブルーチン呼び出しの直前のパス出力は、サブルーチンの入力値のシンボルに対応する。そこで、プログラム分析装置100は、サブルーチン呼び出しの直前の部分ロジック表が示すパス出力を、サブルーチンの部分ロジック表に含まれるシンボルに代入することで、この2つの部分ロジック表のロジックを結合することができる。また、サブルーチンのパス出力は、サブルーチン呼び出しの直後のスタブ値に対応する。そこで、プログラム分析装置100は、サブルーチンの部分ロジック表が示すパス出力を、サブルーチン呼び出しの後の部分ロジック表に含まれるスタブ値に代入することで、この2つの部分ロジック表のロジックを結合することができる。
ただし、複数回のサブルーチン呼び出しを含むプログラムの場合、どの様に複数の部分ロジック表を合成すればよいかが問題となる。後のサブルーチン呼び出しの実行の有無が前のサブルーチン呼び出しの結果に依存する場合など、複数のサブルーチン呼び出しの間に複雑な依存関係が存在する場合がある。その場合、プログラムの実行順序に沿って前方から順に部分ロジック表を結合していく単純な方法では、複数のサブルーチン呼び出しに対応する複数のスタブ値の全てを消去できないことがある。
例えば、部分ロジック表134-1のパス出力を部分ロジック表134-4のシンボル「変数」に代入することで、23行目のサブルーチン呼び出しの直後のロジックを示す中間ロジック表が生成される。この中間ロジック表のパス出力を部分ロジック表134-2のスタブ値「変数_Perform_23_セクション2_1」に代入することで、26行目のサブルーチン呼び出しの直前のロジックを示す中間ロジック表が生成される。この中間ロジック表からは、23行目のスタブ値が消去されている。
この中間ロジック表のパス出力を部分ロジック表134-4のシンボル「変数」に代入することで、26行目のサブルーチン呼び出しの直後のロジックを示す中間ロジック表が生成される。この中間ロジック表のパス出力を部分ロジック表134-3のスタブ値「変数_Perform_26_セクション2_1」に代入することで、セクション1の終点のロジックを示すロジック表が生成される。しかし、このロジック表からは、26行目のスタブ値が消去されているものの、23行目のスタブ値が残っている。このように、スタブ値の1回の定義と1回の参照が単純に繰り返される場合でない複雑な依存関係が存在すると、単純な合成方法では全てのスタブ値を消去できないことがある。
そこで、プログラム分析装置100は、以下に説明する方法で複数の部分ロジック表を合成する。まず、プログラム分析装置100は、復元したいロジックの位置に対応する部分ロジック表(復元対象の部分ロジック表)を基点として選択する。復元対象の部分ロジック表は、通常、分析範囲の終点における部分ロジック表である。例えば、図6においてプログラム133のセクション1が分析範囲に指定されている場合、セクション1の終点に対応する部分ロジック表134-3が復元対象の部分ロジック表として選択される。
次に、プログラム分析装置100は、復元対象の部分ロジック表に含まれるスタブ値を検索し、そのスタブ値に代入されるべきパス出力を含むスタブ値ロジック表を生成する。スタブ値ロジック表は、そのスタブ値が割り当てられたサブルーチン呼び出しの直前の部分ロジック表とサブルーチンの部分ロジック表とから生成される。プログラム分析装置100は、サブルーチン呼び出しの直前の部分ロジック表のパス出力をサブルーチンの部分ロジック表のシンボルに代入することで、スタブ値ロジック表を生成する。スタブ値ロジック表は、サブルーチン呼び出しの直後のロジックを表現したものであると言える。
次に、プログラム分析装置100は、生成したスタブ値ロジック表に他のスタブ値が含まれているか判断する。生成したスタブ値ロジック表に他のスタブ値が含まれている場合、プログラム分析装置100は、他のスタブ値に代入されるべきパス出力を含む他のスタブ値ロジック表を生成する。他のスタブ値ロジック表は、他のスタブ値が割り当てられたサブルーチン呼び出しの直前の部分ロジック表とサブルーチンの部分ロジック表とから生成される。プログラム分析装置100は、生成したスタブ値ロジック表に他のスタブ値が含まれなくなるまで、再帰的にスタブ値ロジック表を生成する。
次に、プログラム分析装置100は、スタブ値ロジック表の生成とは逆順に、一方のスタブ値ロジック表のパス出力を他方のスタブ値ロジック表のスタブ値に代入することで、スタブ値を消去していく。まず、プログラム分析装置100は、他のスタブ値を含まない末端のスタブ値ロジック表のパス出力を、その前段のスタブ値ロジック表のスタブ値に代入することで、後者のスタブ値ロジック表からスタブ値を消去する。他のスタブ値が消去されたスタブ値ロジック表は、2つのスタブ値ロジック表のロジックを結合したものであると言える。すると、プログラム分析装置100は、他のスタブ値が消去されたスタブ値ロジック表のパス出力を、更にその前段のスタブ値ロジック表のスタブ値に代入する。
プログラム分析装置100は、復元対象の部分ロジック表の直前まで上記を繰り返す。これにより、復元対象の部分ロジック表に含まれるスタブ値に対して、他のスタブ値が消去されたスタブ値ロジック表が生成される。最後に、プログラム分析装置100は、他のスタブ値が消去されたスタブ値ロジック表のパス出力を、復元対象の部分ロジック表のスタブ値に代入することで、本来のロジック表を再現する。
このように、プログラム分析装置100は、復元対象の部分ロジック表を基点として、プログラムの実行順序とは逆順に、スタブ値を消去するためのロジックを再帰的に探索する。そして、プログラム分析装置100は、探索された一連のロジックを探索順序とは逆順に結合していくことで、スタブ値を含まないロジックを再現する。これにより、複数のスタブ値に対応する複数のサブルーチン呼び出しの間に複雑な依存関係があっても、複数の部分ロジック表から本来のロジック表を生成することができる。なお、プログラム133のセクション1に含まれる複数のサブルーチン呼び出しは、同一のサブルーチンを呼び出しているが、上記の議論は異なるサブルーチンを呼び出す場合にも当てはまる。
以下では、プログラム133に対するロジック表の生成手順例を説明する。
図7は、スタブ値ロジック表の第1の例を示す図である。
復元対象の部分ロジック表134-3は、「変数_Perform_23_セクション2_1」と「変数_Perform_26_セクション2_1」の2つのスタブ値を含む。そこで、まず、プログラム分析装置100は、スタブ値「変数_Perform_23_セクション2_1」に対応するスタブ値ロジック表を生成する。
前述のように、第2の実施の形態のスタブ値は、変数名と呼び出し命令名と行番号と呼び出し先サブルーチン名と呼び出し回数とを結合した文字列である。スタブ値ロジック表の生成に用いる2つの部分ロジック表は、スタブ値に含まれるこれらの情報に基づいて特定することができる。プログラム分析装置100は、行番号と呼び出し先サブルーチン名と呼び出し回数から、サブルーチン呼び出しの直前の部分ロジック表を選択し、呼び出し先サブルーチン名から、サブルーチンの部分ロジック表を選択する。
ここでは、プログラム分析装置100は、セクション2を呼び出す23行目のサブルーチン呼び出しについて、サブルーチン呼び出しの直前の部分ロジック表134-1とサブルーチンの部分ロジック表134-4を選択する。
プログラム分析装置100は、選択した2つの部分ロジック表の間で、一方の部分ロジック表に含まれる複数の実行パス(複数のレコード)と他方の部分ロジック表に含まれる複数の実行パス(複数のレコード)とを結合する。一方の部分ロジック表の1つの実行パスと他方の部分ロジック表の1つの実行パスの組から、結合後の1つの実行パスが生成され得る。プログラム分析装置100は、サブルーチン呼び出しの直前の部分ロジック表から1つの実行パスを選択し、サブルーチンの部分ロジック表から1つの実行パスを選択する。プログラム分析装置100は、前者の実行パスのパス出力を後者の実行パスのシンボルに代入する。プログラム分析装置100は、前者の実行パスのパス条件とシンボル代入後の後者の実行パスのパス条件の論理積(AND)を、結合後のパス条件と定義し、シンボル代入後の後者の実行パスのパス出力を、結合後のパス出力と定義する。
網羅的な組み合わせにより、最大で、一方の部分ロジック表の実行パス数と他方の部分ロジック表の実行パス数の積だけ結合後の実行パスが生じる。ただし、結合後のパス条件が充足可能でない場合、その実行パスは採用されずに破棄される。
ここでは、プログラム分析装置100は、部分ロジック表134-1の1番目の実行パスと部分ロジック表134-4の1番目の実行パスを選択する。プログラム分析装置100は、前者のパス出力「変数+1」を、後者のパス条件のシンボル「変数」およびパス出力のシンボル「変数」に代入する。前者のパス条件とシンボル代入後の後者のパス条件の論理積は、「変数」が1000より大きくかつ「変数+1」が2000より大きいことである。これを簡約化すると、結合後のパス条件は、「変数+1」が2000より大きいこととなる。結合後のパス出力は、「変数+1+3」となる。
同様に、プログラム分析装置100は、部分ロジック表134-1の2番目の実行パスと部分ロジック表134-4の1番目の実行パスを選択する。ただし、この2つの実行パスから算出されるパス条件は、「変数」が1000以下かつ「変数-1」が2000より大きいこととなり、充足可能でない。よって、この2つの実行パスの組は採用されない。
また、プログラム分析装置100は、部分ロジック表134-1の1番目の実行パスと部分ロジック表134-4の2番目の実行パスを選択する。結合後のパス条件は、「変数」が1000より大きくかつ「変数+1」が2000以下であり、結合後のパス出力は、「変数+1-3」となる。また、プログラム分析装置100は、部分ロジック表134-1の2番目の実行パスと部分ロジック表134-4の2番目の実行パスを選択する。結合後のパス条件は、「変数」が1000以下かつ「変数-1」が2000以下である。これを簡約化すると、結合後のパス条件は、「変数」が1000以下となる。結合後のパス出力は、「変数-1-3」となる。
プログラム分析装置100は、上記の結合後の3つの実行パスを含むスタブ値ロジック表135-1を生成する。このとき、スタブ値ロジック表135-1が示すパス出力は、23行目のサブルーチン呼び出しの直後の変数の値であり、23行目のサブルーチン呼び出しに対して割り当てられたスタブ値に相当する。そこで、プログラム分析装置100は、スタブ値ロジック表135-1のパス出力の左辺をスタブ値に書き換えておく。ここでは、パス出力の左辺が「変数_Perform_23_セクション2_1」となる。
スタブ値ロジック表135-1は、23行目のサブルーチン呼び出しのスタブ値以外の他のスタブ値を含まず、復元対象の部分ロジック表134-3に対してこのまま適用することが可能である。よって、他のスタブ値ロジック表の再帰的な生成は不要である。
図8は、スタブ値ロジック表の第2の例を示す図である。
前述のように、復元対象の部分ロジック表134-3は、「変数_Perform_23_セクション2_1」と「変数_Perform_26_セクション2_1」の2つのスタブ値を含む。そこで、図7と同様、プログラム分析装置100は、スタブ値「変数_Perform_26_セクション2_1」に対応するスタブ値ロジック表を生成する。
プログラム分析装置100は、セクション2を呼び出す26行目のサブルーチン呼び出しについて、サブルーチン呼び出しの直前の部分ロジック表134-2とサブルーチンの部分ロジック表134-4を選択する。プログラム分析装置100は、部分ロジック表134-2,134-4からスタブ値ロジック表135-2を生成する。
スタブ値ロジック表135-2は、2つの実行パスを含む。スタブ値ロジック表135-2の1番目の実行パスは、部分ロジック表134-2の1番目の実行パスと部分ロジック表134-4の1番目の実行パスから生成される。パス条件は、「変数_Perform_23_セクション2_1」が3000未満かつ「変数_Perform_23_セクション2_1」が2000より大きいことである。パス出力は、「変数_Perform_23_セクション2_1+3」である。スタブ値ロジック表135-2の2番目の実行パスは、部分ロジック表134-2の1番目の実行パスと部分ロジック表134-4の2番目の実行パスから生成される。パス条件は、「変数_Perform_23_セクション2_1」が3000未満かつ「変数_Perform_23_セクション2_1」が2000以下である。これを簡約化すると、パス条件は、「変数_Perform_23_セクション2_1」が2000以下となる。パス出力は、「変数_Perform_23_セクション2_1-3」である。
プログラム分析装置100は、スタブ値ロジック表135-2のパス出力の左辺をスタブ値「変数_Perform_26_セクション2_1」に書き換えておく。
ここで、スタブ値ロジック表135-2は、26行目のサブルーチン呼び出しのスタブ値以外に、23行目のサブルーチン呼び出しのスタブ値を含み、復元対象の部分ロジック表134-3に対してこのままでは適用することができない。よって、プログラム分析装置100は、他のスタブ値ロジック表の再帰的な生成を行う。ただし、23行目のサブルーチン呼び出しに対応するスタブ値ロジック表は、前述のスタブ値ロジック表135-1であり、生成済みのスタブ値ロジック表135-1を流用できる。これにより、プログラム分析装置100は、スタブ値ロジック表の生成を終了する。なお、スタブ値ロジック表135-2を生成した時点でスタブ値ロジック表135-1が未生成である場合、プログラム分析装置100は、再帰的にスタブ値ロジック表135-1を生成することになる。
図9は、スタブ値消去の第1の例を示す図である。
消去すべきスタブ値毎のスタブ値ロジック表が全て揃うと、プログラム分析装置100は、スタブ値ロジック表に含まれる他のスタブ値の消去を開始する。当初から他のスタブ値を含まない末端のスタブ値ロジック表またはスタブ値消去により他のスタブ値を含まなくなったスタブ値ロジック表のロジックと、その前段のスタブ値ロジック表のロジックとが結合される。2つのスタブ値ロジック表を用いたスタブ値消去は、前述の2つの部分ロジック表を用いたスタブ値ロジック表の生成と同様の方法で行うことができる。
ただし、スタブ値ロジック表の生成では、サブルーチン呼び出しの直前の部分ロジック表が代入元ロジック表であり、サブルーチンの部分ロジック表が代入先ロジック表である。これに対して、スタブ値消去では、消去したいスタブ値を定義しており他のスタブ値を参照していないスタブ値ロジック表が代入元ロジック表であり、消去したいスタブ値を参照しているスタブ値ロジック表が代入先ロジック表である。
ここでは、プログラム分析装置100は、スタブ値「変数_Perform_23_セクション2_1」について、そのスタブ値を定義するスタブ値ロジック表135-1とそのスタブ値を参照するスタブ値ロジック表135-2を選択する。プログラム分析装置100は、スタブ値ロジック表135-2からスタブ値「変数_Perform_23_セクション2_1」が消去されたスタブ値ロジック表135-3を合成する。
スタブ値ロジック表135-3は、3つの実行パスを含む。スタブ値ロジック表135-3の1番目の実行パスは、スタブ値ロジック表135-1の1番目の実行パスとスタブ値ロジック表135-2の1番目の実行パスから生成される。パス条件は、「変数+1」が2000以上かつ「変数+1+3」が3000未満かつ「変数+1+3」が2000より大きいことである。これを簡約化すると、パス条件は、「変数+1」が2000以上かつ「変数+1+3」が3000未満となる。パス出力は、「変数+1+3+3」である。
スタブ値ロジック表135-3の2番目の実行パスは、スタブ値ロジック表135-1の2番目の実行パスとスタブ値ロジック表135-2の2番目の実行パスから生成される。パス条件は、「変数」が1000より大きくかつ「変数+1」が2000以下かつ「変数+1-3」が2000以下である。これを簡約化すると、パス条件は、「変数」が1000より大きくかつ「変数+1」が2000以下となる。パス出力は、「変数+1-3-3」である。スタブ値ロジック表135-3の3番目の実行パスは、スタブ値ロジック表135-1の3番目の実行パスとスタブ値ロジック表135-2の2番目の実行パスから生成される。パス条件は、「変数」が1000以下かつ「変数-1-3」が2000以下である。これを簡約化すると、パス条件は、「変数」が1000以下となる。パス出力は、「変数-1-3-3」である。これにより、スタブ値ロジック表135-3はスタブ値「変数_Perform_23_セクション2_1」を含まないものとなる。
なお、スタブ値ロジック表135-1の2番目または3番目の実行パスとスタブ値ロジック表135-2の1番目の実行パスの組は、パス条件が充足可能でない。また、スタブ値ロジック表135-1の1番目の実行パスとスタブ値ロジック表135-2の2番目の実行パスの組は、パス条件が充足可能でない。
復元対象の部分ロジック表134-3は、「変数_Perform_23_セクション2_1」と「変数_Perform_26_セクション2_1」の2つのスタブ値を含む。前者のスタブ値に対しては、当該スタブ値を定義しており他のスタブ値を参照しないスタブ値ロジック表135-1が生成されている。後者のスタブ値に対しては、当該スタブ値を定義しており他のスタブ値を参照しないスタブ値ロジック表135-3が生成されている。よって、以上により、スタブ値ロジック表からの他のスタブ値の消去が終了する。
図10は、スタブ値消去の第2の例を示す図である。
復元対象の部分ロジック表に含まれるスタブ値を定義しており他のスタブ値を参照していないスタブ値ロジック表が全て揃うと、最後に、プログラム分析装置100は、復元対象の部分ロジック表からスタブ値を消去する。
復元対象の部分ロジック表のスタブ値消去は、前述のスタブ値ロジック表の生成やスタブ値ロジック表のスタブ値消去と同様の方法で行うことができる。ただし、復元対象の部分ロジック表のスタブ値消去では、消去したいスタブ値を定義しているスタブ値ロジック表が代入元ロジック表であり、復元対象の部分ロジック表が代入先ロジック表である。また、復元対象の部分ロジック表が2以上のスタブ値を含む場合、2以上のスタブ値に対応する2以上のスタブ値ロジック表を1つずつ順に復元対象の部分ロジック表に対して適用していけばよい。スタブ値ロジック表のスタブ値消去において、代入先のスタブ値ロジック表が2以上のスタブ値を含む場合も同様である。
ここでは、プログラム分析装置100は、スタブ値「変数_Perform_23_セクション2_1」について、そのスタブ値を定義するスタブ値ロジック表135-1と復元対象の部分ロジック表134-3を選択する。プログラム分析装置100は、部分ロジック表134-3からスタブ値「変数_Perform_23_セクション2_1」が消去された中間ロジック表135-4を生成する。
中間ロジック表135-4は、4つの実行パスを含む。中間ロジック表135-4の1番目の実行パスは、スタブ値ロジック表135-1の1番目の実行パスと部分ロジック表134-3の1番目の実行パスから生成される。パス条件は、「変数+1」が2000より大きくかつ「変数+1+3」が3000以上である。これを簡約化すると、パス条件は、「変数+1+3」が3000以上となる。パス出力は、「変数+1+3-2」である。
中間ロジック表135-4の2番目の実行パスは、スタブ値ロジック表135-1の1番目の実行パスと部分ロジック表134-3の2番目の実行パスから生成される。パス条件は、「変数+1」が2000より大きくかつ「変数+1+3」が3000未満である。パス出力は、「変数_Perform_26_セクション2_1+2」である。中間ロジック表135-4の3番目の実行パスは、スタブ値ロジック表135-1の2番目の実行パスと部分ロジック表134-3の2番目の実行パスから生成される。パス条件は、「変数」が1000より大きくかつ「変数+1」が2000以下かつ「変数+1-3」が3000未満である。これを簡略化すると、パス条件は、「変数」が1000より大きくかつ「変数+1」が2000以下となる。パス出力は、「変数_Perform_26_セクション2_1+2」である。
中間ロジック表135-4の4番目の実行パスは、スタブ値ロジック表135-1の3番目の実行パスと部分ロジック表134-3の2番目の実行パスから生成される。パス条件は、「変数」が1000以下かつ「変数-1-3」が3000未満である。これを簡略化すると、パス条件は、「変数」が1000以下となる。パス出力は、「変数_Perform_26_セクション2_1+2」である。なお、スタブ値ロジック表135-1の2番目または3番目の実行パスと部分ロジック表134-3の1番目の実行パスの組は、パス条件が充足可能でない。
図11は、スタブ値消去の第2の例を示す図(続き)である。
中間ロジック表135-4には、スタブ値「変数_Perform_26_セクション2_1」がまだ残っている。そこで、プログラム分析装置100は、スタブ値「変数_Perform_26_セクション2_1」について、そのスタブ値を定義するスタブ値ロジック表135-3と復元途中の中間ロジック表135-4を選択する。プログラム分析装置100は、中間ロジック表135-4からスタブ値「変数_Perform_26_セクション2_1」が消去されたロジック表136を生成する。
ロジック表136は、4つの実行パスを含む。ロジック表136の1番目の実行パスは、中間ロジック表135-4の1番目の実行パスである。すなわち、パス条件は、「変数+1+3」が3000以上である。パス出力は、「変数+1+3-2」である。中間ロジック表135-4の1番目の実行パスは、スタブ値を含まないことから、単独でそのままロジック表136の実行パスとして採用される。
ロジック表136の2番目の実行パスは、スタブ値ロジック表135-3の1番目の実行パスと中間ロジック表135-4の2番目の実行パスから生成される。パス条件は、「変数+1」が2000より大きくかつ「変数+1+3」が3000未満である。パス出力は、「変数+1+3+3+2」である。ロジック表136の3番目の実行パスは、スタブ値ロジック表135-3の2番目の実行パスと中間ロジック表135-4の3番目の実行パスから生成される。パス条件は、「変数」が1000より大きくかつ「変数+1」が2000以下である。パス出力は、「変数+1-3-3+2」である。ロジック表136の4番目の実行パスは、スタブ値ロジック表135-3の3番目の実行パスと中間ロジック表135-4の4番目の実行パスから生成される。パス条件は、「変数」が1000以下である。パス出力は、「変数-1-3-3+2」である。
なお、スタブ値ロジック表135-3の2番目または3番目の実行パスと中間ロジック表135-4の2番目の実行パスの組は、パス条件が充足可能でない。また、スタブ値ロジック表135-3の1番目または3番目の実行パスと中間ロジック表135-4の3番目の実行パスの組は、パス条件が充足可能でない。また、スタブ値ロジック表135-3の1番目または2番目の実行パスと中間ロジック表135-4の4番目の実行パスの組は、パス条件が充足可能でない。
このようにして生成されたロジック表136は、プログラム133のセクション1とセクション2に跨がってシンボリック実行を行った場合と同じロジックを表している。よって、プログラム分析装置100は、部分ロジック表134-1,134-2,134-3,134-4から本来のロジック表136を正確に再現することができる。また、プログラム分析装置100は、シンボリック実行のパス爆発を抑制して計算量を削減できる。
以上のロジック表合成の流れをまとめると以下のようになる。
図12は、ロジック表合成の流れの例を示す図である。
復元対象の部分ロジック表134-3が基点として選択される。部分ロジック表134-3は、「変数_Perform_23_セクション2_1」と「変数_Perform_26_セクション2_1」の2つのスタブ値を参照している。
そこで、「変数_Perform_23_セクション2_1」を定義するスタブ値ロジック表135-1が生成されることになる。スタブ値ロジック表135-1は、23行目のサブルーチン呼び出しの直前の部分ロジック表134-1と、サブルーチンの終点の部分ロジック表134-4との間のロジック合成により生成される。
また、「変数_Perform_26_セクション2_1」を定義するスタブ値ロジック表135-2が生成されることになる。スタブ値ロジック表135-2は、26行目のサブルーチン呼び出しの直前の部分ロジック表134-2と、サブルーチンの終点の部分ロジック表134-4との間のロジック合成により生成される。ただし、スタブ値ロジック表135-2は、「変数_Perform_23_セクション2_1」を参照している。そこで、スタブ値ロジック表135-2から「変数_Perform_23_セクション2_1」を消去するために、「変数_Perform_23_セクション2_1」を定義するスタブ値ロジック表135-1が用意されることになる。
そして、スタブ値ロジック表135-1を用いて、スタブ値ロジック表135-2から「変数_Perform_23_セクション2_1」が消去され、スタブ値ロジック表135-3に変換される。これにより、部分ロジック表134-3が参照する2つのスタブ値それぞれに対して、スタブ値を参照しないスタブ値ロジック表が得られる。最後に、スタブ値ロジック表135-1を用いて、部分ロジック表134-3から「変数_Perform_23_セクション2_1」が消去される。また、スタブ値ロジック表135-3を用いて、部分ロジック表134-3から「変数_Perform_26_セクション2_1」が消去される。これにより、スタブ値を参照しないロジック表136が得られる。
次に、プログラム分析装置100の機能について説明する。
図13は、プログラム分析装置の機能例を示すブロック図である。
プログラム分析装置100は、プログラム記憶部121、部分ロジック表記憶部122およびロジック表記憶部123を有する。これらの記憶部は、例えば、RAM102またはHDD103の記憶領域を用いて実現される。また、プログラム分析装置100は、分析範囲指定部124、シンボリック実行部125、部分ロジック表管理部126、スタブ値ロジック表生成部127、ロジック表合成部128およびロジック表出力部129を有する。これらの処理部は、例えば、プログラムを用いて実現される。
プログラム記憶部121は、分析対象のプログラムを記憶する。分析対象のプログラムは、高水準言語で記述されたソースコードでもよいし、ソースコードから変換されて中間言語で記述された中間コードでもよいし、機械可読なオブジェクトコードでもよい。例えば、前述のプログラム133がプログラム記憶部121に記憶される。
部分ロジック表記憶部122は、シンボリック実行によって生成された複数の部分ロジック表を記憶する。また、部分ロジック表記憶部122は、複数の部分ロジック表から本来のロジック表を合成する途中で生成されるスタブ値ロジック表を記憶する。また、部分ロジック表記憶部122は、こららの部分ロジック表やスタブ値ロジック表を管理するためのロジック表管理テーブルを記憶する。例えば、前述の部分ロジック表134-1,134-2,134-3,134-4やスタブ値ロジック表135-1,135-2,135-3が部分ロジック表記憶部122に記憶される。
ロジック表記憶部123は、分析対象のプログラムから最終的に生成されたロジック表を記憶する。例えば、前述のロジック表136がロジック表記憶部123に記憶される。
分析範囲指定部124は、プログラム記憶部121に記憶されたプログラムの一部分または全体として、分析範囲の指定をユーザから受け付ける。分析範囲指定部124は、入力デバイス112から分析範囲の入力を受け付けてもよいし、他の情報処理装置から分析範囲を示す情報を受信してもよい。例えば、分析範囲指定部124は、前述のプログラム133のセクション1を分析範囲の指定として受け付ける。
シンボリック実行部125は、プログラム記憶部121からプログラムを読み出し、分析範囲指定部124で指定された分析範囲とその分析範囲から呼び出されるサブルーチンに対して、シンボリック実行を行う。前述のように、シンボリック実行部125は、呼び出し元ルーチンの始点において入力値を示すシンボルを変数に割り当て、呼び出し元ルーチンのシンボリック実行を開始する。シンボリック実行部125は、サブルーチン呼び出しに到達する毎に、その直前の時点におけるパス条件およびパス出力を記録し、サブルーチンによって更新され得る変数にスタブ値を割り当てる。シンボリック実行部125は、スタブ値を用いて呼び出し元ルーチンのシンボリック実行を継続し、呼び出し元ルーチンの終点におけるパス条件およびパス出力を記録する。
また、シンボリック実行部125は、呼び出し元ルーチンとは独立に、サブルーチンの始点において入力値を示すシンボルを変数に割り当て、サブルーチンの終点におけるパス条件およびパス出力を記録する。そして、シンボリック実行部125は、上記の複数のプログラム位置に対応する複数の部分ロジック表を生成する。複数の部分ロジック表それぞれは、特定のプログラム位置のロジックを表しており、上記で記録したパス条件およびパス出力を含む。生成される部分ロジック表には、サブルーチン呼び出しの直前のものと、サブルーチンの終点のものと、分析範囲の終点のものが含まれる。シンボリック実行部125は、生成した複数の部分ロジック表を部分ロジック表管理部126に出力する。
部分ロジック表管理部126は、部分ロジック表記憶部122に記憶される部分ロジック表およびスタブ値ロジック表を管理する。部分ロジック表管理部126は、シンボリック実行部125から部分ロジック表を取得し、部分ロジック表記憶部122に格納する。このとき、部分ロジック表管理部126は、ロジック表管理テーブルを生成し、ロジック表管理テーブルに部分ロジック表を登録する。ロジック表管理テーブルに登録される部分ロジック表の書誌情報は、シンボリック実行部125から通知される。
また、部分ロジック表管理部126は、スタブ値ロジック表生成部127またはロジック表合成部128からスタブ値ロジック表を取得し、部分ロジック表記憶部122に格納する。このとき、部分ロジック表管理部126は、ロジック表管理テーブルにスタブ値ロジック表を登録する。ロジック表管理テーブルに登録されるスタブ値ロジック表の書誌情報は、スタブ値ロジック表生成部127またはロジック表合成部128から通知される。また、部分ロジック表管理部126は、スタブ値ロジック表生成部127またはロジック表合成部128からの要求に応じて、ロジック表管理テーブルから条件に合う部分ロジック表またはスタブ値ロジック表を検索する。部分ロジック表管理部126は、条件に合う部分ロジック表またはスタブ値ロジック表を部分ロジック表記憶部122から読み出す。
スタブ値ロジック表生成部127は、復元対象の部分ロジック表を部分ロジック表管理部126から取得する。スタブ値ロジック表生成部127は、復元対象の部分ロジック表を基点として、パス条件およびパス出力の少なくとも一方で参照されているスタブ値を消去するためのスタブ値ロジック表を再帰的に生成していく。
具体的には、スタブ値ロジック表生成部127は、復元対象の部分ロジック表からスタブ値を抽出し、抽出したスタブ値に関連する2つの部分ロジック表を部分ロジック表管理部126から取得する。取得する部分ロジック表は、そのスタブ値が割り当てられたサブルーチン呼び出しの直前の部分ロジック表と、呼び出し先のサブルーチンの終点の部分ロジック表である。スタブ値ロジック表生成部127は、スタブ値に含まれる文字列を用いて、該当する部分ロジック表を特定する。第2の実施の形態では、スタブ値に含まれる行番号と呼び出し先サブルーチン名と呼び出し回数が使用される。
スタブ値ロジック表生成部127は、サブルーチン呼び出しの直前の部分ロジック表に含まれるパス出力を、サブルーチンの終点の部分ロジック表に含まれる入力値のシンボルに対応付けることで、スタブ値ロジック表を生成する。スタブ値ロジック表生成部127は、生成したスタブ値ロジック表を部分ロジック表管理部126に出力する。また、スタブ値ロジック表生成部127は、生成したスタブ値ロジック表から未解決の他のスタブ値を検索する。未解決の他のスタブ値が存在する場合、スタブ値ロジック表生成部127は、当該他のスタブ値に対応するスタブ値ロジック表を生成する。スタブ値ロジック表生成部127は、未解決の他のスタブ値が存在しなくなるまで上記を再帰的に実行する。
ロジック表合成部128は、スタブ値ロジック表生成部127がスタブ値ロジック表を生成した順序とは逆順に、スタブ値ロジック表からスタブ値を消去する代入処理を行う。最後に、ロジック表合成部128は、他のスタブ値を参照していないスタブ値ロジック表を用いて、復元対象の部分ロジック表からスタブ値を消去する代入処理を行う。これにより、スタブ値を含まない本来のロジック表が合成される。ロジック表合成部128は、合成したロジック表をロジック表出力部129に出力する。
具体的には、ロジック表合成部128は、他のスタブ値を参照しない末端のスタブ値ロジック表と、末端のスタブ値ロジック表によって定義されるスタブ値を参照する前段のスタブ値ロジック表を、部分ロジック表管理部126から取得する。ロジック表合成部128は、スタブ値に含まれる文字列を用いて、該当するスタブ値ロジック表を特定する。ロジック表合成部128は、末端のスタブ値ロジック表に含まれるパス出力を、前段のスタブ値ロジック表に含まれるスタブ値に対応付けることで、後者のスタブ値ロジック表を他のスタブ値を含まないスタブ値ロジック表に変換する。ロジック表合成部128は、変換後のスタブ値ロジック表を部分ロジック表管理部126に出力する。ロジック表合成部128は、復元対象の部分ロジック表に到達するまで上記を再帰的に実行する。
ロジック表出力部129は、ロジック表合成部128からスタブ値を含まないロジック表を取得し、ロジック表記憶部123に格納する。ロジック表出力部129は、ロジック表を表示装置111に表示する。ただし、ロジック表出力部129は、ロジック表を他の出力デバイスに出力してもよく、他の情報処理装置に送信してもよい。
図14は、ロジック表管理テーブルの例を示す図である。
ロジック表管理テーブル141は、部分ロジック表記憶部122に記憶される。ロジック表管理テーブル141は、ロジック表ID、モジュール、位置、呼び出し回数、スタブ値フラグ、出力変数および復元フラグの項目を含む。
ロジック表IDの項目には、部分ロジック表またはスタブ値ロジック表を識別するための識別子が登録される。モジュールの項目には、呼び出し元ルーチンの名称またはサブルーチンの名称が登録される。前述のプログラム133の場合、セクション1またはセクション2が登録される。位置の項目には、プログラム位置を示す情報が登録される。プログラム位置としては、終点、サブルーチン呼び出しの直前およびサブルーチン呼び出しの直後が挙げられる。サブルーチン呼び出しの直前は、行番号と呼び出し先サブルーチン名とその直前である旨の記載によって特定できる。サブルーチン呼び出しの直後は、行番号と呼び出し先サブルーチン名とその直後である旨の記載によって特定できる。
呼び出し回数の項目には、同一のサブルーチン呼び出しの実行回数を示す数値が登録される。スタブ値フラグの項目には、部分ロジック表またはスタブ値ロジック表が未消去のスタブ値を含むか否かのフラグが登録される。出力変数の項目には、パス出力によって値が定義されている変数の名称が登録される。復元フラグの項目には、複数の部分ロジック表から復元されたスタブ値ロジック表であるか否かを示すフラグが登録される。スタブ値ロジック表は、サブルーチン呼び出しの直後のプログラム位置に対応するものである。
ロジック表管理テーブル141を参照することで、スタブ値ロジック表生成部127およびロジック表合成部128が使用する各種ロジック表が検索される。図14のロジック表ID=1,2,3,4は、シンボリック実行によって生成された部分ロジック表に対応する。ロジック表ID=1,2,3,4のレコードは、ロジック表合成の開始前にロジック表管理テーブル141に登録される。一方、図14のロジック表ID=5,6は、ロジック表合成の途中で生成されたスタブ値ロジック表に対応する。ロジック表ID=5,6のレコードは、ロジック表合成の途中でロジック表管理テーブル141に追記される。
なお、ロジック表管理テーブル141には、他のスタブ値を参照しているスタブ値ロジック表を登録してもよい。あるスタブ値ロジック表から他のスタブ値を消去する毎に、変換後のスタブ値ロジック表をロジック表管理テーブル141に追記してもよいし、変換前のスタブ値ロジック表の情報をロジック表管理テーブル141から消去してもよい。図14では、他のスタブ値を消去済みであるスタブ値ロジック表の情報のみを残している。
次に、プログラム分析装置100の処理手順について説明する。
図15は、プログラム分析の手順例を示すフローチャートである。
(S10)分析範囲指定部124は、プログラムの分析範囲の指定を受け付ける。
(S11)シンボリック実行部125は、プログラムの中から、ステップS10で指定された分析範囲から呼び出されるサブルーチンを検出する。
(S12)シンボリック実行部125は、指定された分析範囲およびステップS11で検出されたサブルーチンについて、前述のように細分化してシンボリック実行を行う。シンボリック実行の詳細については後述する。
(S13)シンボリック実行部125は、ステップS12のシンボリック実行によって検出された実行パスのパス条件およびパス出力を示す部分ロジック表を生成する。シンボリック実行が細分化されて行われるため、複数のプログラム位置に対応する複数の部分ロジック表が生成される。部分ロジック表管理部126は、生成された複数の部分ロジック表を部分ロジック表記憶部122に格納する。また、部分ロジック表管理部126は、ロジック表管理テーブル141を生成し、複数の部分ロジック表をロジック表管理テーブル141に登録し、部分ロジック表記憶部122に格納する。
(S14)スタブ値ロジック表生成部127は、複数の部分ロジック表から1以上のスタブ値ロジック表を生成する。ロジック表合成部128は、複数の部分ロジック表のうちの復元対象の部分ロジック表とスタブ値ロジック表から、本来のロジック表を合成する。ロジック表合成の詳細については後述する。
(S15)ロジック表出力部129は、ステップS14で生成されたロジック表をロジック表記憶部123に保存し、ロジック表を表示装置111に表示する。例えば、図11のロジック表136が表示装置111に表示される。
図16は、シンボリック実行の手順例を示すフローチャートである。
このシンボリック実行は、上記のステップS12で行われる。
(S20)シンボリック実行部125は、着目するモジュールの入力値が格納される入力変数に対して、独立なシンボルを割り当てる。シンボリック実行の開始時は、着目するモジュールは、指定された分析範囲である呼び出し元ルーチンである。
(S21)シンボリック実行部125は、プログラムの処理順序に従って、次に実行されるべき命令をプログラムから1つ取得する。
(S22)シンボリック実行部125は、ステップS21で終了命令を取得したか判断する。終了命令を取得した場合はステップS28に進み、終了命令以外の命令を取得した場合はステップS23に進む。
(S23)シンボリック実行部125は、ステップS21で取得した命令がサブルーチン呼び出し命令であるか判断する。サブルーチン呼び出し命令の場合はステップS24に進み、それ以外の場合はステップS30に進む。
(S24)シンボリック実行部125は、サブルーチン呼び出しの直前におけるパス条件およびパス出力を、途中点のパス条件およびパス出力として記録する。パス条件は、着目するモジュールの先頭から今回のサブルーチン呼び出しの直前までの間に選択した分岐方向の条件を累積したものである。パス出力は、今回のサブルーチン呼び出しの直前における変数の値である。パス条件およびパス出力には、入力値のシンボルが含まれることがあり、後述するスタブ値が含まれることがある。
(S25)シンボリック実行部125は、呼び出し先のサブルーチンが分析済みであるか、すなわち、サブルーチンのシンボリック実行が既に行われているか判断する。分析済みの場合はステップS27に進み、未分析である場合はステップS26に進む。
(S26)シンボリック実行部125は、呼び出し先のサブルーチンに着目して、ステップS20~S36の処理を再帰的に実行する。このとき、シンボリック実行部125は、呼び出し元ルーチンの分析途中の情報を退避し、呼び出し元ルーチンとは独立にサブルーチンについてシンボリック実行を行う。サブルーチンのシンボリック実行が終了すると、シンボリック実行部125は、退避しておいた分析途中の情報を用いて呼び出し元ルーチンのシンボリック実行を続ける。ただし、呼び出し元ルーチンのシンボリック実行が終了してからサブルーチンのシンボリック実行を開始するようにしてもよい。
(S27)シンボリック実行部125は、サブルーチンによって更新され得る更新変数に対して、独立なシンボルであるスタブ値を割り当てる。サブルーチン呼び出しの直前における更新変数の値は破棄され、それ以降のシンボリック実行では、更新変数の値としてスタブ値が使用される。すなわち、サブルーチンによって、更新変数の値がスタブ値に更新されたものとみなされる。そして、ステップS21に戻る。
(S28)シンボリック実行部125は、実行パスが終点に到達したと判断する。シンボリック実行部125は、終点のパス条件およびパス出力を記録する。パス条件は、着目するモジュールの先頭から終点までの間に選択した分岐方向の条件を累積したものである。パス出力は、着目するモジュールの終点における変数の値である。パス条件およびパス出力には、入力値のシンボルが含まれることがあり、スタブ値が含まれることがある。
(S29)シンボリック実行部125は、条件分岐によって分割された実行パスであって、未選択の実行パスが残っているか判断する。未選択の実行パスがある場合、シンボリック実行部125は、1つ前の分割点までバックトラックし、保存しておいたその分割点におけるパス条件およびパス出力を読み出す。シンボリック実行部125は、未選択の分岐方向を選択し、読み出したパス条件およびパス出力を用いてその実行パスについてシンボリック実行を続ける。そして、ステップS21に戻る。一方、未選択の実行パスがない場合、着目するモジュールのシンボリック実行が終了する。
図17は、シンボリック実行の手順例を示すフローチャート(続き)である。
(S30)シンボリック実行部125は、ステップS21で変数更新命令を取得したか判断する。変数更新命令は、例えば、左辺と右辺を等号で結合した代入文やMOVE命令などである。変数更新命令を取得した場合はステップS31に進み、変数更新命令以外の命令を取得した場合はステップS32に進む。
(S31)シンボリック実行部125は、変数更新命令に従って変数の値を更新する。変数の値はシンボルを含む式で表されることもある。そして、ステップS21に戻る。
(S32)シンボリック実行部125は、ステップS21で条件分岐命令を取得したか判断する。条件分岐命令を取得した場合はステップS33に進み、条件分岐命令以外の命令を取得した場合はステップS36に進む。
(S33)シンボリック実行部125は、条件分岐命令に記載された分岐条件とその時点の変数の値とその時点のパス条件とに基づいて、YES方向とNO方向の2つの分岐方向それぞれの充足可能性を判定する。変数の値がシンボルを含む式である場合、2つの分岐方向の両方が充足可能であると判定されることもある。
(S34)シンボリック実行部125は、2つの分岐方向が共に充足可能であるか判断する。2つの分岐方向が共に充足可能である場合はステップS35に進み、一方の分岐方向のみ充足可能である場合はステップS36に進む。
(S35)シンボリック実行部125は、実行パスを分割する。シンボリック実行部125は、2つの分岐方向の何れか一方(例えば、YES方向)を選択して、現在の実行パスの進行方向とする。また、シンボリック実行部125は、その時点のパス条件とパス出力を退避しておく。選択しなかった分岐方向に相当する分割された実行パスは、未選択の実行パスとしておく。そして、ステップS21に戻る。
(S36)シンボリック実行部125は、ステップS21で取得した命令に応じた処理を行う。ステップS34で一方の分岐方向のみ充足可能と判断された場合、シンボリック実行部125は、条件分岐命令に従って充足可能な分岐方向を選択することになる。このとき、実行パスは分割されない。そして、ステップS21に戻る。
図18は、ロジック表合成の手順例を示すフローチャートである。
このロジック表合成は、上記のステップS14で行われる。
(S40)スタブ値ロジック表生成部127は、部分ロジック表管理部126に問い合わせて、復元対象として分析範囲の終点の部分ロジック表を選択する。
(S41)スタブ値ロジック表生成部127は、着目するロジック表にスタブ値が含まれるか判断する。着目するロジック表は、ステップS40で選択された復元対象の部分ロジック表または後述するスタブ値ロジック表である。スタブ値が含まれる場合はステップS42に進み、含まれない場合はステップS46に進む。なお、2種類以上のスタブ値が含まれる場合、スタブ値の種類毎に以下のステップS42~S45が行われる。
(S42)スタブ値ロジック表生成部127は、部分ロジック表管理部126に問い合わせて、ステップS41で検出されたスタブ値に対応するスタブ値ロジック表が既に生成されているか判断する。検出されたスタブ値に対応するスタブ値ロジック表は、検出されたスタブ値をパス出力において定義しているスタブ値ロジック表である。該当するスタブ値ロジック表が既に生成されている場合はステップS46に進み、該当するスタブ値ロジック表がまだ生成されていない場合はステップS43に進む。
(S43)スタブ値ロジック表生成部127は、着目するスタブ値が割り当てられたサブルーチン呼び出しと呼び出し先のサブルーチンを特定する。スタブ値ロジック表生成部127は、部分ロジック表管理部126に問い合わせて、サブルーチン呼び出しの直前の部分ロジック表とサブルーチンの終点の部分ロジック表を検索する。
(S44)スタブ値ロジック表生成部127は、サブルーチン呼び出しの直前の部分ロジック表を代入元ロジック表とし、サブルーチンの終点の部分ロジック表を代入先ロジック表として、ロジック結合を行う。これにより、着目するスタブ値を定義するスタブ値ロジック表が生成される。ロジック結合の詳細については後述する。
(S45)スタブ値ロジック表生成部127は、部分ロジック表管理部126に要求して、ステップS44で生成されたスタブ値ロジック表をロジック表管理テーブル141に登録する。そして、ステップS41に戻る。
(S46)ロジック表合成部128は、部分ロジック表管理部126に問い合わせて、他のスタブ値を含むスタブ値ロジック表が残っているか判断する。該当するスタブ値ロジック表がある場合はステップS47に進み、無い場合はステップS50に進む。なお、2種類以上の他のスタブ値を含むスタブ値ロジック表がある場合、そのスタブ値ロジック表に対して、スタブ値の種類毎に以下のステップS48,S49が行われる。
(S47)ロジック表合成部128は、部分ロジック表管理部126に問い合わせて、ステップS41~S45の生成順序とは逆順に2つのスタブ値ロジック表を選択する。ここでは、他のスタブ値を参照しない末端のスタブ値ロジック表と、その末端のスタブ値ロジック表で定義されるスタブ値を参照する前段のスタブ値ロジック表を選択する。
(S48)ロジック表合成部128は、末端のスタブ値ロジック表を代入元ロジック表とし、その前段のスタブ値ロジック表を代入先ロジック表として、ロジック結合を行う。これにより、後者のスタブ値ロジック表から、前者のスタブ値ロジック表で定義されるスタブ値が消去される。ロジック結合の詳細については後述する。
(S49)ロジック表合成部128は、部分ロジック表管理部126に要求して、ステップS48で他のスタブ値を消去したスタブ値ロジック表が登録されるように、ロジック表管理テーブル141を更新する。そして、ステップS46に戻る。
(S50)ロジック表合成部128は、部分ロジック表管理部126に問い合わせて、復元対象の部分ロジック表と、復元対象の部分ロジック表に含まれるスタブ値を定義するスタブ値ロジック表を選択する。ここで選択されるスタブ値ロジック表には、他のスタブ値は含まれていない。ロジック表合成部128は、選択したスタブ値ロジック表を代入元ロジック表とし、復元対象の部分ロジック表を代入先ロジック表として、ロジック結合を行う。これにより、復元対象の部分ロジック表からスタブ値が消去され、分析範囲のロジックを示す本来のロジック表が合成される。ロジック結合の詳細については後述する。なお、復元対象の部分ロジック表が2種類以上のスタブ値を含む場合、復元対象の部分ロジック表に対して、スタブ値の種類毎にロジック結合が行われる。
図19は、ロジック結合の手順例を示すフローチャートである。
このロジック結合は、上記のステップS44,S48,S50で行われる。スタブ値ロジック表生成部127とロジック表合成部128は、実質的に同様のロジック結合を行うことになる。ここでは、ロジック表合成部128がロジック結合を行う場合を説明する。なお、ロジック結合を実装した再利用可能なソフトウェア部品を作成し、スタブ値ロジック表生成部127とロジック表合成部128からこれを利用するようにしてもよい。
(S60)ロジック表合成部128は、代入元ロジック表としてロジック表T1を取得し、代入先ロジック表としてロジック表T2を取得する。上記のステップS44では、ロジック表T1はサブルーチン呼び出しの直前の部分ロジック表であり、ロジック表T2はサブルーチンの終点の部分ロジック表である。上記のステップS48では、ロジック表T1は末端のスタブ値ロジック表であり、ロジック表T2はその前段のスタブ値ロジック表である。上記のステップS50では、ロジック表T1は他のスタブ値を含まないスタブ値ロジック表であり、ロジック表T2は復元対象の部分ロジック表である。
(S61)ロジック表合成部128は、ロジック表T2からレコードR2を選択する。レコードR2は、ロジック表T2の中の1つの実行パスを表す。
(S62)ロジック表合成部128は、レコードR2のパス条件およびパス出力から、参照されているシンボルを検索する。参照されているシンボルは、入力値を表すシンボルであることもあるし、サブルーチンの実行結果を表すスタブ値であることもある。
(S63)ロジック表合成部128は、ロジック表T1から、ステップS62で検出されたシンボルをパス出力として定義するレコードR1を選択する。レコードR1は、ロジック表T1の中の1つの実行パスを表す。
(S64)ロジック表合成部128は、レコードR1のパス出力を、レコードR2のパス条件に用いられているシンボルに代入する。ロジック表合成部128は、代入結果とレコードR1のパス条件とをAND(論理積)で連結し、結合後のパス条件を生成する。
(S65)ロジック表合成部128は、ステップS64で生成した結合後のパス条件の充足可能性を判断する。結合後のパス条件が充足可能である場合はステップS66に進み、充足可能でない場合はステップS68に進む。
(S66)ロジック表合成部128は、レコードR1のパス出力をレコードR2のパス出力に用いられているシンボルに代入し、結合後のパス出力を生成する。
(S67)ロジック表合成部128は、ステップS64で生成したパス条件とステップS66で生成したパス出力を結合結果のロジック表に記録する。上記のステップS44,S48では、結合結果のロジック表はスタブ値ロジック表である。上記のステップS50では、結合結果のロジック表は最終的なロジック表である。
(S68)ロジック表合成部128は、ロジック表T1に未選択のレコードがあるか判断する。未選択のレコードがある場合はステップS63に戻り、ロジック表T1の全てのレコードを選択した場合はステップS69に進む。
(S69)ロジック表合成部128は、ロジック表T2に未選択のレコードがあるか判断する。未選択のレコードがある場合はステップS61に戻り、ロジック表T2の全てのレコードを選択した場合はロジック結合が終了する。
第2の実施の形態のプログラム分析装置100によれば、シンボリック実行によって、プログラムの入力と出力の関係を表すロジック表が生成される。よって、具体的な入力値を次々にプログラムに入力する動的分析よりも、プログラムの挙動を効率的に分析することができる。また、プログラムがサブルーチンを呼び出す場合に、呼び出し元ルーチンとサブルーチンに対して独立にシンボリック実行が行われ、複数の部分ロジック表が事後的に結合されて本来のロジック表が再現される。よって、呼び出し元ルーチンとサブルーチンに跨がる実行パスを直接追跡する場合よりも、シンボリック実行で探索すべき実行パスが減少し、パス爆発を抑制してシンボリック実行の計算量を削減できる。
また、呼び出し元ルーチンの終点のロジック表を基点として、サブルーチン呼び出しに伴って付与されるスタブ値が探索され、シンボリック実行の結果から、そのスタブ値を定義するスタブ値ロジック表が生成される。スタブ値ロジック表が他のスタブ値を含む場合、他のスタブ値を含まないスタブ値ロジック表が得られるまで再帰的にスタブ値ロジック表が生成される。そして、スタブ値ロジック表を用いた代入処理によりスタブ値が順に消去され、最終的に呼び出し元ルーチンの終点のロジック表からスタブ値が消去される。
これにより、後のサブルーチン呼び出しの実行の有無が前のサブルーチン呼び出しの結果に依存するプログラムなど、複数のサブルーチン呼び出しの間に複雑な依存関係があるプログラムについても、事後的にロジック表を再現する手法を採用できる。よって、このようなプログラムの挙動を効率的に分析することが可能となる。