(57)【要約】【課題】一貫性破壊の障害検出を短い時間で行え、かつ誤検出が少ない一貫性破壊検出装置、一貫性破壊検出プログラム、及び一貫性破壊検出方法を提供する。【解決手段】一貫性破壊検出装置２０００は、並行メソッド抽出部２２００、更新系メソッド抽出部２４００、及びプローブ挿入部２６００を有する。並行メソッド抽出部２２００は、プログラム１０から並行実行されうるメソッドである並行メソッドを抽出する。更新系メソッド抽出部２４００は、並行メソッドのうち、スレッド間の共有変数を更新するものをスレッドアンセーフな並行メソッドとし、スレッド間で共有され、かつスレッドアンセーフな並行メソッドが更新する変数を更新変数とし、「スレッドアンセーフな並行メソッド、更新変数」の組み合わせを抽出する。プローブ挿入部２６００は、上記スレッドアンセーフな並行メソッド内において、上記更新変数を更新する命令の前又は後ろにプローブを挿入する。【選択図】図１
2014038467.tif 000002
【特許請求の範囲】
【請求項１】
プログラムを取得し、該プログラムの中から、並行に実行されうるメソッドである並行メソッドを抽出し、並行メソッドリストを生成する並行メソッド抽出手段と、
前記プログラムと前記並行メソッドリストに基づいて、スレッド間で共有される変数を更新する並行メソッドであるスレッドアンセーフな並行メソッドと、前記スレッドアンセーフな並行メソッドが更新する変数である更新変数とを組み合わせて抽出する更新系メソッド抽出手段と、
前記スレッドアンセーフな並行メソッドと前記更新変数の組み合わせに基づき、前記プログラムにおいて、該スレッドアンセーフな並行メソッド内にある、該更新変数を更新する命令の前又は後ろに、検査用の命令列を挿入するプローブ挿入手段を有する一貫性破壊検出装置。
【請求項２】
前記並行メソッド抽出手段は、
前記プログラムの中から、並行に実行されるメソッド列の起点となるメソッドを検出し、起点メソッドとして抽出する並行ＡＰＩ抽出手段と、
前記起点メソッドを起点としたコールフローグラフを生成するコールフローグラフ生成手段と、
前記コールフローグラフに含まれるメソッドを並行メソッドとして、並行メソッドリストを生成するコールフロートレース手段と、
を有する請求項１記載の一貫性破壊検出装置。
【請求項３】
前記更新系メソッド抽出手段は、
前記並行メソッドリストから前記並行メソッドを取得し、該並行メソッドの定義を取得するメソッド取得手段と、
前記メソッド取得手段により取得された前記並行メソッドの定義に基づいて、該並行メソッド内の制御フローを示す制御フローグラフに、該並行メソッドに含まれる各分岐命令の種類を示す分岐識別情報を付加した構造化制御フローグラフを生成する構造化制御フローグラフ生成手段と、
前記構造化制御フローグラフを解析し、前記並行メソッドの定義に含まれる変数のうち、前記構造化制御フローが示すいずれかの制御フローにおいて、スレッド間で共有され、かつ、更新される変数を、前記更新変数として抽出する更新変数分析手段と、
前記取得された並行メソッドと前記更新変数を対応づけて抽出する更新系メソッド出力手段と、
を有する請求項１又は２記載の一貫性破壊検出装置。
【請求項４】
前記更新変数分析手段は、
前記メソッド取得手段が取得した前記並行メソッドの定義に含まれる変数ごとに、変数の更新の有無を示す情報である更新情報、及び該変数と同一のアドレスを参照している他の変数を示す情報である参照先同一変数情報を記録する変数リストを生成し、
前記構造化制御フローグラフの始点から順に命令を１つずつ取得し、
取得された前記命令によって変数が更新された場合は、該変数に関する前記更新情報を更新有りとし、
取得された前記命令によって、変数と他の変数が同一のアドレスを参照するようになった場合は、該変数に関する前記参照先同一変数情報に、該他の変数を加え、
前記変数リストを参照し、前記更新情報において更新有りとされている前記変数、及び、前記参照先同一変数情報において該変数と参照するアドレスが同一であるとされている前記他の変数を前記更新変数とすることを特徴とする請求項３記載の一貫性破壊検出装置。
【請求項５】
前記構造化制御フローグラフ生成手段は、
前記並行メソッドの定義を取得し、該並行メソッド内の命令列の制御の流れを表す初期制御フローグラフを生成する初期制御フローグラフ生成手段と、
前記初期制御フローグラフに示される前記命令列の中から、ループ処理を継続するか否かの判定を行う命令をループ判定命令として抽出し、抽出された該ループ判定命令をループリストに登録するループ抽出手段と、
前記初期制御フローグラフに示される前記命令列の中から、分岐命令であり、かつ、ループ判定命令ではない命令を条件分岐命令として抽出し、抽出された該条件分岐命令を条件分岐リストに登録する条件分岐抽出手段と、
前記初期制御フローグラフ、前記ループリスト、及び前記条件分岐リストに基づいて、前記初期制御フローグラフに示される分岐命令ごとに、前記ループ判定命令と前記条件分岐命令のどちらであるかを示す情報を、分岐識別情報として付加して構造化制御フローグラフを生成する構造化手段と、
を有する請求項４に記載の一貫性破壊検出装置。
【請求項６】
前記更新変数分析手段は、
前記構造化制御フローグラフから取り出された命令に、前記条件分岐命令を示す分岐識別情報が付加されている場合は、各条件分岐について、該構造化制御フローグラフの中から、該条件分岐命令の次の命令から条件分岐の終了までの命令を示す部分グラフを前記構造化制御フローグラフとして再帰実行し、
前記構造化制御フローグラフから取り出された命令に、前記ループ判定命令を示す分岐識別情報が付加されている場合は、前記変数リストが更新されなくなるまで、該ループ判定命令の次の命令からループ処理の終了までの命令を示す部分グラフを前記構造化制御フローグラフとした再帰実行を繰り返すことを特徴とする請求項５記載の一貫性破壊検出装置。
【請求項７】
前記更新変数分析手段は、作業領域としてスタックを有し、前記構造化制御フローグラフから取り出された命令の種類を調べ、
前記命令がＬｏａｄ系命令である場合は、前記命令の内容に応じて前記スタックをｐｕｓｈし、
前記命令がＳｔｏｒｅ系命令である場合は、前記命令の内容に応じて前記スタックをｐｏｐし、前記命令の対象となっている変数に関する変数表の参照先同一変数に、Ｓｔｏｒｅ系命令の対象となっている別の変数を加え、
前記命令が更新系命令の場合は、前記命令の内容に応じて前記スタックを処理し、前記命令によって更新される変数に関する変数リストにおいて、更新情報を更新ありに変更し、
前記命令がメソッドを起動する命令の場合は、前記命令の内容に応じて前記スタックを処理し、前記命令が起動するメソッドについて生成された更新変数表を参照して、該更新変数表が更新変数として示している変数について、前記変数リストの更新情報を更新有りに変更することを特徴とする請求項４乃至６いずれか一項に記載の一貫性破壊検出装置。
【請求項８】
前記コールフローグラフ生成手段は、
前記プログラム及び前記起点メソッドを取得し、前記起点メソッドから到達可能なメソッドのそれぞれについて、該メソッドが呼び出すメソッドの一覧である呼び出し先メソッドリストを生成するメソッド内呼び出し抽出手段と、
前記プログラムの中から、クラス間の階層関係を表すクラス階層グラフを生成するクラス階層抽出手段と、
クラス階層グラフを参照し、前記呼び出し先メソッドリストに含まれるメソッドのそれぞれについて、該メソッドをオーバライドしたメソッドの一覧であるオーバライドメソッドリストを生成するオーバライドメソッド抽出手段と、
前記起点メソッドから到達可能な前記各メソッドについて、該メソッドの前記呼び出し先メソッドリスト及び該呼び出し先メソッドリストに関する前記オーバライドメソッドリストに基づいて、始点ノードが該メソッドであり、終端ノードが該メソッドリスト又は該オーバライドメソッドリストに含まれるメソッドである部分グラフを生成し、前記部分グラフを連結して、前記起点メソッドを始点ノードとするコールフローグラフを生成するグラフ生成手段と、
を有する請求項２乃至７いずれか一項に記載の一貫性破壊検出装置。
【請求項９】
コンピュータに、並行実行されるプログラムにおける一貫性破壊を検出する機能を持たせる一貫性破壊検出プログラムであって、
前記コンピュータに、
プログラムを取得し、該プログラムの中から、並行に実行されうるメソッドである並行メソッドを抽出し、並行メソッドリストを生成する並行メソッド抽出機能と、
前記プログラムと前記並行メソッドリストに基づいて、スレッド間で共有される変数を更新する並行メソッドであるスレッドアンセーフな並行メソッドと、前記スレッドアンセーフな並行メソッドが更新する変数である更新変数とを組み合わせて抽出する更新系メソッド抽出機能と、
前記スレッドアンセーフな並行メソッドと前記更新変数の組み合わせに基づき、前記プログラムにおいて、該スレッドアンセーフな並行メソッド内にある、該更新変数を更新する命令の前又は後ろに、検査用の命令列を挿入するプローブ挿入機能を持たせる一貫性破壊検出プログラム。
【請求項１０】
コンピュータが、並行実行するプログラムにおける一貫性破壊を検出する一貫性破壊検出方法であって、
前記コンピュータが、プログラムを取得し、該プログラムの中から、並行に実行されうるメソッドである並行メソッドを抽出し、並行メソッドリストを生成する並行メソッド抽出ステップと、
前記コンピュータが、前記プログラムと前記並行メソッドリストに基づいて、スレッド間で共有される変数を更新する並行メソッドであるスレッドアンセーフな並行メソッドと、前記スレッドアンセーフな並行メソッドが更新する変数である更新変数とを組み合わせて抽出する更新系メソッド抽出ステップと、
前記コンピュータが、前記スレッドアンセーフな並行メソッドと前記更新変数の組み合わせに基づき、前記プログラムにおいて、該スレッドアンセーフな並行メソッド内にある、該更新変数を更新する命令の前又は後ろに、検査用の命令列を挿入するプローブ挿入ステップを有する一貫性破壊検出方法。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は、一貫性破壊検出装置、一貫性破壊検出プログラム、及び一貫性破壊検出方法に関する。
【背景技術】
【０００２】
コンピュータプログラムの信頼性を向上させるため、テスト時や運用時において、プログラムの並行実行により発生する一貫性破壊を検出することが求められている。ここでいう一貫性破壊とは、変数を共有する複数のスレッドが、その共有されている変数に対して同時にアクセスすることにより、プログラムの実行状態が、プログラマの意図とは異なる状態になることを指す。
【０００３】
特許文献１には、静的解析技術とモデル検査技術を使って、並行性による一貫性破壊 (データレース)の発生のエラートレースを、実行時前に発見する方法を提案している。
【０００４】
非特許文献１には、静的解析によりＪａｖａ（登録商標）プログラムのバグの可能性を実行前に検出するツールが記載されている。上記ツールでは、プログラムの実行前に、そのプログラムに含まれるスレッドアンセーフなメソッドに対して、スレッドアンセーフであることを示す注釈（ａｎｎｏｔａｔｉｏｎ）をプログラマが与える。そして、上記ツールは、注釈が与えられたメソッドに対し、並行同時実行する可能性があるかを静的に解析する。
【先行技術文献】
【特許文献】
【０００５】
【特許文献１】特開２００９−１２３２１６号公報
【非特許文献】
【０００６】
【非特許文献１】Nathaniel Ayewah、J. David Morgenthaler、William Pugh、「Evaluating Static Analysis Defect Warnings On Production Software」、7th ACM SIGPLAN-SIGSOFT Workshop on Program Analysis for Software Tools and Engineering、Advanced Computing Machinery (ACM)、２００７年６月１３日
【発明の概要】
【発明が解決しようとする課題】
【０００７】
一貫性破壊検出装置による一貫性破壊の障害検出にかかる時間を短くする必要がある。特許文献１に記載されているようなモデル検査を用いる検出方法は、プログラムの大きさに対し、指数的に検査に要する時間が長くなる。そのため、モデル検査を用いる方法を、実用的な規模のプログラムの検査に用いると、一貫性破壊の障害検出に長い時間を要する。また、非特許文献１に記載されている技術は、プログラムに注釈を記述する作業に時間がかかるため、一貫性破壊検出にかかる時間が長い。これは、非特許文献１に記載されている技術の場合、プログラマが人手でプログラムを解読し、一貫性破壊の障害が起こりうる箇所を見つけ出して注釈を入れる必要があるためである。
【０００８】
本発明の目的は、一貫性破壊の障害検出を短い時間で行う一貫性破壊検出装置、及びコンピュータが一貫性破壊検出を行うためのプログラム、及びコンピュータが一貫性破壊の検出を行う方法を提供することである。
【課題を解決するための手段】
【０００９】
本発明が提供する一貫性破壊検出装置は、プログラムを取得し、該プログラムの中から、並行に実行されうるメソッドである並行メソッドを抽出し、並行メソッドリストを生成する並行メソッド抽出手段と、前記プログラムと前記並行メソッドリストに基づいて、スレッド間で共有される変数を更新する並行メソッドであるスレッドアンセーフな並行メソッドと、前記スレッドアンセーフな並行メソッドが更新する変数である更新変数とを組み合わせて抽出する更新系メソッド抽出手段と、前記スレッドアンセーフな並行メソッドと前記更新変数の組み合わせに基づき、前記プログラムに検査用の命令列を挿入するプローブ挿入手段を有する。
【００１０】
本発明が提供する一貫性破壊検出プログラムは、コンピュータに、並行実行されるプログラムにおける一貫性破壊を検出する機能を持たせる。当該プログラムは、前記コンピュータに、プログラムを取得し、該プログラムの中から、並行に実行されうるメソッドである並行メソッドを抽出し、並行メソッドリストを生成する並行メソッド抽出機能と、前記プログラムと前記並行メソッドリストに基づいて、スレッド間で共有される変数を更新する並行メソッドであるスレッドアンセーフな並行メソッドと、前記スレッドアンセーフな並行メソッドが更新する変数である更新変数とを組み合わせて抽出する更新系メソッド抽出機能と、前記スレッドアンセーフな並行メソッドと前記更新変数の組み合わせに基づき、前記プログラムに検査用の命令列を挿入するプローブ挿入機能を持たせる。
【００１１】
本発明が提供する一貫性破壊検出方法は、コンピュータが、並行実行するプログラムにおける一貫性破壊を検出する一貫性破壊検出方法である。当該一貫性破壊検出方法は、前記コンピュータが、プログラムを取得し、該プログラムの中から、並行に実行されうるメソッドである並行メソッドを抽出し、並行メソッドリストを生成する並行メソッド抽出ステップと、前記コンピュータが、前記プログラムと前記並行メソッドリストに基づいて、スレッド間で共有される変数を更新する並行メソッドであるスレッドアンセーフな並行メソッドと、前記スレッドアンセーフな並行メソッドが更新する変数である更新変数とを組み合わせて抽出する更新系メソッド抽出ステップと、前記コンピュータが、前記スレッドアンセーフな並行メソッドと前記更新変数の組み合わせに基づき、前記プログラムに検査用の命令列を挿入するプローブ挿入ステップを有する。
【発明の効果】
【００１２】
本発明によれば、一貫性破壊の障害検出を短い時間で行う一貫性破壊検出装置、及びコンピュータが一貫性破壊検出を行うためのプログラム、及びコンピュータが一貫性破壊の検出を行う方法が提供される。
【図面の簡単な説明】
【００１３】
【図１】実施形態１に係る一貫性破壊検出装置を表すブロック図である。
【図２】並行メソッド抽出部を表すブロック図である。
【図３】コールフローグラフ生成部を表すブロック図である。
【図４】更新系メソッド抽出部を表すブロック図である。
【図５】構造化制御フローグラフ生成部を表すブロック図である。
【図６】変数リストの構成を表す図である。
【図７】一貫性破壊検出装置による処理の流れの一例を表すフローチャートである。
【図８】並行メソッド抽出部による処理の流れの一例を表すフローチャートである。
【図９】コールフローグラフ生成部による処理の流れの一例を表すフローチャートである。
【図１０】更新系メソッド抽出部による処理の流れの一例を表すフローチャートである。
【図１１】構造化制御フローグラフ生成部による処理の流れの一例を表すフローチャートである。
【図１２】更新変数分析部による処理全体の流れの一例を表すフローチャートである。
【図１３】更新変数分析部による命令分析処理の流れの一例を表すフローチャートである。
【図１４】実施形態２に係るコールフローグラフ生成部を表すブロック図である。
【図１５】実施形態２に係るコールフローグラフ生成部による処理全体の流れの一例を表すフローチャートである。
【図１６】実施例のプログラムに関するクラス階層グラフを示す図である。
【図１７】実施例のプログラムにおいて、Ｃｏｕｎｔｅｒ＃ｉｎｃを起点メソッドとするコールフローグラフを示す図である。
【図１８】実施例のプログラムにおける構造化制御フローグラフを示す図である。
【図１９】実施例における初期化時の変数リスト、及び実施例において変更された変数リストを示す図である。
【図２０】実施例におけるスレッドアンセーフな並行メソッドと更新変数リストの組み合わせを示す図である。
【発明を実施するための形態】
【００１４】
以下、本発明の実施の形態について、図面を用いて説明する。尚、すべての図面において、同様な構成要素には同様の符号を付し、適宜説明を省略する。
【００１５】
なお、以下に示す説明において、各装置の各構成要素は、ハードウエア単位の構成ではなく、機能単位のブロックを示している。各装置の各構成要素は、任意のコンピュータのＣＰＵ、メモリ、メモリにロードされた本図の構成要素を実現するプログラム、そのプログラムを格納するハードディスクなどの記憶メディア、ネットワーク接続用インタフェースを中心にハードウエアとソフトウエアの任意の組合せによって実現される。そして、その実現方法、装置には様々な変形例がある。
【００１６】
[実施形態１]
＜概要＞
図１は、 本実施形態における一貫性破壊検出装置２０００を、その使用環境と共に示す図である。図において、矢印は情報の流れを示す。
【００１７】
一貫性破壊検出装置２０００は、並行メソッド抽出部２２００を有する。並行メソッド抽出部２２００は、プログラム１０を取得する。プログラム１０は、ソースコード、バイトコード、又はバイトコードに相当する実行媒体である。そして並行メソッド抽出部２２００は、プログラム１０の中から、実行時に並行に動作しうるメソッド（以下、並行メソッド）を抽出し、並行メソッドのリスト（以下、並行メソッドリスト）を生成する。
【００１８】
一貫性破壊検出装置２０００は、更新系メソッド抽出部２４００を有する。更新系メソッド抽出部２４００は、プログラム１０、及び並行メソッドリストを取得する。そして、更新系メソッド抽出部２４００は、並行メソッドリストに含まれる並行メソッドの中から、スレッド間で共有される変数を更新するメソッドを、スレッドアンセーフな並行メソッドとして抽出する。また、更新系メソッド抽出部２４００は、スレッド間で共有される変数であり、かつ、上記スレッドアンセーフな並行メソッドによって更新される変数を、更新変数として抽出し、更新変数のリスト（以下、更新変数リスト）を生成する。更新系メソッド抽出部２４００は、「スレッドアンセーフな並行メソッド、そのメソッドに関する更新変数リスト」の組み合わせを抽出する。
【００１９】
一貫性破壊検出装置２０００はさらに、プローブ挿入部２６００を有する。プローブ挿入部２６００は、「スレッドアンセーフな並行メソッド、更新変数リスト」の組み合わせに基づき、プログラム１０に対し、一貫性破壊検出用の命令列を挿入する。具体的には、プローブ挿入部２６００は、上記スレッドアンセーフな並行メソッド内における、上記更新変数リストに含まれる更新変数を更新する命令の前、又は後ろに、上記一貫性破壊検出用の命令列を挿入する。以下、一貫性破壊障害検出用の命令列を、プローブと呼ぶ。そして、プローブ挿入部２６００は、プローブを挿入したプローブ入りプログラム２０を生成する。
【００２０】
以上のように、本実施形態における一貫性破壊検出装置２０００は、並行メソッド抽出部２２００、更新系メソッド抽出部２４００、及びプローブ挿入部２６００により、「スレッドアンセーフな並行メソッド、更新変数リスト」の組み合わせを抽出する。そして、その組み合わせに基づき、プログラム１０にプローブを挿入し、プローブ入りプログラム２０を生成する。こうすることで、プログラム１０のうち、一貫性破壊の原因となる可能性がある箇所にプローブを挿入する。プローブ入りプログラム２０を実行すると、一貫性破壊が起こった場合に、その一貫性破壊を検出することができる。一貫性破壊検出装置２０００は、プログラム１０の中から、実行時に並行実行されうるメソッド（並行メソッド）を抽出し、抽出した並行メソッドに関してのみ一貫性破壊が起こるか否かを検証する。そのため、一貫性破壊検出装置２０００は、プログラムの実行経路を網羅的に検査するモデル検査に比べ、一貫性破壊の検出にかかる時間を短くすることができる。さらに、一貫性破壊検出装置２０００は、プローブ入りプログラム２０において、プローブが挿入されている部分、つまりは、一貫性破壊の障害が起こりうる部分が実際に実行された場合のみ、一貫性破壊障害の検出が行われる。そのため、一貫性破壊検出装置２０００は、一貫性破壊障害の誤検出を少なくすることができる。
【００２１】
以下、本実施形態の詳細を述べる。
【００２２】
＜並行メソッド抽出部２２００の構成詳細＞
並行メソッド抽出部２２００の構成は、例えば図２のブロック図に示す構成である。図２に示す並行メソッド抽出部２２００は、並行ＡＰＩ抽出部２２２０、コールフローグラフ生成部２２４０、及びコールフロートレース部２２６０を有する。
【００２３】
並行ＡＰＩ抽出部２２２０は、プログラム１０を取得する。そして、並行ＡＰＩ抽出部２２２０は、プログラム１０の中から、並行に実行されるメソッド列の起点となるメソッドを抽出し、起点メソッドとする。並行ＡＰＩ抽出部２２２０が、起点メソッドを抽出する方法は様々である。並行ＡＰＩ抽出部２２２０は例えば、プログラム１０を記述するために提供されているスレッドライブラリを取得し、上記スレッドライブラリにおいて並行命令を開始するメソッドを特定する。例えば、Ｊａｖａ（登録商標）におけるＴｈｒｅａｄ＃ｒｕｎのオーバライドメソッドや、C言語におけるｐｔｈｒｅａｄ＿ｃｒｅａｔｅ関数に引数として与える関数である。そして、並行メソッド抽出部２２００は、プログラム１０の中から、特定した並行命令を開始するメソッドを割り出し、起点メソッドとする。その他にも例えば、起点メソッドになりうるメソッドの一覧を手動、もしくはファイル等を通じて入力して並行メソッド抽出部２２００に与えてもよい。
【００２４】
プログラム１０において、起点メソッドは複数あってもよい。その場合、起点メソッドごとに、並行メソッドリストを生成する。
【００２５】
コールフローグラフ生成部２２４０は、プログラム１０、及び並行ＡＰＩ抽出部２２２０が抽出した起点メソッドを取得する。そして、コールフローグラフ生成部２２４０は、上記起点メソッドを始点ノードとしたプログラム１０のコールフローグラフ９０を生成する。コールフローグラフ生成部２２４０の詳細については、後述する。
【００２６】
コールフロートレース部２２６０は、コールフローグラフ生成部２２４０が生成したコールフローグラフを取得する。そして、コールフロートレース部２２６０は、コールフローグラフに含まれるメソッドを並行メソッドとする並行メソッドリスト３０を生成する。
【００２７】
このように、一貫性破壊検出装置２０００は、並行メソッド抽出部２２００によって、起点メソッドを抽出し、起点メソッドから到達可能なメソッドのコールフローグラフ９０を生成する。こうすることで、以降の解析の対象を、起点メソッドから到達可能なメソッドに絞り込む。こうすることで、一貫性破壊の危険性のあるメソッドを効率的かつ自動的にリストアップすることができる。
【００２８】
＜コールフローグラフ生成部２２４０の構成詳細＞
コールフローグラフ生成部２２４０の構成は、例えば図３のブロック図で表される。コールフローグラフ生成部２２４０は、メソッド内呼び出し抽出部２２４４を有する。メソッド内呼び出し抽出部２２４４は、プログラム１０及び起点メソッド８０を取得する。さらに、メソッド内呼び出し抽出部２２４４は、プログラム１０の中から、起点メソッド８０から到達可能なメソッドを１つずつ選択する。以下、メソッド内呼び出し抽出部２２４４が選択したメソッドを選択メソッドと表記する。次に、メソッド内呼び出し抽出部２２４４は、上記選択メソッドごとに、選択メソッドの内部から呼び出されるメソッド（以下、呼び出し先メソッド）を抽出する。そして、メソッド内呼び出し抽出部２２４４は、上記選択メソッドごとに、「選択メソッド、呼び出し先メソッド」の組み合わせを示す呼び出し先メソッドリストを生成する。
【００２９】
コールフローグラフ生成部２２４０はさらに、グラフ生成部２２４６を有する。グラフ生成部２２４６は、呼び出し先メソッドリストに基づいて、コールフローグラフ９０を生成する。具体的にはまず、グラフ生成部２２４６は、呼び出し先メソッドリストに基づき、始点ノードが選択メソッドであり、終端ノードが呼び出し先メソッドである部分グラフを生成する。そしてグラフ生成部２２４６は、生成した全ての部分グラフを、同じメソッドを示すノードを重ね合わせて連結することで、コールフローグラフ９０を生成する。生成されたコールフローグラフ９０は、始点ノードが起点メソッドであり、起点メソッドから到達しうるメソッド間のコールフローを示すコールフローグラフとなる。
【００３０】
＜更新系メソッド抽出部２４００の構成詳細＞
更新系メソッド抽出部２４００の構成は、例えば図４に示すブロック図で表される。図４に示す更新系メソッド抽出部２４００は、メソッド取得部２４２０、構造化制御フローグラフ生成部２４４０、及び更新変数分析部２４６０を有する。
【００３１】
メソッド取得部２４２０は、並行メソッドリスト３０を取得する。そして、メソッド取得部２４２０は、並行メソッドリスト３０に示されている並行メソッドの中から１つを選択し、選択した並行メソッドの定義であるメソッド定義４０を取得する。ここで、メソッドの定義とは、プログラム１０において、そのメソッドを表す命令列を指す。例として、以下にｔｅｓｔというメソッドの定義を示す。
【００３２】
int test(int x){
int y = 2;
return x+y;
}
【００３３】
構造化制御フローグラフ生成部２４４０は、メソッド取得部２４２０が取得したメソッド定義４０における制御の流れを解析し、その制御の流れを表す制御フローグラフに、メソッド定義４０に含まれる各分岐命令の種類を示す分岐識別情報を付加した構造化制御フローグラフを生成する。
【００３４】
更新変数分析部２４６０は、構造化制御フローグラフ生成部２４４０が生成した構造化制御フローグラフを取得する。そして、更新変数分析部２４６０は、構造化制御フローグラフを解析し、メソッド取得部２４２０が選択した並行メソッド内の変数の中から、スレッド間で共有される可能性があり、かつ、更新される可能性がある変数を、更新変数として抽出する。更新変数分析部２４６０は、上記選択した並行メソッドにおいて、更新変数が１つ以上存在した場合、上記選択した並行メソッドをスレッドアンセーフな並行メソッド５０とする。また、更新変数分析部２４６０は、抽出された更新変数のリストを生成し、更新変数リスト６０とする。そして、更新変数分析部２４６０は、スレッドアンセーフな並行メソッド５０と更新変数リスト６０を対応づけて抽出する。
【００３５】
＜構造化制御フローグラフ生成部２４４０の構成詳細＞
構造化制御フローグラフ生成部２４４０の構成は、例えば図５に示すブロック図で表される。図５に示す構造化制御フローグラフ生成部２４４０は、初期制御フローグラフ生成部２４４２、ループ抽出部２４４４、条件分岐抽出部２４４６、及び構造化部２４４８を有する。
【００３６】
初期制御フローグラフ生成部２４４２は、メソッド定義４０を取得する。そして、初期制御フローグラフ生成部２４４２は、メソッド定義４０で表される命令の制御の流れを示す初期制御フローグラフを生成する。
【００３７】
ループ抽出部２４４４は、初期制御フローグラフを取得する。そして、ループ抽出部２４４４は、初期制御フローグラフからループ処理を抽出する。ループ処理とは、一定の条件を満たす間、又は一定の条件を満たさない間、繰り返し行われる命令列から構成される処理である。さらに、ループ抽出部２４４４は、上記ループ処理の継続又は終了を判定する命令（以下、ループ判定命令）をループリストに登録する。
【００３８】
条件分岐抽出部２４４６は、初期制御フローグラフ及びループリストを取得する。そして、条件分岐抽出部２４４６は、初期制御フローグラフから分岐命令を抽出し、抽出した分岐命令がループリストに含まれていなければ、その分岐命令を条件分岐命令として、条件分岐リストに登録する。
【００３９】
構造化部２４４８は、ループリスト及び条件分岐リストを参照しながら初期制御フローグラフを解析する。そして、構造化部２４４８は、初期制御フローグラフに含まれる各分岐命令に対し、ループ判定命令であるか、条件分岐命令であるかを示す分岐識別情報を付加した構造化制御フローグラフ７０を生成する。
【００４０】
＜更新変数分析部２４６０の詳細＞
更新変数分析部２４６０は、構造化制御フローグラフ７０を取得する。そして、更新変数分析部２４６０は、空の変数リストを生成する。変数リストは、変数の更新の有無を示す情報である更新情報、及び、その変数と同一のアドレスを参照している他の変数を示す情報である同一参照情報を有する。
【００４１】
変数リストの一例は、例えば図６に示す変数リスト２００である。変数リスト２００は、変数識別子２１０、更新情報２２０、及び参照先同一変数情報２３０を有する。例えば、図６に示す変数表２００の１行目のレコードは、変数ｘは更新されていること、及び、変数ｘは変数ａと同じアドレスを参照していることを示している。
【００４２】
更新変数分析部２４６０は、構造化制御フローグラフ７０が示す命令ごとに、その命令が操作対象としている変数の更新の有無を調べる。変数が更新されていた場合、更新変数分析部２４６０は、その変数に関する変数リストのレコードの更新情報を「更新あり」とする。
【００４３】
また、更新変数分析部２４６０は、構造化制御フローグラフ７０が示す命令ごとに、その命令によって、２つ以上の変数が同一のアドレスを参照するようになったか否かを調べる。上記命令によって２つ以上の変数が同一のアドレスを参照するようになった場合、命令分析部２４６２は、上記変数リストにおける上記各変数の同一参照情報に、同一のアドレスを参照するようになった他の変数を追加する。
【００４４】
更新変数分析部２４６０は、変数リストを参照し、更新情報が更新有りを示している変数を更新変数とし、更新変数リストに加える。また、更新変数分析部２４６０は、変数リストを参照し、更新情報が更新有りとなっている変数に関するレコードにおいて、同一参照情報に示されている変数も、更新変数リストに加える。
【００４５】
＜プローブ挿入部２６００の詳細＞
プローブ挿入部２６００は、プログラム１０、及び「スレッドアンセーフな並行メソッド、更新変数リスト」の組み合わせを取得する。そして、プログラム１０のうち、一貫性破壊の可能性がある箇所に、プローブを挿入し、プローブ入りプログラム２０を生成する。具体的には、プローブ挿入部２６００は、プログラム１０において、上記スレッドアンセーフな並行メソッド内にある、上記更新変数リストに含まれる更新変数を更新する命令の前又は後ろにプローブを挿入する。ここで、プローブを挿入する箇所は、更新変数を更新する命令の直前又は直後には限定されない。更新変数を更新する命令とプローブの間に、他の命令があってもよい。
【００４６】
プローブ挿入部２６００が挿入するプローブは様々である。例えばプローブ挿入部２６００は、スレッドアンセーフな並行メソッドにおいて、更新変数リストに示されている変数を更新する前の部分に、時刻を記録するプローブを挿入する。さらに、プローブ挿入部２６００は、上記並行メソッドにおいて、上記変数を更新した後の部分に、変数更新前に記録した時刻の変更の有無を確認し、時刻が変更されていた場合はエラーを出力するプローブを挿入する。並行メソッドにおいて、変数更新前に記録した時刻が、変数更新後に変更されている場合、他のスレッドによって再度変数が更新されたことを意味する。したがって、上記プローブが挿入されたプローブ入りプログラム２０を実行すると、一貫性破壊の障害が起こった場合は、上記プローブによってエラーが出力される。そのため、上記プローブ入りプログラム２０を実行することで、一貫性破壊の障害を検出することができる。
【００４７】
＜一貫性破壊検出装置２０００による処理の流れ＞
図７は、一貫性破壊検出装置２０００がプログラム１０に対してプローブを挿入する処理の全体的な流れの一例を表すフローチャートである。
【００４８】
ステップＳ１０２において、並行メソッド抽出部２２００は、対象のプログラム１０を取得する。
【００４９】
ステップＳ１０４において、並行メソッド抽出部２２００は、取得したプログラム１０を解析し、並行メソッドリス３０トを生成する。
【００５０】
ステップＳ１０６において、更新系メソッド抽出部２４００は、並行メソッドリスト３０に含まれるメソッドの中から、「スレッドアンセーフな並行メソッド、更新変数リスト」の組み合わせを抽出する。
【００５１】
ステップＳ１０８において、プローブ挿入部２６００は、「スレッドアンセーフな並行メソッド、更新変数リスト」の組み合わせに基づいてプログラム１０へプローブを挿入し、プローブ入りプログラム２０を生成する。
【００５２】
＜並行メソッド抽出部２２００による処理の流れ＞
図８は、並行メソッド抽出部２２００が、並行メソッドリストを作成する処理の流れの一例を表すフローチャートである。
【００５３】
ステップＳ２０２において、並行メソッド抽出部２２００は、プログラム１０を取得する。
【００５４】
ステップＳ２０４において、並行ＡＰＩ抽出部２２２０は、プログラム１０から、起点メソッド８０を抽出する。
【００５５】
ステップＳ２０６において、コールフローグラフ生成部２２４０は、プログラム１０に基づき、上記起点メソッド８０を始点ノードとするコールフローグラフ９０を生成する。
【００５６】
ステップＳ２０８において、コールフロートレース部２２６０は、上記コールフローグラフ９０を辿り、コールフローグラフ９０に含まれるメソッドを並行メソッドとする並行メソッドリスト３０を生成する。
【００５７】
＜コールフローグラフ生成部２２４０による処理の流れ＞
図９は、コールフローグラフ生成部２２４０による処理の流れの一例を示すフローチャートである。
【００５８】
ステップＳ７０２において、コールフローグラフ生成部２２４０は、プログラム１０を取得する。
【００５９】
ステップＳ７０４において、コールフローグラフ生成部２２４０は、起点メソッド８０を取得する。
【００６０】
ステップＳ７０６において、コールフローグラフ生成部２２４０は、空の集合Ｓに起点メソッド８０を加える。
【００６１】
ステップＳ７０８〜ステップＳ７２０は、集合Ｓにメソッドが含まれる間行うループ処理Ａである。ステップＳ７０８において、コールフローグラフ生成部２２４０は、集合Ｓにメソッドが含まれるか否かをチェックする。集合Ｓにメソッドが含まれる場合、コールフローグラフ生成部２２４０は、集合Ｓに含まれるメソッドから１つを取り出し、ステップＳ７１０に進む。集合Ｓにメソッドが含まれない場合、コールフローグラフ生成部２２４０は、ステップＳ７２２に進む。
【００６２】
ステップＳ７１０において、コールフローグラフ生成部２２４０は、集合Ｓと同じ要素から成る集合Ｖを生成する。そして、集合Ｓを空にする。
【００６３】
ステップＳ７１２〜ステップＳ７１８は、集合Ｖに含まれる各メソッドｉについて行うループ処理Ｂである。ステップＳ７１２において、コールフローグラフ生成部２２４０は、集合Ｖに含まれる全てのメソッドをループ処理Ｂの対象としたかをチェックする。集合Ｖの中にループ処理Ｂの対象としていないメソッドがある場合、その中から１つを選択してメソッドｉとし、ステップＳ７１４に進む。一方、集合Ｖに含まれる全てのメソッドについてループ処理Ｂを終えている場合、ステップＳ７２０に進む。
【００６４】
ステップＳ７１４において、メソッド内呼び出し抽出部２２４４は、メソッドｉを選択メソッドとして、呼び出し先メソッドリストを生成する。
【００６５】
ステップＳ７１６において、コールフローグラフ生成部２２４０は、メソッドｉの各呼び出し先メソッドを、集合Ｓに加える。
【００６６】
ステップＳ７１８は、ループ処理Ｂの終端である。そのため、ステップＳ７１２に戻る。
【００６７】
ステップＳ７２０は、ループ処理Ａの終端である。そのため、ステップＳ７０８に戻る。
【００６８】
ステップＳ７２２において、グラフ生成部２２４６は、呼び出し先メソッドリストに基づき、コールフローグラフ９０を生成する。
【００６９】
＜更新系メソッド抽出部２４００による処理の流れ＞
図１０は、更新系メソッド抽出部２４００による処理の流れの一例を示すフローチャートである。
【００７０】
ステップＳ３０２において、メソッド取得部２４２０は、並行メソッドリスト３０を取得する。
【００７１】
ステップＳ３０４〜ステップＳ３１２は、並行メソッドリスト３０に含まれる各並行メソッドについてそれぞれ行うループ処理Ａである。まず、ステップＳ３０４において、メソッド取得部２４２０は、並行メソッドリスト３０に含まれる全ての並行メソッドについてループ処理Ａを行ったかをチェックする。まだループ処理Ａの対象としていない並行メソッドがある場合、その中から１つを選択し、ステップＳ３０６に進む。一方、全ての並行メソッドについてループ処理Ａを終えている場合は、ステップＳ３１４に進む。
【００７２】
ステップＳ３０６において、メソッド取得部２４２０は、上記選択した並行メソッドについて、メソッド定義４０を取得する。
【００７３】
ステップＳ３０８において、構造化制御フローグラフ生成部２４４０は、上記メソッド定義４０に基づいて、構造化制御フローグラフを生成する。
【００７４】
ステップＳ３１０において、更新変数分析部２４６０は、構造化制御フローグラフを解析する。そして、上記選択した並行メソッドについて、更新変数リスト６０を生成する。ここで、変数の更新を行わない並行メソッドの場合は、例えば更新変数リスト６０が空のリストとなる。
【００７５】
ステップＳ３１２は、ループ処理Ａの終端である。そのため、ステップＳ３０４に戻る。
【００７６】
ステップＳ３１４において、更新変数分析部２４６０は、「スレッドアンセーフな並行メソッド、その並行メソッドに関する更新変数リスト６０」の組み合わせを抽出する。
【００７７】
＜構造化制御フローグラフ生成部２４４０による処理の流れ＞
図１１は、構造化制御フローグラフ生成部２４４０による処理の流れの一例を示すフローチャートである。
【００７８】
ステップＳ４０２において、初期制御フローグラフ生成部２４４２は、メソッド定義４０を取得する。
【００７９】
ステップＳ４０４において、初期制御フローグラフ生成部２４４２は、メソッド定義４０に基づき、初期制御フローグラフを生成する。
【００８０】
ステップＳ４０６において、ループ抽出部２４４４は、初期制御フローグラフを辿ってループ判定命令を抽出し、抽出したループ判定命令の一覧を示すループリストを生成する。
【００８１】
ステップＳ４０８において、条件分岐抽出部２４４６は、初期制御フローグラフを辿って分岐命令を抽出する。そして、抽出した分岐命令のうち、ループリストに含まれていない分岐命令を条件分岐命令として抽出し、抽出した条件分岐命令の一覧を示す条件分岐リストを生成する。
【００８２】
ステップＳ４１０において、構造化部２４４８は、初期制御フローグラフ、ループリスト、及び条件分岐リストに基づき、構造化制御フローグラフを生成する。
【００８３】
＜更新変数分析部２４６０による処理の流れ＞
図１２は、更新変数分析部２４６０による更新変数分析処理の流れの一例を示すフローチャートである。
【００８４】
ステップＳ５０２において、更新変数分析部２４６０は、構造化制御フローグラフを取得する。
【００８５】
ステップＳ５０３において、更新変数分析部２４６０は、変数リスト、及び参照先同一変数リストを初期化する。
【００８６】
ステップＳ５０４〜ステップＳ５２８は、構造化制御フローグラフから読み込んでいないノードがある間行うループ処理Ａである。ステップＳ５０４において、更新変数分析部２４６０は、ステップＳ５０２で取得した構造化制御フローグラフに、まだ読み込んでいないノードがあるか否かをチェックする。まだ読み込んでいないノードがある場合、更新変数分析部２４６０は、先頭のノードを読み込む。すでに全てのノードを読み込んでいる場合、更新変数分析部２４６０は、ステップＳ５３０に進む。
【００８７】
ステップＳ５０６において、更新変数分析部２４６０は、ステップＳ５０４で読み込んだノードが示す命令を分析し、変数リストを更新する。ステップＳ５０６における処理の詳細は後述する（図１３参照）。
【００８８】
ステップＳ５０８において、更新変数分析部２４６０は、ステップＳ５０４で読み込んだノードに付加されている分岐識別情報によって、処理を分岐する。上記ノードに条件分岐命令を示す分岐識別情報が付加されている場合、ステップＳ５１０に進む。上記ノードにループ判定命令を示す分岐識別情報が付加されている場合、ステップＳ５２０に進む。上記ノードに分岐識別情報が付加されていない場合、ステップＳ５２８に進む。
【００８９】
ステップＳ５１０〜ステップＳ５１８は、上記ノードが示す命令を始点とする条件分岐の各分岐について行うループ処理Ｂである。ステップＳ５１０において、更新変数分析部２４６０は、全ての分岐についてループ処理Ｂを行ったか否かをチェックする。まだループ処理Ｂを行っていない分岐がある場合は、分岐を一つ選択し、ステップＳ５１２に進む。すでに全ての分岐についてループ処理Ｂを終えている場合は、ステップＳ５２８に進む。
【００９０】
ステップＳ５１２において、変数リスト、及び命令分析に用いる一時作業領域をコピーする。
【００９１】
ステップＳ５１４において、更新変数分析部２４６０は、ステップＳ５０２で取得した構造化制御フローグラフの内、ステップＳ５１０で選択した分岐の開始ノードから、上記分岐が終了する合流ノードまでの間の部分グラフを入力として、更新変数分析処理を再帰実行する。再帰実行する更新変数分析処理において、更新変数分析部２４６０は、上記部分グラフを構造化制御フローグラフとして取得する。また、再帰実行する更新変数分析処理において、更新変数分析部２４６０は、ステップＳ５１２でコピーした変数リスト及び一時作業領域を利用する。
【００９２】
ステップＳ５１６において、更新変数分析部２４６０は、ステップＳ５１４における処理で変更された変数リスト及び一時作業領域のコピーを、コピー元の変数リスト及び一時作業領域にマージする。
【００９３】
ステップＳ５１８は、ループ処理Ｂの終端である。そのため、ステップＳ５１０に戻る。
【００９４】
ステップＳ５２０〜ステップＳ５２６は、ステップＳ５０４で選択したノードにループ判定命令を示す分岐識別情報が付加されている場合に行うループ処理Ｃである。ステップＳ５２０は、ループ処理Ｃの開始処理である。
【００９５】
ステップＳ５２２において、更新変数分析部２４６０は、参照先同一変数リストに、変数リストの内容を追加する。具体的には、更新変数分析部２４６０は、変数リストの参照先同一変数情報において参照先が同一であると示されている変数を、参照先同一変数とし、参照先同一変数リストに加える。
【００９６】
ステップＳ５２４において、更新変数分析部２４６０は、ステップＳ５０２で取得した構造化制御フローグラフの内、ステップＳ５０４で読み込んだノードの次のノードから、ループ処理の終端ノードまでのノードで構成される部分グラフを入力として、更新変数分析処理を再帰実行する。再帰実行する更新変数分析処理において、更新変数分析部２４６０は、上記部分グラフを構造化制御フローグラフとして取得する。
【００９７】
ステップＳ５２６は、ループ処理Ｃの終端である。更新変数分析部２４６０は、現在の変数リスト及び参照先同一変数リストを、前回のループ処理Ｃの終了時における変数リスト又は参照先同一変数リストと比較する。更新変数分析部２４６０は、変数リスト又は参照先同一変数リストのいずれかが変更されていた場合は、さらにループ処理Ｃを行うため、ステップＳ５２０に戻る。一方、変数リスト及び参照先同一変数リストの双方が変更されていない場合、更新変数分析部２４６０は、ループ処理Ｃを終えてステップＳ５２８に進む。
【００９８】
ステップＳ５２８は、ループ処理Ａの終端である。そのため、ステップＳ５０４に戻る。
【００９９】
ステップＳ５３０において、更新変数分析部２４６０は、更新変数リストを生成する。具体的にはまず、更新変数分析部２４６０は、空の更新変数リストを生成する。そして、更新変数分析部２４６０は、変数リストにおいて、更新情報が「更新有り」となっている変数を、更新変数リストに追加する。また、変数リストにおいて、更新情報が「更新有り」となっている変数に関する参照先同一変数情報が示している他の変数も、更新変数リストに加える。さらに、参照先同一変数リストにおいて、更新変数リストが示している変数と参照先が同一であると示されている変数も、更新変数リストに加える。
【０１００】
＜命令分析処理の流れ＞
図１３は、更新変数分析部２４６０が図１２のステップＳ５０４において行う命令分析処理の流れの一例を示すフローチャートである。
【０１０１】
ステップＳ６０２において、更新変数分析部２４６０は、命令の種類を特定し、命令の種類によって以降の処理を分岐する。分析する命令がＬｏａｄ系命令の場合、ステップＳ６０４に進む。ここで、Ｌｏａｄ系命令とは、変数の内容を一時作業領域にコピーする命令を指す。分析する命令がＳｔｏｒｅ系命令の場合、ステップＳ６０６に進む。ここで、Ｓｔｏｒｅ系命令とは、一時作業領域の内容を変数にコピーする命令を指す。分析する命令が更新系命令の場合、ステップＳ６１０に進む。更新系命令とは、変数の値を更新する命令を指す。分析する命令がメソッド呼び出しを行う命令の場合、ステップＳ６１４に進む。分析する命令が上記Ｌｏａｄ系命令、Ｓｔｏｒｅ系命令、更新系命令、及びメソッド呼び出しを行う命令のいずれにも当てはまらない場合、ステップＳ６２０に進む。
【０１０２】
上記一時作業領域は、例えばレジスタ、スタックなどである。本実施形態においては、スタックを一時作業領域とする場合を例に説明する。そのため、更新変数分析部２４６０は、分析用の一時作業領域として、スタックを用いる。以下、更新変数分析部２４６０が分析に用いるスタックを、分析用スタックと呼ぶ。
【０１０３】
ステップＳ６０４は、分析する命令がＬｏａｄ系命令の場合に行う処理である。ステップＳ６０４において、更新変数分析部２４６０は、Ｌｏａｄ系命令の対象としている変数の識別子を、分析用スタックにｐｕｓｈする。
【０１０４】
ステップＳ６０６〜ステップＳ６０８は、分析する命令がＳｔｏｒｅ系命令の場合に行う処理である。まず、ステップＳ６０６において、分析用スタックに格納されている変数の識別子をｐｏｐする。
【０１０５】
ステップＳ６０８において、更新変数分析部２４６０は、変数リストを更新する。具体的には、ステップＳ６０６でｐｏｐした変数と、Ｓｔｏｒｅ系命令が対象としている変数に関する参照先同一変数情報を更新し、お互いに参照先が同一であるとする。
【０１０６】
ステップＳ６１０〜ステップＳ６１２は、分析する命令が更新系命令である場合の処理である。まずステップＳ６１０において、更新変数分析部２４６０は、命令の内容に従って分析用スタックを操作する。具体的には、更新変数分析部２４６０は、その命令を実行した際に、実行中のプログラムの一時作業領域であるスタックに適用される操作と同じ操作を、分析用スタックに対して行う。
【０１０７】
ステップＳ６１２において、更新変数分析部２４６０は、上記更新系命令が更新対象としている変数について、変数リストの更新情報を更新し、「更新有り」とする。
【０１０８】
ステップＳ６１４〜ステップＳ６１８は、分析する命令がメソッド呼び出しの場合の処理である。まずステップＳ６１４において、更新変数分析部２４６０は、ステップＳ６１０と同様に、命令の内容に従って分析用スタックを操作する。
【０１０９】
ステップＳ６１６において、更新変数分析部２４６０は、呼び出すメソッドについて作成された更新変数リストを取得する。
【０１１０】
ステップＳ６１８において、更新変数分析部２４６０は、変数リストが示す変数であり、かつ取得した上記更新変数リストに示されている変数に関し、変数リストの更新情報を更新有りに変更する
【０１１１】
ステップＳ６２０は、分析する命令が上記Ｌｏａｄ系命令、Ｓｔｏｒｅ系命令、更新系命令、及びメソッド呼び出しを行う命令のいずれにも当てはまらない場合の処理である。ステップＳ６２０において、更新変数分析部２４６０は、ステップＳ６１０と同様に、命令の内容に従って分析用スタックを操作する。
【０１１２】
＜作用・効果＞
以上の構成により、本実施形態に係る一貫性破壊検出装置２０００は、並行メソッド抽出部２２００により、プログラム１０の中から、実行時に並行に動作しうる並行メソッドを抽出し、並行メソッドリストを生成する。また、一貫性破壊検出装置２０００は、更新系メソッド抽出部２４００により、「スレッドアンセーフな並行メソッド、更新変数リスト」の組み合わせを抽出する。そして、一貫性破壊検出装置２０００は、プローブ挿入部２６００により、「スレッドアンセーフな並行メソッド、更新変数リスト」の組み合わせに基づき、プログラム１０において、上記スレッドアンセーフな並行メソッド内にある、上記更新変数リストに含まれる更新変数を更新する命令の前又は後ろにプローブを挿入して、プローブ入りプログラム２０を生成する。一貫性破壊検出装置２０００を利用すると、プログラム１０を実行した時に実際に通る実行経路においてのみ、一貫性破壊の障害の検出が行われる。したがって、一貫性破壊検出装置２０００は、プログラムを網羅的に検査するモデル検査と比べ、短い時間で一貫性破壊の障害の検出を行うことができる。また、一貫性破壊検出装置２０００を利用すると、一貫性破壊障害の誤検出を少なくすることができる。これは、プローブ入りプログラム２０を実行して一貫性破壊を検出する場合、一貫性破壊の検出は、実際に一貫性破壊が起こった場合にのみ行われるためである。
【０１１３】
[実施形態２]
＜構成＞
実施形態２に係る一貫性破壊検出装置２０００は、クラス階層を持つプログラムに対して、一貫性破壊障害を検出するためのプローブを挿入する機能を有する。クラス階層を有するプログラムの例としては、Ｊａｖａ（登録商標）やＳｍａｌｌｔａｌｋ等のオブジェクト指向言語で記述されたプログラムがある。本実施形態における一貫性破壊検出装置２０００は、コールフローグラフ生成部２２４０により、クラス階層を考慮したコールフローグラフ９０を生成する。
【０１１４】
図１４は、実施形態２に係るコールフローグラフ生成部２２４０を表すブロック図である。図１４において、図３に同符号の機能ブロックが示されている機能ブロックは、図３における同符号の機能ブロックと同じ機能を有する。そのため、それらの機能ブロックについては、適宜説明を省略する。
【０１１５】
本実施形態におけるコールフローグラフ生成部２２４０は、さらにクラス階層抽出部２２４８及びオーバライドメソッド抽出部２２５０を有する。クラス階層抽出部２２４８は、プログラム１０を取得する。そして、クラス階層抽出部２２４８は、プログラム１０に含まれる各クラス間の階層関係を表すクラス階層グラフを生成する。
【０１１６】
オーバライドメソッド抽出部２２５０は、メソッド内呼び出し抽出部２２４４が生成した呼び出し先メソッドリスト、及びクラス階層抽出部２２４８が生成したクラス階層グラフを参照し、呼び出し先メソッドリストに含まれる各呼び出し先メソッドのオーバライドメソッドを割り出す。そして、上記オーバライドメソッドを示すオーバライドメソッドリストを生成する。
【０１１７】
本実施形態におけるグラフ生成部２２４６は、呼び出し先メソッドリスト及びオーバライドメソッドリストを参照し、コールフローグラフ９０を生成する。具体的にはまず、グラフ生成部２２４６は、呼び出し先メソッドリストに基づき、始点ノードが選択メソッドであり、終端ノードが呼び出し先メソッド、及び各呼び出し先メソッドのオーバライドメソッドである部分グラフを生成する。そして、グラフ生成部２２４６は、各部分グラフを連結して、コールフローグラフ９０を生成する。生成されたコールフローグラフ９０は、始点ノードが起点メソッドであり、起点メソッドから到達しうるメソッド、及び各メソッドのオーバライドメソッド間のコールフローを示すコールフローグラフとなる。
【０１１８】
＜実施形態２におけるコールフローグラフ生成部２２４０による処理の流れ＞
図１５は、実施形態２におけるコールフローグラフ生成部２２４０による処理の流れの一例を示すフローチャートである。ここで、図１５のフローチャートは、ステップＳ８０２、Ｓ８０４、及びＳ８０６を除き、図９のフローチャートと同じである。そのため、図９に含まれるステップについては、適宜説明を省略する。
【０１１９】
ステップＳ８０２において、クラス階層抽出部２２４８は、クラス階層グラフを生成する。
【０１２０】
ステップＳ８０４において、オーバライドメソッド抽出部２２５０は、ステップＳ７１４で生成された呼び出し先メソッドリストに含まれる各呼び出し先メソッドについて、オーバライドメソッドリストを生成する。
【０１２１】
ステップＳ８０６において、グラフ生成部２２４６は、呼び出し先メソッドリスト及びオーバライドメソッドリストに基づいて、コールフローグラフ９０を生成する。
【０１２２】
＜作用・効果＞
以上の構成により、本実施形態に係る一貫性破壊検出装置２０００は、クラス階層抽出部２２４８により、プログラム１０におけるクラス間の階層構造を表すクラス階層グラフを生成する。また、一貫性破壊検出装置２０００は、オーバライドメソッド抽出部２２５０により、呼び出し先メソッドリストが示すメソッドごとに、そのメソッドのオーバライドメソッドを示すオーバライドメソッドリストを生成する。そして、一貫性破壊検出装置２０００は、グラフ生成部２２４６により、呼び出し先メソッドリスト及びオーバライドメソッドリストに基づいて、コールフローグラフ９０を生成する。これにより、本実施形態におけるコールフローグラフ生成部２２４０が生成するコールフローグラフ９０は、各メソッドから呼び出されうるメソッドとして、そのメソッドが内部から明示的に呼び出している呼び出し先メソッドだけでなく、呼び出し先メソッドのオーバライドメソッドも示す。こうすることで、クラス階層を有するプログラムについても、起点メソッドから到達しうる全てのメソッドを対象として、プローブを挿入することができる。
【０１２３】
[実施例]
以下に、実施形態２に係る一貫性破壊検出装置２０００の実施例を示す。なお、以下に示す実施例はあくまで例示である。上述した実施形態は、下記実施例によって何ら限定を受けない。
【０１２４】
まず、次のＪａｖａ（登録商標）プログラムのソースコードが与えられているとする。
public class ConcurrentMain implements Runnable {
private Thread t;
static Counter c = new Counter(0);
public static void main(String[] args) {
ConcurrentMain t1 = new ConcurrentMain();
ConcurrentMain t2 = new ConcurrentMain();
System.out.println("cnt=" + ConcurrentMain.c.getVal());   
}
public ConcurrentMain() {
t = new Thread(this);
t.start();
}
@Override
public void run() {
ConcurrentMain.c.inc();
}
}
public class Counter {
public Counter(int cnt) {
this.cnt = cnt;
}
private int cnt;
void inc() {   cnt++;  }
int getVal() { return cnt; }
}
【０１２５】
これをｊａｖａｃ等のコマンドでコンパイルしたバイトコードは、以下のとおりである。以下、このバイトコードをプログラム１０とする。
Compiled from "ConcurrentMain.java"
public class ConcurrentMain implements java.lang.Runnable {
static Counter c;
static {};
Code:
0: new           #14                 // class Counter
3: dup           
4: iconst_0      
5: invokespecial #16                 // Method Counter."<init>":(I)V
8: putstatic     #20                 // Field c:LCounter;
11: return        
public static void main(java.lang.String[]);
Code:
0: new           #1                  // class ConcurrentMain
3: dup           
4: invokespecial #26                 // Method "<init>":()V
7: astore_1      
8: new           #1                  // class ConcurrentMain
11: dup           
12: invokespecial #26                 // Method "<init>":()V
15: astore_2      
16: getstatic     #28                 // Field java/lang/System.out:Ljava/io/PrintStream;
19: new           #34                 // class java/lang/StringBuilder
22: dup           
23: ldc           #36                 // String cnt=
25: invokespecial #38                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
28: getstatic     #20                 // Field c:LCounter;
31: invokevirtual #41                 // Method Counter.getVal:()I
34: invokevirtual #45                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
37: invokevirtual #49                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
40: invokevirtual #53                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
43: return        
public ConcurrentMain();
Code:
0: aload_0       
1: invokespecial #63                 // Method java/lang/Object."<init>":()V
4: aload_0       
5: new           #64                 // class java/lang/Thread
8: dup           
9: aload_0       
10: invokespecial #66                 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
13: putfield      #69                 // Field t:Ljava/lang/Thread;
16: aload_0       
17: getfield      #69                 // Field t:Ljava/lang/Thread;
20: invokevirtual #71                 // Method java/lang/Thread.start:()V
23: return        
public void run();
Code:
0: getstatic     #20                 // Field c:LCounter;
3: invokevirtual #76                 // Method Counter.inc:()V
6: return        
}
Compiled from "Counter.java"
public class Counter {
public Counter(int);
Code:
0: aload_0       
1: invokespecial #10                 // Method java/lang/Object."<init>":()V
4: aload_0       
5: iload_1       
6: putfield      #13                 // Field cnt:I
9: return        
void inc();
Code:
0: aload_0       
1: dup           
2: getfield      #13                 // Field cnt:I
5: iconst_1      
6: iadd          
7: putfield      #13                 // Field cnt:I
10: return        
int getVal();
Code:
0: aload_0       
1: getfield      #13                 // Field cnt:I
4: ireturn       
}
【０１２６】
まず、並行メソッド抽出部２２００は、対象のプログラム１０を解析し、並行メソッドリストを生成する（図８のステップＳ１０４）。その具体的な動作として、まず、並行ＡＰＩ抽出部２２２０は、プログラム１０を取得し、起点メソッドをもとめる（図７のステップＳ２０４）。Ｊａｖａ（登録商標）の場合、並行ＡＰＩは、Ｒｕｎｎａｂｌｅ＃ｒｕｎのオーバライドメソッドか、Ｔｈｒｅａｄ＃ｒｕｎのオーバライドメソッドである。そのため、ＣｏｎｃｕｒｒｅｎｔＭａｉｎ＃ｒｕｎ が起点メソッドとなる。
【０１２７】
そして、コールフローグラフ生成部２２４０は、プログラム１０を取得し、コールフローグラフ９０を生成する（図８のステップＳ２０６）。その具体的な処理として、クラス階層抽出部２２４８は、プログラム１０を読み込み、クラス階層グラフを生成する（図１５のステップＳ８０２）。その例として、図１６に示すクラス階層グラフを生成する。そして、メソッド選択部２２４２は、起点メソッドから到達しうる全てのメソッドに関して、図１５のステップＳ７１２〜ステップＳ７１８のループ処理Ｂを行う。その結果として、プログラム１０もしくは、それをコンパイルしたバイトコードをもとに、起点メソッドＣｏｎｃｕｒｒｅｎｔＭａｉｎ＃ｒｕｎを起点とする図１７に示すコールフローグラフ９０を生成する。すなわち、ＣｏｎｃｕｒｒｅｎｔＭａｉｎ＃ｒｕｎと、ＣｏｎｃｕｒｒｅｎｔＭａｉｎ＃ｒｕｎから呼び出されるＣｏｕｎｔｅｒ＃ｉｎｃ（）をノードとし、ＣｏｎｃｕｒｒｅｎｔＭａｉｎ＃ｒｕｎからＣｏｕｎｔｅｒ＃ｉｎｃ（）への有向辺を持つコールフローグラフ９０を生成する。
【０１２８】
そして、コールフロートレース部２２６０は、起点メソッドであるＣｏｎｃｕｒｒｅｎｔＭａｉｎ＃ｒｕｎと、起点メソッドから上記コールフローグラフ９０を辿って得られるメソッドであるＣｏｕｎｔｅｒ＃ｉｎｃの２つを並行メソッドとする並行メソッドリスト３０を生成する（図８のステップＳ２０８）。
【０１２９】
そして、更新系メソッド抽出部２４００は、上記並行メソッドの中で、スレッド間で共有される変数が更新されるメソッドとその変数のリスト、すなわち、スレッドアンセーフな並行メソッドと、更新変数リストとを求める（図１０）。例えばＪａｖａ（登録商標）の場合、スレッド間で共有される可能性のある変数は、ｓｔａｔｉｃ変数、ｔｈｉｓ変数、及びメソッドの仮引数のうち、オブジェクトへのポインタであるものである。
【０１３０】
メソッド取得部２４２０は、並行メソッドリスト３０から並行メソッドを１つ読み込み、そのメソッド定義４０を得る（図１０のステップＳ３０４及びＳ３０６）。そして、更新系メソッド抽出部２４００は、図１０のステップＳ３０４〜Ｓ３１２までのループ処理Ａを、並行メソッドリスト３０に含まれる全てのメソッドに適用するまで繰り返す。以下、並行メソッドの一つであるＣｏｕｎｔｅｒ＃ｉｎｃを例として説明する。
【０１３１】
図１０のループ処理Ａの内部において、構造化制御フローグラフ生成部２４４０はまず、Ｃｏｕｎｔｅｒ＃ｉｎｃのメソッド定義４０を読み込み、図１８に示す構造化制御フローグラフ７０を生成する（図１０のステップＳ３０４及びＳ３０６）。
【０１３２】
次に、更新変数分析部２４６０は、構造化制御フローグラフ７０を読み込み、更新変数リストを生成する（図１０のステップＳ３１０）。
【０１３３】
図１０のステップＳ３１０は、図１１に示す一連の処理で構成される。変数リストの例を、図１９（ａ）に示す。更新変数分析部２４６０は、変数リストにおいて、Ｃｏｕｎｔｅｒ＃ｉｎｃの引数がないため、ｔｈｉｓの識別子である０に関して、更新情報を「無し」に設定し、参照先同一変数情報には、自身と同じである０を示す。また、参照先同一変数リストについては、例えばループの脱出分岐節のアドレスを記入する。ただし、例のＣｏｕｎｔｅｒ＃ｉｎｃはループ処理を有しないので、参照先同一変数リストは空表である。
【０１３４】
更新変数分析部２４６０は、以下に示すように構造化制御フローグラフ７０を辿り、命令分析を行う。ここで、更新変数分析部２４６０は一時領域としてスタックを用いるとする。以下、このスタックを分析用スタックと表記する。また、更新変数分析部２４６０が各命令を分析した後の分析用スタックの状態を、図１８の構造化制御フローグラフ７０の右側に示す。
【０１３５】
更新変数分析部２４６０はまず、構造化制御フローグラフ７０の先頭ノードである「０：ａｌｏａｄ＿０」を読み込む（図１２のステップＳ５０４）。そして、更新変数分析部２４６０は、読み込んだ命令の種類を調べる（図１２のステップＳ５０６、及び図１３のステップＳ６０２）。
【０１３６】
ａｌｏａｄ＿０はｌｏａｄ系命令なので、更新変数分析部２４６０は、分析用スタックＳを「Ｓ０」とする。これは、分析用スタックＳに０番目の局所変数 (Ｊａｖａ（登録商標）の場合はｔｈｉｓ)を積むことを意味する(図１３のステップＳ６０４)。
【０１３７】
そして、更新変数分析部２４６０は、上記命令によって条件分岐が行われるかを調べる（図１２のステップＳ５０８）。上記命令は、条件分岐を行わない命令である。したがって、更新変数分析部２４６０は、図１２のステップＳ５２８に進んだ後、ステップＳ５０４に戻る。
【０１３８】
更新変数分析部２４６０は、構造化制御フローグラフ７０における次のノード「１：ｄｕｐ」を読み込み、命令の種類を調べる。ｄｕｐは、Ｌｏａｄ系命令、Ｓｔｏｒｅ系命令、更新系命令、及びメソッド呼び出し命令のいずれにも該当しない。そこで更新変数分析部２４６０は、図１３のステップＳ６２０に進む。更新変数分析部２４６０は、ｄｕｐが行うスタック操作を、分析用スタックに適用する。具体的には、ｄｕｐは、スタックの先頭要素をコピーし、スタックにｐｕｓｈする命令である。したがって、更新変数分析部２４６０は、分析用スタックＳを、「Ｓ０」から、「Ｓ００」に変更する。さらに更新変数分析部２４６０は、上記命令によって条件分岐が行われるか調べる。ｄｕｐは条件分岐を伴わない命令なので、再度図１２のステップＳ５０４に戻る。
【０１３９】
そして、更新変数分析部２４６０は、構造化制御フローグラフ７０の次の節「２：ｇｅｔｆｉｅｌｄ＃１３」を１つ読み込み、命令の種類を調べる。ｇｅｔｆｉｅｌｄは、Ｌｏａｄ系命令であり、まず、スタックの先頭にあるオブジェクトをｐｏｐする。本例の場合、スタックの先頭に積まれているのはＣｏｕｎｔｅｒオブジェクトである。さらに、ｇｅｔｉｅｌｄは、ｐｏｐしたオブジェクトのフィールドの内、＃で指定したフィールドの値を、スタックにｐｕｓｈする。本例の場合は、Ｃｏｕｎｔｅｒオブジェクトのｃｎｔフィールドを、スタックにｐｕｓｈする。Ｃｏｕｎｔｅｒ＃ｃｎｔは整数型なので、更新変数分析部２４６０は、分析用スタックＳに対し、単純型を表すマーク「＊」を積む。つまり、スタック「S 0 0」を、スタック「Ｓ０＊」に更新する。さらに更新変数分析部２４６０は、上記命令によって条件分岐が行われるか調べる。ｇｅｔｆｉｅｌｄは条件分岐を伴わない命令なので、再度図１２のステップＳ５０４に戻る。
【０１４０】
更新変数分析部２４６０は、構造化制御フローグラフ７０の次のノード「５：ｉｃｏｎｓｔ＿１」を読み込み、命令の種類を調べる。ｉｃｏｎｓｔ＿１は、定数１をスタックにプッシュするＬｏａｄ系命令である。そこで、更新変数分析部２４６０は、分析用スタックＳを、「Ｓ０＊」から、「Ｓ０＊＊」に更新する。さらに更新変数分析部２４６０は、上記命令によって条件分岐が行われるか調べる。ｉｃｏｎｓｔ＿１は条件分岐を伴わない命令なので、再度図１２のステップＳ５０４に戻る。
【０１４１】
更新変数分析部２４６０は、構造化制御フローグラフ７０の次のノード「６：ｉａｄｄ」を読み込み、命令の種類を調べる。ｉａｄｄはスタック操作系命令で、２つのスタック上の変数をｐｏｐし、ｐｏｐした２つの変数の和をスタックに積む。そこで、更新変数分析部２４６０は、分析用スタックＳ「Ｓ０＊＊」を、「Ｓ０＊」に更新する。さらに更新変数分析部２４６０は、上記命令によって条件分岐が行われるか調べる。ｉａｄｄは条件分岐を伴わない命令なので、再度図１２のステップＳ５０４に戻る。
【０１４２】
更新変数分析部２４６０は、構造化制御フローグラフ７０の次のノード「７：ｐｕｔｆｉｅｌｄ＃１３」を読み込み、命令の種類を調べる。ｐｕｔｆｉｅｌｄは、スタック上のオブジェクト及び値の２つをｐｏｐし、ｐｏｐしたオブジェクトの指定したフィールドに、ｐｏｐした値を代入する更新系命令である。本例の場合、Ｃｏｕｎｔｅｒクラスのオブジェクトと、上記ｉａｄｄでスタックにｐｕｓｈした値の２つをｐｏｐし、Ｃｏｕｎｔｅｒクラスのｃｎｔフィールドにｐｏｐした値を代入する。そこで、更新変数分析部２４６０は、分析用スタックＳからオブジェクトと整数型をｐｏｐする（図１３のステップＳ６１０）。具体的には、分析用スタックＳ「Ｓ０＊」を、「Ｓ」に更新する。そして、更新変数分析部２４６０は、変数リストにおいて、ｐｕｔｆｉｅｌｄが更新した変数である０（ｔｈｉｓ）に関するレコードの更新情報を、「無し」から「有り」に更新する（図１３のステップＳ６１２）。さらに更新変数分析部２４６０は、上記命令によって条件分岐が行われるか調べる。ｐｕｔｆｉｅｌｄは条件分岐を伴わない命令なので、再度図１２のステップＳ５０４に戻る。
【０１４３】
さらに、更新変数分析部２４６０は、構造化制御フローグラフ７０の次のノード「１０：ｒｅｔｕｒｎ」を読み込み、命令の種類を調べる。ｒｅｔｕｒｎは、Ｌｏａｄ系命令、Ｓｔｏｒｅ系命令、更新系命令、及びメソッド呼び出し命令のいずれにも該当しない。そこで更新変数分析部２４６０は、図１３のステップＳ６２０に進み、分析用スタックを操作する。また、更新変数分析部２４６０は、上記命令によって条件分岐が行われるか調べる。ｒｅｔｕｒｎは条件分岐を伴わない命令なので、再度図１２のステップＳ５０４に戻る。
【０１４４】
更新変数分析部２４６０は、構造化制御フローグラフ７０に含まれる全ての命令について、分析を終えている。したがって、図１２のステップＳ５３０に進む。そして、変数リストと参照先同一変数リストを併合して更新変数リストを生成する。本例の場合、参照先同一変数リストは変更されなかったため、更新変数リストは、変数リストと同じになる。
【０１４５】
本例において、更新変数分析部２４６０による処理後の更新変数リストは、図１９（ｂ）に示す表となる。更新変数リストは、変数０（ｔｈｉｓ）が更新されていることを示している。したがってｔｈｉｓ、すなわちＣｏｕｎｔｅｒオブジェクトが、更新変数となる。
【０１４６】
以上の動作により、一貫性破壊検出装置２０００は、Ｃｏｕｎｔｅｒ＃ｉｎｃメソッドがスレッドアンセーフな並行メソッドであり、Ｃｏｕｎｔｅｒ＃ｉｎｃメソッドによって更新される更新変数はＣｏｕｎｔｅｒ＃ｔｈｉｓであることを割り出した。同様に、一貫性破壊検出装置２０００がその他のメソッドについても分析して出力した「スレッドアンセーフな並行メソッド、更新変数リスト」の組み合わせを、図２０に示す。
【０１４７】
プローブ挿入部２６００は、Ｃｏｕｎｔｅｒ＃ｉｎｃメソッドにプローブを挿入する（図７のステップＳ１０８）。以下に、プローブ挿入部２６００がＣｏｕｎｔｅｒ＃ｉｎｃに挿入するプローブの例を示す。
【０１４８】
public class Counter extends java.lang.Object{
void inc();
Code:
0: aload_0
1: invokestatic #3; //Method Log.getUpdateTime:(Ljava/lang/Object;)J
4: lstore_1
5: aload_0
6: dup
7: getfield #2; //Field cnt:I
10: iconst_1
11: iadd
12: putfield #2; //Field cnt:I
15: aload_0
16: invokestatic #3; //Method Log.getUpdateTime:(Ljava/lang/Object;)J
19: lstore_3
20: aload_0
21: invokestatic #4; //Method Log.updateTime:(Ljava/lang/Object;)V
24: lload_1
25: lload_3
26: lcmp
27: ifeq 40
30: new #5; //class java/lang/RuntimeException
33: dup
34: ldc #6; //String Atomicity Error
36: invokespecial #7; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
39: athrow
40: goto 75
43: astore 5
45: aload_0
46: invokestatic #3; //Method Log.getUpdateTime:(Ljava/lang/Object;)J
49: lstore 6
51: aload_0
52: invokestatic #4; //Method Log.updateTime:(Ljava/lang/Object;)V
55: lload_1
56: lload 6
58: lcmp
59: ifeq 72
62: new #5; //class java/lang/RuntimeException
65: dup
66: ldc #6; //String Atomicity Error
68: invokespecial #7;  //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
71: athrow
72: aload 5
74: athrow
75: return
Exception table:
from   to  target type
5    15    43   any
43    45    43   any
}
【０１４９】
アドレス０からアドレス４は、更新変数ｔｈｉｓの更新時間を得るメソッドＬｏｇ＃ｇｅｔＵｐｄａｔｅＴｉｍｅを呼び出すプローブである。アドレス１５からアドレス１９は、再度更新変数ｔｈｉｓの更新時間を得るメソッドＬｏｇ＃ｇｅｔＵｐｄａｔｅＴｉｍｅを呼び出すプローブである。アドレス２０から２１は、更新変数ｔｈｉｓの更新時間を再設定するためのメソッドＬｏｇ＃ｕｐｄａｔｅＴｉｍｅを呼び出すプローブである。アドレス２４から３９は、更新変数ｔｈｉｓの変更時刻を比較し、不一致であれば、一貫性違反としてＲｕｎｔｉｍｅＥｘｃｅｐｔｉｏｎをｔｈｒｏｗするプローブである。アドレス４３から４９は、上記一貫性違反の例外をハンドルする例外ハンドラである。
【０１５０】
上記プローブが挿入されたプローブ入りプログラム２０を実行すると、スレッドアンセーフである並行メソッド（例：Ｃｏｕｎｔｅｒ＃ｉｎｃ）が並行実行されたとき、上記プローブは、一貫性が破壊されたことを通知するＲｕｎｔｉｍｅＥｘｅｐｔｉｏｎを発生させる。
【０１５１】
以上、図面を参照して本発明の実施形態及び実施例について述べたが、これらは本発明の例示であり、上記以外の様々な構成を採用することもできる。
【０１５２】
[付記]
（付記１）
プログラムを取得し、該プログラムの中から、並行に実行されうるメソッドである並行メソッドを抽出し、並行メソッドリストを生成する並行メソッド抽出手段と、
前記プログラムと前記並行メソッドリストに基づいて、スレッド間で共有される変数を更新する並行メソッドであるスレッドアンセーフな並行メソッドと、前記スレッドアンセーフな並行メソッドが更新する変数である更新変数とを組み合わせて抽出する更新系メソッド抽出手段と、
前記スレッドアンセーフな並行メソッドと前記更新変数の組み合わせに基づき、前記プログラムにおいて、該スレッドアンセーフな並行メソッド内にある、該更新変数を更新する命令の前又は後ろに、検査用の命令列を挿入するプローブ挿入手段を有する一貫性破壊検出装置。
（付記２）
前記並行メソッド抽出手段は、
前記プログラムの中から、並行に実行されるメソッド列の起点となるメソッドを検出し、起点メソッドとして抽出する並行ＡＰＩ抽出手段と、
前記起点メソッドを起点としたコールフローグラフを生成するコールフローグラフ生成手段と、
前記コールフローグラフに含まれるメソッドを並行メソッドとして、並行メソッドリストを生成するコールフロートレース手段と、
を有する付記１記載の一貫性破壊検出装置。
（付記３）
前記更新系メソッド抽出手段は、
前記並行メソッドリストから前記並行メソッドを取得し、該並行メソッドの定義を取得するメソッド取得手段と、
前記メソッド取得手段により取得された前記並行メソッドの定義に基づいて、該並行メソッド内の制御フローを示す制御フローグラフに、該並行メソッドに含まれる各分岐命令の種類を示す分岐識別情報を付加した構造化制御フローグラフを生成する構造化制御フローグラフ生成手段と、
前記構造化制御フローグラフを解析し、前記並行メソッドの定義に含まれる変数のうち、前記構造化制御フローが示すいずれかの制御フローにおいて、スレッド間で共有され、かつ、更新される変数を、前記更新変数として抽出する更新変数分析手段と、
前記取得された並行メソッドと前記更新変数を対応づけて抽出する更新系メソッド出力手段と、
を有する付記１又は２記載の一貫性破壊検出装置。
（付記４）
前記更新変数分析手段は、
前記メソッド取得手段が取得した前記並行メソッドの定義に含まれる変数ごとに、変数の更新の有無を示す情報である更新情報、及び該変数と同一のアドレスを参照している他の変数を示す情報である参照先同一変数情報を記録する変数リストを生成し、
前記構造化制御フローグラフの始点から順に命令を１つずつ取得し、
取得された前記命令によって変数が更新された場合は、該変数に関する前記更新情報を更新有りとし、
取得された前記命令によって、変数と他の変数が同一のアドレスを参照するようになった場合は、該変数に関する前記参照先同一変数情報に、該他の変数を加え、
前記変数リストを参照し、前記更新情報において更新有りとされている前記変数、及び、前記参照先同一変数情報において該変数と参照するアドレスが同一であるとされている前記他の変数を前記更新変数とすることを特徴とする付記３記載の一貫性破壊検出装置。
（付記５）
前記構造化制御フローグラフ生成手段は、
前記並行メソッドの定義を取得し、該並行メソッド内の命令列の制御の流れを表す初期制御フローグラフを生成する初期制御フローグラフ生成手段と、
前記初期制御フローグラフに示される前記命令列の中から、ループ処理を継続するか否かの判定を行う命令をループ判定命令として抽出し、抽出された該ループ判定命令をループリストに登録するループ抽出手段と、
前記初期制御フローグラフに示される前記命令列の中から、分岐命令であり、かつ、ループ判定命令ではない命令を条件分岐命令として抽出し、抽出された該条件分岐命令を条件分岐リストに登録する条件分岐抽出手段と、
前記初期制御フローグラフ、前記ループリスト、及び前記条件分岐リストに基づいて、前記初期制御フローグラフに示される分岐命令ごとに、前記ループ判定命令と前記条件分岐命令のどちらであるかを示す情報を、分岐識別情報として付加して構造化制御フローグラフを生成する構造化手段と、
を有する付記４記載の一貫性破壊検出装置。
（付記６）
前記更新変数分析手段は、
前記構造化制御フローグラフから取り出された命令に、前記条件分岐命令を示す分岐識別情報が付加されている場合は、各条件分岐について、該構造化制御フローグラフの中から、該条件分岐命令の次の命令から条件分岐の終了までの命令を示す部分グラフを前記構造化制御フローグラフとして再帰実行し、
前記構造化制御フローグラフから取り出された命令に、前記ループ判定命令を示す分岐識別情報が付加されている場合は、前記変数リストが更新されなくなるまで、該ループ判定命令の次の命令からループ処理の終了までの命令を示す部分グラフを前記構造化制御フローグラフとした再帰実行を繰り返すことを特徴とする付記５記載の一貫性破壊検出装置。
（付記７）
前記更新変数分析手段は、作業領域としてスタックを有し、前記構造化制御フローグラフから取り出された命令の種類を調べ、
前記命令がＬｏａｄ系命令である場合は、前記命令の内容に応じて前記スタックをｐｕｓｈし、
前記命令がＳｔｏｒｅ系命令である場合は、前記命令の内容に応じて前記スタックをｐｏｐし、前記命令の対象となっている変数に関する変数表の参照先同一変数に、Ｓｔｏｒｅ系命令の対象となっている別の変数を加え、
前記命令が更新系命令の場合は、前記命令の内容に応じて前記スタックを処理し、前記命令によって更新される変数に関する変数リストにおいて、更新情報を更新ありに変更し、
前記命令がメソッドを起動する命令の場合は、前記命令の内容に応じて前記スタックを処理し、前記命令が起動するメソッドについて生成された更新変数表を参照して、該更新変数表が更新変数として示している変数について、前記変数リストの更新情報を更新有りに変更することを特徴とする付記４乃至６いずれか一項に記載の一貫性破壊検出装置。
（付記８）
前記コールフローグラフ生成手段は、
前記プログラム及び前記起点メソッドを取得し、前記起点メソッドから到達可能なメソッドのそれぞれについて、該メソッドが呼び出すメソッドの一覧である呼び出し先メソッドリストを生成するメソッド内呼び出し抽出手段と、
前記プログラムの中から、クラス間の階層関係を表すクラス階層グラフを生成するクラス階層抽出手段と、
クラス階層グラフを参照し、前記呼び出し先メソッドリストに含まれるメソッドのそれぞれについて、該メソッドをオーバライドしたメソッドの一覧であるオーバライドメソッドリストを生成するオーバライドメソッド抽出手段と、
前記起点メソッドから到達可能な前記各メソッドについて、該メソッドの前記呼び出し先メソッドリスト及び該呼び出し先メソッドリストに関する前記オーバライドメソッドリストに基づいて、始点ノードが該メソッドであり、終端ノードが該メソッドリスト又は該オーバライドメソッドリストに含まれるメソッドである部分グラフを生成し、前記部分グラフを連結して、前記起点メソッドを始点ノードとするコールフローグラフを生成するグラフ生成手段と、
を有する付記２乃至７いずれか一項に記載の一貫性破壊検出装置。
（付記９）
コンピュータに、並行実行されるプログラムにおける一貫性破壊を検出する機能を持たせる一貫性破壊検出プログラムであって、
前記コンピュータに、
プログラムを取得し、該プログラムの中から、並行に実行されうるメソッドである並行メソッドを抽出し、並行メソッドリストを生成する並行メソッド抽出機能と、
前記プログラムと前記並行メソッドリストに基づいて、スレッド間で共有される変数を更新する並行メソッドであるスレッドアンセーフな並行メソッドと、前記スレッドアンセーフな並行メソッドが更新する変数である更新変数とを組み合わせて抽出する更新系メソッド抽出機能と、
前記スレッドアンセーフな並行メソッドと前記更新変数の組み合わせに基づき、前記プログラムにおいて、該スレッドアンセーフな並行メソッド内にある、該更新変数を更新する命令の前又は後ろに、検査用の命令列を挿入するプローブ挿入機能を持たせる一貫性破壊検出プログラム。
（付記１０）
前記並行メソッド抽出機能は、
前記プログラムの中から、並行に実行されるメソッド列の起点となるメソッドを検出し、起点メソッドとして抽出する並行ＡＰＩ抽出機能と、
前記起点メソッドを起点としたコールフローグラフを生成するコールフローグラフ生成機能と、
前記コールフローグラフに含まれるメソッドを並行メソッドとして、並行メソッドリストを生成するコールフロートレース機能と、
を有する付記９記載の一貫性破壊検出プログラム。
（付記１１）
前記更新系メソッド抽出機能は、
前記並行メソッドリストから前記並行メソッドを取得し、該並行メソッドの定義を取得するメソッド取得機能と、
前記メソッド取得機能により取得された前記並行メソッドの定義に基づいて、該並行メソッド内の制御フローを示す制御フローグラフに、該並行メソッドに含まれる各分岐命令の種類を示す分岐識別情報を付加した構造化制御フローグラフを生成する構造化制御フローグラフ生成機能と、
前記構造化制御フローグラフを解析し、前記並行メソッドの定義に含まれる変数のうち、前記構造化制御フローが示すいずれかの制御フローにおいて、スレッド間で共有され、かつ、更新される変数を、前記更新変数として抽出する更新変数分析機能と、
前記取得された並行メソッドと前記更新変数を対応づけて抽出する更新系メソッド出力機能と、
を有する付記９又は１０記載の一貫性破壊検出プログラム。
（付記１２）
前記更新変数分析機能は、
前記メソッド取得機能が取得した前記並行メソッドの定義に含まれる変数ごとに、変数の更新の有無を示す情報である更新情報、及び該変数と同一のアドレスを参照している他の変数を示す情報である参照先同一変数情報を記録する変数リストを生成し、
前記構造化制御フローグラフの始点から順に命令を１つずつ取得し、
取得された前記命令によって変数が更新された場合は、該変数に関する前記更新情報を更新有りとし、
取得された前記命令によって、変数と他の変数が同一のアドレスを参照するようになった場合は、該変数に関する前記参照先同一変数情報に、該他の変数を加え、
前記変数リストを参照し、前記更新情報において更新有りとされている前記変数、及び、前記参照先同一変数情報において該変数と参照するアドレスが同一であるとされている前記他の変数を前記更新変数とすることを特徴とする付記１１記載の一貫性破壊検出プログラム。
（付記１３）
前記構造化制御フローグラフ生成機能は、
前記並行メソッドの定義を取得し、該並行メソッド内の命令列の制御の流れを表す初期制御フローグラフを生成する初期制御フローグラフ生成機能と、
前記初期制御フローグラフに示される前記命令列の中から、ループ処理を継続するか否かの判定を行う命令をループ判定命令として抽出し、抽出された該ループ判定命令をループリストに登録するループ抽出機能と、
前記初期制御フローグラフに示される前記命令列の中から、分岐命令であり、かつ、ループ判定命令ではない命令を条件分岐命令として抽出し、抽出された該条件分岐命令を条件分岐リストに登録する条件分岐抽出機能と、
前記初期制御フローグラフ、前記ループリスト、及び前記条件分岐リストに基づいて、前記初期制御フローグラフに示される分岐命令ごとに、前記ループ判定命令と前記条件分岐命令のどちらであるかを示す情報を、分岐識別情報として付加して構造化制御フローグラフを生成する構造化機能と、
を有する付記１２記載の一貫性破壊検出プログラム。
（付記１４）
前記更新変数分析機能は、
前記構造化制御フローグラフから取り出された命令に、前記条件分岐命令を示す分岐識別情報が付加されている場合は、各条件分岐について、該構造化制御フローグラフの中から、該条件分岐命令の次の命令から条件分岐の終了までの命令を示す部分グラフを前記構造化制御フローグラフとして再帰実行し、
前記構造化制御フローグラフから取り出された命令に、前記ループ判定命令を示す分岐識別情報が付加されている場合は、前記変数リストが更新されなくなるまで、該ループ判定命令の次の命令からループ処理の終了までの命令を示す部分グラフを前記構造化制御フローグラフとした再帰実行を繰り返すことを特徴とする付記１３記載の一貫性破壊検出プログラム。
（付記１５）
前記更新変数分析機能は、作業領域としてスタックを有し、前記構造化制御フローグラフから取り出された命令の種類を調べ、
前記命令がＬｏａｄ系命令である場合は、前記命令の内容に応じて前記スタックをｐｕｓｈし、
前記命令がＳｔｏｒｅ系命令である場合は、前記命令の内容に応じて前記スタックをｐｏｐし、前記命令の対象となっている変数に関する変数表の参照先同一変数に、Ｓｔｏｒｅ系命令の対象となっている別の変数を加え、
前記命令が更新系命令の場合は、前記命令の内容に応じて前記スタックを処理し、前記命令によって更新される変数に関する変数リストにおいて、更新情報を更新ありに変更し、
前記命令がメソッドを起動する命令の場合は、前記命令の内容に応じて前記スタックを処理し、前記命令が起動するメソッドについて生成された更新変数表を参照して、該更新変数表が更新変数として示している変数について、前記変数リストの更新情報を更新有りに変更することを特徴とする付記１１乃至１４いずれか一項に記載の一貫性破壊検出プログラム。
（付記１６）
前記コールフローグラフ生成機能は、
前記プログラム及び前記起点メソッドを取得し、前記起点メソッドから到達可能なメソッドのそれぞれについて、該メソッドが呼び出すメソッドの一覧である呼び出し先メソッドリストを生成するメソッド内呼び出し抽出機能と、
前記プログラムの中から、クラス間の階層関係を表すクラス階層グラフを生成するクラス階層抽出機能と、
クラス階層グラフを参照し、前記呼び出し先メソッドリストに含まれるメソッドのそれぞれについて、該メソッドをオーバライドしたメソッドの一覧であるオーバライドメソッドリストを生成するオーバライドメソッド抽出機能と、
前記起点メソッドから到達可能な前記各メソッドについて、該メソッドの前記呼び出し先メソッドリスト及び該呼び出し先メソッドリストに関する前記オーバライドメソッドリストに基づいて、始点ノードが該メソッドであり、終端ノードが該メソッドリスト又は該オーバライドメソッドリストに含まれるメソッドである部分グラフを生成し、前記部分グラフを連結して、前記起点メソッドを始点ノードとするコールフローグラフを生成するグラフ生成機能と、
を有する付記１０乃至１５いずれか一項に記載の一貫性破壊検出プログラム。
（付記１７）
コンピュータが、並行実行するプログラムにおける一貫性破壊を検出する一貫性破壊検出方法であって、
前記コンピュータが、プログラムを取得し、該プログラムの中から、並行に実行されうるメソッドである並行メソッドを抽出し、並行メソッドリストを生成する並行メソッド抽出ステップと、
前記コンピュータが、前記プログラムと前記並行メソッドリストに基づいて、スレッド間で共有される変数を更新する並行メソッドであるスレッドアンセーフな並行メソッドと、前記スレッドアンセーフな並行メソッドが更新する変数である更新変数とを組み合わせて抽出する更新系メソッド抽出ステップと、
前記コンピュータが、前記スレッドアンセーフな並行メソッドと前記更新変数の組み合わせに基づき、前記プログラムにおいて、該スレッドアンセーフな並行メソッド内にある、該更新変数を更新する命令の前又は後ろに、検査用の命令列を挿入するプローブ挿入ステップを有する一貫性破壊検出方法。
（付記１８）
前記並行メソッド抽出ステップは、
前記コンピュータが、前記プログラムの中から、並行に実行されるメソッド列の起点となるメソッドを検出し、起点メソッドとして抽出する並行ＡＰＩ抽出ステップと、
前記コンピュータが、前記起点メソッドを起点としたコールフローグラフを生成するコールフローグラフ生成ステップと、
前記コンピュータが、前記コールフローグラフに含まれるメソッドを並行メソッドとして、並行メソッドリストを生成するコールフロートレースステップと、
を有する付記１７記載の一貫性破壊検出方法。
（付記１９）
前記更新系メソッド抽出ステップは、
前記コンピュータが、前記並行メソッドリストから前記並行メソッドを取得し、該並行メソッドの定義を取得するメソッド取得ステップと、
前記コンピュータが、前記メソッド取得機能により取得された前記並行メソッドの定義に基づいて、該並行メソッド内の制御フローを示す制御フローグラフに、該並行メソッドに含まれる各分岐命令の種類を示す分岐識別情報を付加した構造化制御フローグラフを生成する構造化制御フローグラフ生成ステップと、
前記コンピュータが、前記構造化制御フローグラフを解析し、前記並行メソッドの定義に含まれる変数のうち、前記構造化制御フローが示すいずれかの制御フローにおいて、スレッド間で共有され、かつ、更新される変数を、前記更新変数として抽出する更新変数分析ステップと、
前記コンピュータが、前記取得された並行メソッドと前記更新変数を対応づけて抽出する更新系メソッド出力ステップと、
を有する付記１７又は１８記載の一貫性破壊検出方法。
（付記２０）
前記更新変数分析ステップは、前記コンピュータが、
前記メソッド取得機能が取得した前記並行メソッドの定義に含まれる変数ごとに、変数の更新の有無を示す情報である更新情報、及び該変数と同一のアドレスを参照している他の変数を示す情報である参照先同一変数情報を記録する変数リストを生成し、
前記構造化制御フローグラフの始点から順に命令を１つずつ取得し、
取得された前記命令によって変数が更新された場合は、該変数に関する前記更新情報を更新有りとし、
取得された前記命令によって、変数と他の変数が同一のアドレスを参照するようになった場合は、該変数に関する前記参照先同一変数情報に、該他の変数を加え、
前記変数リストを参照し、前記更新情報において更新有りとされている前記変数、及び、前記参照先同一変数情報において該変数と参照するアドレスが同一であるとされている前記他の変数を前記更新変数とすることを特徴とする付記１９記載の一貫性破壊検出方法。
（付記２１）
前記構造化制御フローグラフ生成ステップは、
前記コンピュータが、前記並行メソッドの定義を取得し、該並行メソッド内の命令列の制御の流れを表す初期制御フローグラフを生成する初期制御フローグラフ生成ステップと、
前記コンピュータが、前記初期制御フローグラフに示される前記命令列の中から、ループ処理を継続するか否かの判定を行う命令をループ判定命令として抽出し、抽出された該ループ判定命令をループリストに登録するループ抽出ステップと、
前記コンピュータが、前記初期制御フローグラフに示される前記命令列の中から、分岐命令であり、かつ、ループ判定命令ではない命令を条件分岐命令として抽出し、抽出された該条件分岐命令を条件分岐リストに登録する条件分岐抽出ステップと、
前記コンピュータが、前記初期制御フローグラフ、前記ループリスト、及び前記条件分岐リストに基づいて、前記初期制御フローグラフに示される分岐命令ごとに、前記ループ判定命令と前記条件分岐命令のどちらであるかを示す情報を、分岐識別情報として付加して構造化制御フローグラフを生成する構造化ステップと、
を有する付記２０記載の一貫性破壊検出方法。
（付記２２）
前記更新変数分析ステップは、
前記構造化制御フローグラフから取り出された命令に、前記条件分岐命令を示す分岐識別情報が付加されている場合は、各条件分岐について、該構造化制御フローグラフの中から、該条件分岐命令の次の命令から条件分岐の終了までの命令を示す部分グラフを前記構造化制御フローグラフとして再帰実行し、
前記構造化制御フローグラフから取り出された命令に、前記ループ判定命令を示す分岐識別情報が付加されている場合は、前記変数リストが更新されなくなるまで、該ループ判定命令の次の命令からループ処理の終了までの命令を示す部分グラフを前記構造化制御フローグラフとした再帰実行を繰り返すことを特徴とする付記２１記載の一貫性破壊検出方法。
（付記２３）
前記更新変数分析ステップは、前記コンピュータが、作業領域としてスタックを有し、前記構造化制御フローグラフから取り出された命令の種類を調べ、
前記命令がＬｏａｄ系命令である場合は、前記命令の内容に応じて前記スタックをｐｕｓｈし、
前記命令がＳｔｏｒｅ系命令である場合は、前記命令の内容に応じて前記スタックをｐｏｐし、前記命令の対象となっている変数に関する変数表の参照先同一変数に、Ｓｔｏｒｅ系命令の対象となっている別の変数を加え、
前記命令が更新系命令の場合は、前記命令の内容に応じて前記スタックを処理し、前記命令によって更新される変数に関する変数リストにおいて、更新情報を更新ありに変更し、
前記命令がメソッドを起動する命令の場合は、前記命令の内容に応じて前記スタックを処理し、前記命令が起動するメソッドについて生成された更新変数表を参照して、該更新変数表が更新変数として示している変数について、前記変数リストの更新情報を更新有りに変更することを特徴とする付記１９乃至２２いずれか一項に記載の一貫性破壊検出方法。
（付記２４）
前記コールフローグラフ生成ステップは、
前記コンピュータが、前記プログラム及び前記起点メソッドを取得し、前記起点メソッドから到達可能なメソッドのそれぞれについて、該メソッドが呼び出すメソッドの一覧である呼び出し先メソッドリストを生成するメソッド内呼び出し抽出ステップと、
前記コンピュータが、前記プログラムの中から、クラス間の階層関係を表すクラス階層グラフを生成するクラス階層抽出ステップと、
前記コンピュータが、クラス階層グラフを参照し、前記呼び出し先メソッドリストに含まれるメソッドのそれぞれについて、該メソッドをオーバライドしたメソッドの一覧であるオーバライドメソッドリストを生成するオーバライドメソッド抽出ステップと、
前記コンピュータが、前記起点メソッドから到達可能な前記各メソッドについて、該メソッドの前記呼び出し先メソッドリスト及び該呼び出し先メソッドリストに関する前記オーバライドメソッドリストに基づいて、始点ノードが該メソッドであり、終端ノードが該メソッドリスト又は該オーバライドメソッドリストに含まれるメソッドである部分グラフを生成し、前記部分グラフを連結して、前記起点メソッドを始点ノードとするコールフローグラフを生成するグラフ生成ステップと、
を有する付記１８乃至２３いずれか一項に記載の一貫性破壊検出プログラム。
【符号の説明】
【０１５３】
１０ プログラム
２０ プローブ入りプログラム
３０ 並行メソッドリスト
４０ メソッド定義
５０ スレッドアンセーフな並行メソッド
６０ 更新変数リスト
７０ 構造化制御フローグラフ
８０ 起点メソッド
９０ コールフローグラフ
２００ 変数リスト
２１０ 変数識別子
２２０ 更新情報
２３０ 参照先同一変数情報
２０００ 一貫性破壊検出装置
２２００ 並行メソッド抽出部
２２２０ 並行ＡＰＩ抽出部
２２４０ コールフローグラフ生成部
２２４２ メソッド選択部
２２４４ メソッド内呼び出し抽出部
２２４６ グラフ生成部
２２４８ クラス階層抽出部
２２５０ オーバライドメソッド抽出部
２２６０ コールフロートレース部
２４００ 更新系メソッド抽出部
２４２０ メソッド取得部
２４４０ 構造化制御フローグラフ生成部
２４４２ 初期制御フローグラフ生成部
２４４４ ループ抽出部
２４４６ 条件分岐抽出部
２４４８ 構造化部
２４６０ 更新変数分析部
２４６２ 命令分析部
２６００ プローブ挿入部
【図１】
2014038467.tif 000003
【図２】
2014038467.tif 000004
【図３】
2014038467.tif 000005
【図４】
2014038467.tif 000006
【図５】
2014038467.tif 000007
【図６】
2014038467.tif 000008
【図７】
2014038467.tif 000009
【図８】
2014038467.tif 000010
【図９】
2014038467.tif 000011
【図１０】
2014038467.tif 000012
【図１１】
2014038467.tif 000013
【図１２】
2014038467.tif 000014
【図１３】
2014038467.tif 000015
【図１４】
2014038467.tif 000016
【図１５】
2014038467.tif 000017
【図１６】
2014038467.tif 000018
【図１７】
2014038467.tif 000019
【図１８】
2014038467.tif 000020
【図１９】
2014038467.tif 000021
【図２０】
2014038467.tif 000022