図2に、本実施の形態における情報処理装置1の機能ブロック図を示す。情報処理装置1は、入力部101と、プログラム格納部102と、前処理部103と、ドライバ格納部1041と、スタブ格納部1042と、シンボリック実行部105と、状態データ格納部106と、条件表格納部107と、コールツリー格納部108と、統合処理部109と、テストデータ生成部110と、テストデータ格納部111とを含む。
入力部101は、テストデータが生成されるべきプログラムの入力を受け付け、プログラム格納部102に格納する。前処理部103は、プログラム格納部102に格納されているプログラムに基づき、シンボリック実行を開始するためのドライバを生成し、ドライバ格納部1041に格納する。また、前処理部103は、プログラム格納部102に格納されているプログラムに基づきスタブを生成し、スタブ格納部1042に格納する。
シンボリック実行部105は、プログラム格納部102に格納されているプログラム、ドライバ格納部1041に格納されているドライバ、及びスタブ格納部1042に格納されているスタブを用いてシンボリック実行を行い、シンボリック実行中における実行状態のデータを状態データ格納部106に格納する。また、シンボリック実行部105は、シンボリック実行時に得られた条件及び返却値(返り値とも呼ばれる)等を含む条件表を条件表格納部107に格納する。また、シンボリック実行部105は、関数の呼び出し関係を表すコールツリーを生成し、コールツリー格納部108に格納する。
統合処理部109は、条件表格納部107に格納されている条件表及びコールツリー格納部108に格納されているコールツリーを用いて、条件を統合する処理を実行し、処理結果を条件表格納部107に格納する。テストデータ生成部110は、条件表格納部107に最終的に格納された条件表における条件を満たすテストデータを生成し、テストデータ格納部111に格納する。
図3に、プログラム格納部102に格納されるプログラムの一例を示す。図3の例では、関数funcAについてのプログラムと、関数funcBについてのプログラムと、関数funcCについてのプログラムとが格納される。funcAは4行目においてfuncBを呼び出し、funcBは7行目及び9行目においてfuncCを呼び出す。本実施の形態においては、図3に示すように、複数の関数が実行されるプログラムを処理対象とする。
図4に、コールツリーの一例を示す。図4の例は、図3に示したプログラムについて生成されたコールツリーであり、矢印に指されている関数は呼び出される側の関数である。このコールツリーにおいては、最も上位の関数はfuncAであり、最も下位の関数はfuncCである。コールツリー格納部108には、このような関数の呼び出し関係を表すコールツリーのデータが格納される。
図5及び図6を用いて、プログラムの実行状態について説明する。まず、図5を用いて、コールスタックについて説明する。図5に示したプログラムは、メインの処理を表すコードにおいて関数funcAを呼び出し、関数funcAにおいて関数absを呼び出すプログラムである。命令1乃至7におけるいずれかの命令を実行中におけるコールスタックはstack3のようになっており、命令8乃至15におけるいずれかの命令を実行中におけるコールスタックはstack2のようになっており、命令16乃至19におけるいずれかの命令を実行中におけるコールスタックはstack1のようになっている。
図6に、図5に示したプログラムの実行木を示す。図6の実行木においては、各実行状態について、プログラムカウンタの値、コールスタックの識別情報(図5における識別情報に対応している)、メモリの内容、及びパス条件(本実施の形態においては、シンボル変数に関わる分岐を辿った履歴を表す条件)が示されている。例えば、プログラムカウンタの値が12である場合には、実行状態はstate1又はstate2である。「*」は、変数がシンボル変数であることを表す。状態データ格納部106には、シンボリック実行中におけるプログラムの実行状態を表すデータが、図6における60のような形式で格納される。
次に、図7乃至図14を用いて、本実施の形態における処理の概要を説明する。本実施の形態においては、関数毎に生成されたドライバ及びスタブを用いて、関数毎にシンボリック実行を行う。そして、シンボリック実行によって各関数について生成された条件を論理積によって統合し、統合後の条件を満たすシンボル変数の値によってテストデータを生成する。以下では、funcBの返却値をfuncB_retと表し、funcCの返却値をfuncC_retと表し、funcBの引数xをfuncB_xと表し、funcCの引数xをfuncC_xと表す。
図7に、図3に示したfuncAについてシンボリック実行を行った場合において、各パスについて生成される条件及び返却値を示す。IDは、パスのIDである。条件には、パス条件と、呼び出す関数の引数についての条件とが含まれる。パス条件に該当するのは、A−(1)における「x<=0」、A−(2)における「x>0 ∧ funcB_ret>0」、及びA−(3)における「x>0 ∧ funcB_ret<=0」である。呼び出す引数についての条件は、仮引数と実引数との関係を表しており、A−(2)においては「funcB_x==x」が該当し、A−(3)においては「funcB_x==x」が該当する。図7における返却値は、funcAの返却値である。
図8に、図3に示したfuncBについてシンボリック実行を行った場合において、各パスについて生成される条件及び返却値を示す。図8に示した条件にも、パス条件と、呼び出す関数の引数についての条件とが含まれる。パス条件に該当するのは、B−(1)における「x==0」、B−(2)における「x!=0 ∧ x>10 ∧ funcC_ret>=0」、B−(3)における「x!=0 ∧ x>10 ∧ funcC_ret>=0」、B−(4)における「x!=0 ∧ x<=10 ∧ funcC_ret<0」、及びB−(5)における「x!=0 ∧ x<=10 ∧ funcC_ret>=0」である。呼び出す引数についての条件に該当するのは、B−(2)における「funcC_x==x+1」、B−(3)における「funcC_x==x+1」、B−(4)における「funcC_x==x−1」、及びB−(5)における「funcC_x==x−1」である。図8における返却値は、funcBの返却値である。
図9に、図3に示したfuncCについてシンボリック実行を行った場合において、各パスについて生成される条件及び返却値を示す。図9に示した条件には、パス条件が含まれる。具体的には、C−(1)にお「x==20」と、C−(2)における「x!=20」とがパス条件である。図9における返却値は、funcCの返却値である。なお、図9に示したような条件表は、条件表格納部107に格納される。
なお、図7乃至図9に示した返却値は、統合処理部109によって条件に変換され、図7乃至図9に示した条件に追加される。例えば、B−(2)における返却値は、「funcB_ret==−1」という条件に変換され、B−(2)における条件「x!=0 ∧ x>10 ∧ funcC_ret<0 ∧ funcC_x==x+1」に追加される。
そして、各関数について生成された条件を、統合処理部109が関数間で網羅的に統合する。例えば、A−(2)の条件とfuncBについての各条件とを統合すると、図10に示すようになる。図10においては、条件に2つの括弧が含まれており、左側の括弧にはA−(2)の条件が含まれ、右側の括弧にはfuncBについての条件が含まれる。2つの括弧内の条件は、論理積によって結合されている。そして、条件の欄の右に設けられている判定の欄には、条件を満たす解が存在するか否かについての判定結果が示されている。SAT(Satisfied)である場合には、条件を満たす解が存在する。UNSAT(UNSATisfied)である場合には、条件を満たす解が存在しない。UNSATの括弧内には、UNSATである原因である条件が示されている。例えばパスA−(2)B−(1)については、funcB_ret>0とfuncB_ret==0とが同時に成立することが無いため、UNSATである。
但し、図10に示した条件は、funcBの下位関数であるfuncCに依存している。そこで、図10においてSATであると判定された条件(ここでは、A−(2)B−(3)の条件)と、funcCについての各条件とをさらに統合すると、図11に示すようになる。図11においては、条件に3つの括弧が含まれており、左側の括弧にはA−(2)の条件が含まれ、真ん中の括弧にはB−(3)の条件が含まれ、右側の括弧にはfuncCについての条件が含まれる。3つの括弧内の条件は、論理積によって結合されている。そして、条件の欄の右に設けられている判定の欄には、条件を満たす解が存在するか否かについての判定結果が示されている。
また、A−(3)の条件とfuncBについての各条件とを統合すると、図12に示すようになる。図12においては、条件に2つの括弧が含まれており、左側の括弧にはA−(3)の条件が含まれ、右側の括弧にはfuncBについての条件が含まれる。2つの括弧内の条件は、論理積によって結合されている。そして、条件の欄の右に設けられている判定の欄には、条件を満たす解が存在するか否かについての判定結果が示されている。
但し、図12に示した条件は、funcBの下位関数であるfuncCに依存している。そこで、図12においてSATであると判定された条件(ここでは、A−(3)B−(2))と、funcCについての各条件とをさらに統合すると、図13に示すようになる。図13においては、条件に3つの括弧が含まれており、左側の括弧にはA−(3)の条件が含まれ、真ん中の括弧にはB−(2)の条件が含まれ、右側の括弧にはfuncCについての条件が含まれる。3つの括弧は、論理積によって結合されている。そして、条件の欄の右に設けられている判定の欄には、条件を満たす解が存在するか否かについての判定結果が示されている。
以上のようにして条件を統合すると、最終的にSATである条件は、図14に示した条件である。すなわち、A−(1)の条件、A−(2)B−(3)C−(1)の条件、A−(3)B−(2)C−(2)の条件、及びA−(3)B−(4)C−(2)の条件である。そして、これらの条件を満たすシンボル変数の値を含むテストデータが生成される。なお、このようなテストデータを用いて図3に示したプログラムのテストを実行すると、funcBにおける4行目の命令以外を網羅することができる。
なお、条件には、パス条件、引数についての条件、及び返却値についての条件の他に、以下で説明する処理によって別の条件が追加される場合もある。但し、説明を簡単にするため、上ではパス条件、引数についての条件、及び返却値についての条件のみを示した。
次に、図15乃至図51を用いて、情報処理装置1が実行する処理について詳細に説明する。
まず、情報処理装置1における入力部101は、ユーザからプログラムの入力を受け付け、プログラム格納部102に格納する。これに応じ、シンボリック実行部105は、処理対象の関数fをプログラム格納部102から特定する(図15:ステップS1)。ステップS1においては、エントリポイントのプログラム(例えば、「main」のプログラム)が特定される。
シンボリック実行部105は、関数fに対して既にシンボリック実行を行ったか判断する(ステップS3)。関数fに対して既にシンボリック実行を行った場合(ステップS3:Yesルート)、シンボリック実行部105は、関数fの最終更新の時点がシンボリック実行の時点よりも前であるか判断する(ステップS5)。関数fの最終更新の時点がシンボリック実行の時点よりも前である場合(ステップS5:Yesルート)、既に行われたシンボリック実行の結果を採用することができる。そこで、シンボリック実行部105は、関数fに対するシンボリック実行の結果を、条件表格納部107から特定する(ステップS7)。条件表格納部107には、例えば、図7乃至図13に示したような条件表が格納されている。
一方、関数fに対して未だシンボリック実行を行っていない場合(ステップS3:Noルート)及び関数fの最終更新の時点がシンボリック実行の時点より後である場合(ステップS5:Noルート)、新たにシンボリック実行を行うことが求められる。そこで、シンボリック実行部105は、前処理部103に前処理の実行を指示する。これに応じ、前処理部103は、前処理を実行する(ステップS9)。前処理については、図16乃至図18を用いて説明する。但し、ドライバ及びスタブの生成はよく知られた処理であるので、簡単に説明する。
まず、前処理部103は、関数fから、変数及び関数fにおいて呼び出される関数(以下、呼び出し関数と呼ぶ)を抽出する(図16:ステップS21)。例えば図3に示したfuncAの場合、呼び出し関数としてfuncBが抽出される。
前処理部103は、ステップS21において抽出された呼び出し関数についてスタブを生成し(ステップS23)、スタブ格納部1042に格納する。スタブはドライバから呼び出され、呼び出しに応じてシンボルを返すプログラムである。図17に、生成されるスタブの一例を示す。図17に示したスタブの6行目において、ドライバに対してシンボルを返すようになっている。
前処理部103は、関数fの変数及び呼び出し関数に対応するシンボル変数を設定するためのプログラムであるドライバを生成し(ステップS25)、ドライバ格納部1041に格納する。そして処理を終了する。図18に、生成されるドライバの一例を示す。図18に示したドライバにおいては、3行目及び4行目においてシンボル変数を設定し、5行目においてスタブを呼び出し、6行目においてfuncAを呼び出している。
以上のような処理を実行すれば、関数単体でシンボリック実行を行えるようになる。
図15の説明に戻り、ドライバ及びスタブが生成されると、シンボリック実行部105は、関数fについてシンボリック実行を行う(ステップS11)。ステップS11の処理については、図19乃至図44を用いて説明する。なお、図19にける「シンボリック実行(p)」とは、実行状態pについてシンボリック実行を行うことを表している。
まず、シンボリック実行部105は、状態データ格納部106に格納されている、状態pのプログラムカウンタの値に基づき、命令を1つ読み出す(図19:ステップS31)。例えばプログラムカウンタの値が「2」である場合、関数fの2行目の命令を読み出す。以下では、ステップS31において読み出された命令を「処理対象の命令」と呼ぶ。
シンボリック実行部105は、処理対象の命令が、関数を呼び出す命令であるか判断する(ステップS33)。関数を呼び出す命令ではない場合(ステップS33:Noルート)、ステップS43の処理に移行する。
一方、関数を呼び出す命令である場合(ステップS33:Yesルート)、シンボリック実行部105は、呼び出される関数ffの引数に関数ポインタが含まれるか判断する(ステップS35)。関数ffの引数に関数ポインタが含まれていない場合(ステップS35:Noルート)、ステップS39の処理に移行する。関数ffの引数に関数ポインタが含まれている場合(ステップS35:Yesルート)、シンボリック実行部105は、関数ポインタについての条件を、実行中のパスについての条件に追加する(ステップS37)。
図20乃至図25を用いて、ステップS37の処理について説明する。例えば、プログラム格納部102に格納されているプログラムが図20に示すプログラムであるとする。このプログラムにおいては、funcAがfuncBを呼び出し、funcBがfuncCを呼び出す。従って、このプログラムのコールツリーは、図21に示すようになる。
このプログラムにおいては、funcAの4行目においてfuncBを呼び出しているが、funcBの引数には関数ポインタ(*p)が含まれている。このような場合においては、funcB単体についてシンボリック実行を行ったとしても、funcBがfuncCに依存しているということを特定することができない。
そこで、図22に示すように、funcAについてのパスのうちfuncBを呼び出すパスについては、「funcB_p==funcC」という条件を追加する。これにより、関数ポインタが指す関数を、条件の統合時に特定できるようになる。
また、関数ポインタを呼び出す場合を区別できるようにするため、図23に示すように、funcBについての条件において「funcC」を「*p」に置き換える。
なお、funcCについての条件及び返却値は通常どおり生成されるので、図24に示すようになる。
ここで、funcAについての条件と、funcBについての条件とを、後述の統合処理によって統合すると、図25に示すようになる。図25においては、条件に2つの括弧が含まれており、左側の括弧にはfuncAについての条件が含まれ、右側の括弧にはfuncBについての条件が含まれる。2つの括弧内の条件は、論理積によって結合されている。統合の際には、funcAについての条件に含まれる「funcB_p==funcC」という条件を用いて、funcBについての条件に含まれる「*p」をfuncCに置き換える。
図19の説明に戻り、シンボリック実行部105は、関数ffの実引数と仮引数との関係を表す条件を、実行中のパスについての条件に追加する(ステップS39)。ステップS39において追加される条件は、例えば、図8のB−(3)における「funcC_x==x+1」が該当する。
なお、関数ffが複数回呼び出される場合、ステップS39においては、引数についての条件が呼び出し毎に追加される。これについては、図26乃至図32を用いて説明する。
例えば図26に示すプログラムにおいては、funcAの4行目及び5行目の処理によって、funcBが3回呼び出される。従って、このプログラムのコールツリーは、図27に示すようになる。
このような場合、図28に示すように、funcAについての条件には、funcBの引数についての条件がfuncBの呼び出し毎に追加される。すなわち、A−(2)及びA−(3)の条件に対しては「funcB_0_x==x」という条件、「funcB_1_x==x+1」という条件、及び「funcB_2_x==x+2」という条件が追加される。
funcBについての条件は、図29に示すように、呼び出し毎に条件表を生成する。図26のプログラムの場合、funcBについての条件表は3つ生成される
そして、funcAについての条件と、funcBについての呼び出し毎の条件とを、後述の統合処理によって統合する。図30に、A−(2)とfuncBについての条件とを統合することによって得られる条件を示す。図30においては、条件に4つの括弧が含まれており、左から1番目の括弧にはA−(2)の条件が含まれ、左から2番目の括弧には1回目の呼び出しについての条件が含まれ、左から3番目の括弧には2回目の呼び出しについての条件が含まれ、左から4番目の括弧には3回目の呼び出しについての条件が含まれる。4つの括弧内の条件は、論理積によって結合されている。そして、条件の欄の右に設けられている判定の欄には、条件を満たす解が存在するか否かについての判定結果が示されている。
また、A−(3)とfuncBについての呼び出し毎の条件とを、後述の統合処理によって統合することによって得られる条件は、図31に示すようになる。図31においては、条件に4つの括弧が含まれており、左から1番目の括弧にはA−(3)の条件が含まれ、左から2番目の括弧には1回目の呼び出しについての条件が含まれ、左から3番目の括弧には2回目の呼び出しについての条件が含まれ、左から4番目の括弧には3回目の呼び出しについての条件が含まれる。4つの括弧内の条件は、論理積によって結合されている。そして、条件の欄の右に設けられている判定の欄には、条件を満たす解が存在するか否かについての判定結果が示されている。
よって、判定がSATである条件は、図32に示したA−(1)の条件、A−(3)B0−(2)B1−(2)B2−(1)の条件、A−(3)B0−(2)B1−(1)B2−(2)の条件、A−(3)B0−(1)B1−(2)B2−(2)の条件、及びA−(3)B0−(2)B1−(2)B2−(2)の条件である。これらの5つの条件についてテストデータを求めると、x=0、18、19、20、1となる。
図19の説明に戻り、シンボリック実行部105は、関数ffをコールツリーに追加するための追加処理を実行する(ステップS41)。追加処理については、図33乃至図36を用いて説明する。
まず、シンボリック実行部105は、コールツリー格納部108に格納されているコールツリーに最も後に追加された関数の位置を現在位置に設定する(図33:ステップS71)。
シンボリック実行部105は、関数ffはコールツリーにおける現在位置より上位の位置に存在するか判断する(ステップS73)。
現在位置より上位の位置に存在しない場合(ステップS73:Noルート)、再帰呼び出しには該当しないので、シンボリック実行部105は、コールツリーにおける現在位置の下に関数ffを追加する(ステップS75)。一方、現在位置より上位の位置に存在する場合(ステップS73:Yesルート)、再帰呼び出しに該当する。そこで、シンボリック実行部105は、関数ffについての条件を、実行中のパスについての条件から削除する(ステップS77)。そして呼び出し元の処理に戻る。
図34乃至図36を用いて、追加処理についてより具体的に説明する。例えば、図34に示すようなプログラム「rec3」があるとする。rec3においては、4行目においてrec1を呼び出している。rec3が呼び出される前にrec1が呼び出されていないのであれば、再帰呼び出しには該当しないので問題は無い。しかしながら、例えば図35の左側のコールツリーに示すように、rec1においてrec2を呼び出し、rec2においてrec3を呼び出し、rec3においてrec1を呼び出すという呼び出し関係があるとする。このような場合には再帰呼び出しに該当するので、処理が終わらなくなる可能性がある。
そこで、コールツリーにおける2回目のrec1を削除することにより、図35の左側のコールツリーを右側のコールツリーに示すように変える。また、図36に示すように、直前のステップS39等において追加されたrec1についての条件を、実行中のパスについての条件から削除する。具体的には、A−(2)から「rec1_ret>0 ∧ rec1_x==x」を削除し、A−(3)から「rec1_ret<=0 ∧ rec1_x==x」を削除する。
以上のような処理を実行すれば、再帰呼び出しによって同じ処理が繰り返し行われてしまうことを防げるようになる。
図19の説明に戻り、シンボリック実行部105は、処理対象の命令がグローバル変数を読み込む命令又は書き込む命令であるか判断する(ステップS43)。グローバル変数を読み込む命令又は書き込む命令のいずれでもない場合(ステップS43:Noルート)、処理は端子Aを介して図44のステップS49に移行する。一方、グローバル変数を読み込む命令又は書き込む命令である場合(ステップS43:Yesルート)、ステップS45の処理に移行する。そして、グローバル変数を読み込む命令である場合、シンボリック実行部105は、読み込みに対応する書き込みの命令を、コールツリー格納部108に格納されているコールツリーによって特定する(ステップS45)。なお、グローバル変数を書き込む命令である場合には、ステップS45の処理は行われない。
シンボリック実行部105は、ステップS43においてグローバル変数の読み込みであると判定された場合にはグローバル変数の読み込みについての条件を、ステップS43においてグローバル変数の書き込みであると判定された場合にはグローバル変数の書き込みについての条件を、実行中のパスについての条件に追加する(ステップS47)。処理は端子Aを介して図44のステップS49に移行する。
図37乃至図43を用いて、ステップS43乃至S47において実行される処理について具体的に説明する。例えば図37に示すようなプログラムが有るとする。図37のプログラムにおいては、プログラム370においてグローバル変数zが定義されている。また、funcAの3行目乃至5行目の処理によってaddz及びfuncBが2回呼び出され、funcBにおいてfuncCが呼び出される。従って、このプログラムのコールツリーは、図38に示すようになる。
ステップS45においては、図38に示すように、グローバル変数zの読み込みに対応する書き込みを特定する。これにより、グローバル変数zの書き込みが複数回行われる場合であっても、それぞれの書き込みに対応する読み込みの条件を生成できるようになる。なお、コールツリーは左側から順に生成されることを前提とする。
従って、図37に示したプログラム370について生成される条件は図39に示すようになり、図37に示したfuncAについて生成される条件及び返却値は図40に示すようになり、図37に示したfuncBについて生成される返却値は図41に示すようになり、図37に示したfuncCについて生成される条件及び返却値は図42に示すようになる。本例においては、プログラム370、funcB、及びfuncCが2回呼び出されているため、呼び出し毎に条件が生成されるようになっている。また、ステップS45の処理によって、書き込みについての条件であるZ0−(1)には読み込みについての条件であるC0−(1)及びC0−(2)が対応付けられ、書き込みについての条件であるZ1−(1)には読み込みについての条件であるC1−(1)及びC1−(2)が対応付けられる。
そして、図39乃至図42に示した条件及び返却値についての条件を、後述の統合処理によって統合すると、図43に示すようになる。図43においては、funcAについての条件と、プログラム370についての呼び出し毎の条件と、funcBについての呼び出し毎の条件と、funcCについての呼び出し毎の条件とが統合されている。そして、条件の欄の右に設けられている判定の欄には、条件を満たす解が存在するか否かについての判定結果が示されている。
図44の説明に移行し、シンボリック実行部105は、処理対象の命令がシンボルに関わる分岐の命令であるか判断する(図44:ステップS49)。シンボルに関わる分岐の命令とは、例えば、if文にシンボル変数が含まれている命令である。
シンボルに関わる分岐の命令である場合(ステップS49:Yesルート)、シンボリック実行部105は、新たにシンボリック実行が行われる実行状態Pに実行状態p(すなわち、状態データ格納部106にデータが格納されている現在の実行状態)をコピーする(ステップS51)。
シンボリック実行部105は、処理対象の命令において未処理の分岐先を1つ特定する(ステップS53)。そして、シンボリック実行部105は、分岐の条件(すなわち、パス条件)を、実行中のパスについての条件に追加する(ステップS55)。
シンボリック実行部105は、実行状態Pについてのシンボリック実行を再帰的に行う(ステップS57)。
ステップS57におけるシンボリック実行が完了すると、シンボリック実行部105は、処理対象の命令において未処理の分岐先が有るか判断する(ステップS59)。未処理の分岐先が有る場合(ステップS59:Yesルート)、次の分岐先について処理するため、ステップS53の処理に戻る。一方、未処理の分岐先が無い場合(ステップS59:Noルート)、呼び出し元の処理に戻る。
一方、処理対象の命令がシンボルに関わる分岐ではない場合(ステップS49:Noルート)、新たにシンボリック実行を行わなくてもよい。従って、シンボリック実行部105は、処理対象の命令を実行し、状態データ格納部106に格納されているプログラムカウンタの値を1進める(ステップS61)。
シンボリック実行部105は、実行状態pは終了の状態であるか判断する(ステップS63)。終了の状態とは、例えば、プログラムカウンタの値がプログラムにおける最後の行の番号に達している状態である。終了の状態ではない場合(ステップS63:Noルート)、次の命令について処理するため、ステップS31の処理に戻る。
一方、実行状態pは終了の状態である場合(ステップS63:Yesルート)、シンボリック実行部105は、シンボリック実行によって得られた、各パスについての条件及び返却値を含む条件表を条件表格納部107に格納する(ステップS65)。そして呼び出し元の処理に戻る。
以上のような処理を実行すれば、各関数についてシンボリック実行を行い、満たすべき条件及び関数の返却値についてのデータを条件表格納部107に保存できるようになる。なお、各関数についてのシンボリック実行の結果(すなわち、条件表)は、条件表格納部107に保存され、ステップS7の処理において再利用することができる。
図15の説明に戻り、シンボリック実行部105は、統合処理の実行を統合処理部109に指示する。これに応じ、統合処理部109は、条件表格納部107に格納されている条件表を用いて統合処理を実行する(ステップS13)。統合処理については、図45を用いて説明する。なお、上で述べたように、統合処理部109は、統合処理を実行するにあたり条件表格納部107における返却値を条件に変換する。
まず、統合処理部109は、条件表格納部107に、統合すべき2つの条件表(ここでは、条件表A及び条件表Bとする)が有るか判断する(図45:ステップS81)。統合すべき2つの条件表A及びBが存在しない場合(ステップS81:Noルート)、呼び出し元の処理に戻る。
一方、統合すべき2つの条件表A及びBが存在する場合(ステップS81:Yesルート)、統合処理部109は、条件表Aから未処理の条件(ここでは、条件aとする)を1つ特定する(ステップS83)。また、統合処理部109は、条件表Bから未処理の条件(ここでは、条件bとする)を1つ特定する(ステップS83)。ステップS83及びS85において、統合処理部109は、パス単位で条件を特定する。
統合処理部109は、条件aと条件bとの論理積を求めることにより、条件cを生成し(ステップS87)、メインメモリ等の記憶装置に格納する。
統合処理部109は、条件cを満たす解が存在するか、例えばソルバによって判断する(ステップS89)。条件cを満たす解が存在しない場合(ステップS89:Noルート)、ステップS93の処理に移行する。一方、条件cを満たす解が存在する場合(ステップS89:Yesルート)、統合処理部109は、条件cを条件表Cに追加する(ステップS91)。なお、条件表Cが存在しない場合には、ステップS91において新たに条件表Cが生成される。
統合処理部109は、条件表Bに未処理の条件が有るか判断する(ステップS93)。未処理の条件が有る場合(ステップS93:Yesルート)、次の条件について処理するため、ステップS85の処理に戻る。一方、条件表Bに未処理の条件が無い場合(ステップS93:Noルート)、統合処理部109は、条件表Bにおける条件を全て未処理に設定する(ステップS95)。
統合処理部109は、条件表Aに未処理の条件が有るか判断する(ステップS97)。未処理の条件が有る場合(ステップS97:Yesルート)、次の条件について処理するため、ステップS83の処理に戻る。一方、条件表Aに未処理の条件が無い場合(ステップS97:Noルート)、統合処理部109は、条件表Cを条件表格納部107に格納し、呼び出し元の処理に戻る。
以上のような処理を実行すれば、各関数について生成された条件をまとめることができるようになる。
図15の説明に戻り、統合処理部109は、シンボリック実行部105に、統合処理の完了を通知する。これに応じ、シンボリック実行部105は、統合後の条件が下位関数に依存しているか判断する(ステップS15)。統合後の条件が下位関数に依存しているとは、統合後の条件に下位関数が含まれるということである。統合後の条件が下位関数に依存している場合(ステップS15:Yesルート)、処理対象の関数fをその下位関数とし(ステップS17)、ステップS3の処理に戻る。
統合後の条件が下位関数に依存していない場合(ステップS15:Noルート)、シンボリック実行部105は、テストデータ生成部110に処理の実行を指示する。これに応じ、テストデータ生成部110は、統合後の条件を満たすシンボル変数の値をソルバによって算出し、算出されたシンボル変数の値を含むテストデータを生成し(ステップS19)、テストデータ格納部111に格納する。そして処理を終了する。なお、テストデータ格納部111に格納されるデータは、例えば図14に示したようなデータである。
以上のような処理を実行すれば、シンボリック実行時に使用する計算資源の量を減らせるようになる。具体的には、シンボリック実行中においてメモリに保持するデータの量を減らすことができるようになる。
これについて、図46及び図47を用いて説明する。本実施の形態においては、引数毎に生成された条件及び返却値についての条件によってメモリ使用量は増えるが、状態保存のためのメモリ使用量は減る。
まず、本実施の形態におけるメモリ使用量の増加について検討する。関数fにおける引数の数をn_argfとし、関数fの返却値に含まれる変数の数をn_retfとし、関数fにおけるパス条件の数をn_pathcondfとし、1つの条件ごとのメモリ使用量をMとする。すると、メモリ使用量の増加分は以下の式によって算出される。
但し、状態保存のためのメモリ使用量が支配的であれば、上記の要因で増えるメモリ使用量の増加は無視できる。そこで、(1)状態保存のためのメモリ使用量が支配的であること、(2)深さ優先の探索によってプログラムを実行することを前提として、メモリ使用量の減少について検討する。
以下では、1番目の関数を関数f
1とし、k番目に呼ばれる関数f
kの深さをd
kとし、関数f
kにおける各パスの状態を、
とする。また、状態sにおけるメモリ使用量をM(s)とする。
まず、通常のシンボリック実行について検討する。通常のシンボリック実行において最もメモリ使用量が多くなるのは、一番深い関数についてシンボリック実行が行われている時である。この時、図46に示すように、深さd1において状態sf1,1・・・sf1,d1についてメモリを使用しており、・・・、深さdnにおいて状態s(f1・・・fn),1・・・s(f1・・・fn),dnについてメモリを使用している。なお、f及びdの添え字は本来は下付きであるが、ここではファイル形式の都合により下付きにはしていない。この場合、メモリ使用量は以下の式によって算出される。
次に、本実施の形態の方法について検討する。本実施の形態の方法において最もメモリ使用量が多くなるのは、f1・・・fnの中で最も深い位置にある関数fmについてシンボリック実行を行っている時である。この時、図47に示すように、深さdmにおいて状態sfm,1・・・sfm,dmについてメモリを使用している。この場合、メモリ使用量は以下の式によって算出される。
ここで、両者を比較する。或るk≦nにおいて、状態s(f1・・・fk),dkはスタックにf1・・・fkのコンテキストを持つため、状態sfk,dkよりもメモリ使用量が多くなり、以下の式が成立する。
また、スタックf1・・・fnのコンテキストを保持することになるfnにおいて深さが最大となる場合、以下の式によって算出される値が最大になる。
よって、最悪の場合であっても、本実施の形態の方が以下の量だけメモリ使用量が少ない。
また、本実施の形態によれば、シンボリック実行の量を減らすことができるので、CPUの負荷が減少する。
これについて、図48及び図49を用いて説明する。まず、図48に示すような、n(nは自然数)個の分岐があるプログラムがあるとする。このプログラムにおいては、n回の分岐を経た後に、関数func(x)を実行する。通常のシンボリック実行においては、それぞれのパスにおいて関数func(x)を実行するため、関数func(x)の実行回数はn回である。一方、本実施の形態の方法であれば、関数毎にシンボリック実行を行うため、関数func(x)の実行回数は1回であるので、実行回数を減らすことができる。
また、図49に示すような、同じ関数をn回実行するプログラムがあるとする。このプログラムにおいては、func(x+i)がn回実行される。通常のシンボリック実行においては、コードの実行回数はn回である。これに対し、本実施の形態の方法であれば、コードの実行回数は1回であるので、実行回数を減らすことができる。但し、関数の入力がそれぞれの実行において異なる場合には、それぞれの条件(図49の例の場合、func_x==x、func_x==x+1・・・)を保存することになるため、メモリ使用量は増加することがある。
さらに、本実施の形態においては、関数毎の実行結果が条件表格納部107に保存されているため、関数のコードを変更した場合においてもシンボリック実行を最小限の計算でやり直すことができる。
例えば、図3に示したfuncCを、図50に示すように変更したとする。図50のfuncCは、図3と比較すると、4行目及び5行目に分岐が追加されている。このような場合には、変更後のfuncCについてのみ再度シンボリック実行を行い、図51に示すような条件表を生成する。これに対し、funcA及びfuncBについては変更が無いので、条件表格納部107に保存されている実行結果を再利用する。そして、funcA及びfuncBについての条件と、変更後のfuncCについての条件とを統合する。また、funcAについての条件とfuncBについての条件とを統合した結果が条件表格納部107に格納されている場合には、統合後の条件と変更後のfuncCについての条件とを統合すれば済むので、統合の処理をも減らすことができるようになる。
以上本発明の一実施の形態を説明したが、本発明はこれに限定されるものではない。例えば、上で説明した情報処理装置1の機能ブロック構成は実際のプログラムモジュール構成に一致しない場合もある。
また、上で説明した各テーブルの構成は一例であって、上記のような構成でなければならないわけではない。さらに、処理フローにおいても、処理結果が変わらなければ処理の順番を入れ替えることも可能である。さらに、並列に実行させるようにしても良い。
なお、上で述べた情報処理装置1は、コンピュータ装置であって、図52に示すように、メモリ2501とCPU(Central Processing Unit)2503とハードディスク・ドライブ(HDD:Hard Disk Drive)2505と表示装置2509に接続される表示制御部2507とリムーバブル・ディスク2511用のドライブ装置2513と入力装置2515とネットワークに接続するための通信制御部2517とがバス2519で接続されている。オペレーティング・システム(OS:Operating System)及び本実施例における処理を実施するためのアプリケーション・プログラムは、HDD2505に格納されており、CPU2503により実行される際にはHDD2505からメモリ2501に読み出される。CPU2503は、アプリケーション・プログラムの処理内容に応じて表示制御部2507、通信制御部2517、ドライブ装置2513を制御して、所定の動作を行わせる。また、処理途中のデータについては、主としてメモリ2501に格納されるが、HDD2505に格納されるようにしてもよい。本発明の実施例では、上で述べた処理を実施するためのアプリケーション・プログラムはコンピュータ読み取り可能なリムーバブル・ディスク2511に格納されて頒布され、ドライブ装置2513からHDD2505にインストールされる。インターネットなどのネットワーク及び通信制御部2517を経由して、HDD2505にインストールされる場合もある。このようなコンピュータ装置は、上で述べたCPU2503、メモリ2501などのハードウエアとOS及びアプリケーション・プログラムなどのプログラムとが有機的に協働することにより、上で述べたような各種機能を実現する。
以上述べた本発明の実施の形態をまとめると、以下のようになる。
本実施の形態に係るテストデータ生成方法は、(A)プログラムにおいて実行される複数の関数の各々についてシンボリック実行を行うと共に、シンボル変数に関わる分岐を辿った履歴を表す条件と、当該関数の引数及び返却値についての条件とを含む実行条件を複数の関数の各々について生成し、(B)生成された複数の実行条件を論理積によって統合し、(C)統合後の条件を満たすシンボル変数の値を算出し、算出された当該シンボル変数の値を含むテストデータを生成する処理を含む。
このようにすれば、シンボリック実行の際に保持するデータの量及び計算量が少なくなるので、計算資源の使用量を減らすことができるようになる。
また、上で述べた複数の関数の各々について、シンボル変数を設定するためのプログラムと当該関数において呼び出される関数のスタブとを生成してもよい。このようにすれば、単一の関数について適切にシンボリック実行を行えるようになる。
また、上で述べた実行条件を生成する処理において、(a1)関数の引数に関数ポインタが含まれる場合に、当該関数ポインタと当該関数ポインタが指す関数との関係を表す条件を、実行条件に追加してもよい。このようにすれば、条件の統合時に、関数ポインタが指す関数を特定できるようになる。
また、上で述べた実行条件を生成する処理において、(a2)プログラムにグローバル変数が含まれる場合、当該グローバル変数の読み込みについての条件及び書き込みについての条件を、実行条件に追加してもよい。このようにすれば、グローバル変数が使用される場合にも適切に対処できるようになる。
また、上で述べた実行条件を生成する処理において、(a3)関数において同一の関数を複数回呼び出す場合、呼び出される当該関数の引数についての条件を複数回の呼び出し毎に生成し、実行条件に追加してもよい。このようにすれば、考慮すべき条件の取りこぼしを防げるようになる。
また、上で述べた実行条件を生成する処理において、(a4)関数間の関係を表すコールツリーを生成し、(a5)コールツリーの端に追加された関数が、再帰呼び出しされる関数である場合、コールツリーの端に追加された関数について生成された条件を削除してもよい。このようにすれば、不要な条件が追加されることを防げるようになる。
なお、上記方法による処理をコンピュータに行わせるためのプログラムを作成することができ、当該プログラムは、例えばフレキシブルディスク、CD−ROM、光磁気ディスク、半導体メモリ、ハードディスク等のコンピュータ読み取り可能な記憶媒体又は記憶装置に格納される。尚、中間的な処理結果はメインメモリ等の記憶装置に一時保管される。
以上の実施例を含む実施形態に関し、さらに以下の付記を開示する。
(付記1)
プログラムにおいて実行される複数の関数の各々についてシンボリック実行を行うと共に、シンボル変数に関わる分岐を辿った履歴を表す条件と、当該関数の引数及び返却値についての条件との少なくともいずれかを含む実行条件を前記複数の関数の各々について生成し、
生成された複数の実行条件を論理積によって統合し、
統合後の条件を満たすシンボル変数の値を算出し、算出された当該シンボル変数の値を含むテストデータを生成する
処理をコンピュータに実行させるためのテストデータ生成プログラム。
(付記2)
前記複数の関数の各々について、シンボル変数を設定するためのプログラムと当該関数において呼び出される関数のスタブとを生成する
処理をさらに実行させるための付記1記載のテストデータ生成プログラム。
(付記3)
前記実行条件を生成する処理において、
前記関数の引数に関数ポインタが含まれる場合に、当該関数ポインタと当該関数ポインタが指す関数との関係を表す条件を、前記実行条件に追加する
ことを特徴とする付記1又は2記載のテストデータ生成プログラム。
(付記4)
前記実行条件を生成する処理において、
前記プログラムにグローバル変数が含まれる場合、当該グローバル変数の読み込みについての条件及び書き込みについての条件を、前記実行条件に追加する
ことを特徴とする付記1乃至3のいずれか1つ記載のテストデータ生成プログラム。
(付記5)
前記実行条件を生成する処理において、
前記関数において同一の関数を複数回呼び出す場合、呼び出される当該関数の引数についての条件を前記複数回の呼び出し毎に生成し、前記実行条件に追加する
ことを特徴とする付記1乃至4のいずれか1つ記載のテストデータ生成プログラム。
(付記6)
前記実行条件を生成する処理において、
関数間の関係を表すコールツリーを生成し、
前記コールツリーの端に追加された関数が、再帰呼び出しされる関数である場合、前記コールツリーの端に追加された関数について生成された条件を削除する
ことを特徴とする付記1記載のテストデータ生成プログラム。
(付記7)
プログラムにおいて実行される複数の関数の各々についてシンボリック実行を行うと共に、シンボル変数に関わる分岐を辿った履歴を表す条件と、当該関数の引数及び返却値についての条件との少なくともいずれかを含む実行条件を前記複数の関数の各々について生成し、
生成された複数の実行条件を論理積によって統合し、
統合後の条件を満たすシンボル変数の値を算出し、算出された当該シンボル変数の値を含むテストデータを生成する
処理をコンピュータが実行するテストデータ生成方法。
(付記8)
プログラムにおいて実行される複数の関数の各々についてシンボリック実行を行うと共に、シンボル変数に関わる分岐を辿った履歴を表す条件と、当該関数の引数及び返却値についての条件との少なくともいずれかを含む実行条件を前記複数の関数の各々について生成する第1処理部と、
生成された複数の実行条件を論理積によって統合する第2処理部と、
統合後の条件を満たすシンボル変数の値を算出し、算出された当該シンボル変数の値を含むテストデータを生成する第3処理部と、
を有するテストデータ生成装置。