37
何故モデル検査が必要なのか? 多くのソフトウェアが分散処理・並行処理を基 本としている 複数の計算主体が並行動作をしながら共有資源 を用いて機能を実現している システム全体が安全な動作をしない可能性が 高い 資源を奪い合う競合状態に陥る可能性が高い 非決定的な振る舞いについて、誤りがテストなど では現れない可能性が高い 1

何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

  • Upload
    others

  • View
    0

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

何故モデル検査が必要なのか?

• 多くのソフトウェアが分散処理・並行処理を基本としている

– 複数の計算主体が並行動作をしながら共有資源を用いて機能を実現している

• システム全体が安全な動作をしない可能性が高い

– 資源を奪い合う競合状態に陥る可能性が高い

– 非決定的な振る舞いについて、誤りがテストなどでは現れない可能性が高い

1

Page 2: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

非決定的な振舞

• 複数スレッド間の並列動作

• 複数機器間の並列動作

• ネットワーク環境の変化

2

Page 3: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

複数スレッド間の並列動作

3

int a;

(ロックは適切にとっているものとする.)

スレッド間共有データ

while (true) {if (a < 10) { a++; }

}

スレッド1

while (true) {a--;

}

a = 10;thread1.run();thread2.run();while (true) { b = 100/a; }

スレッド2

スレッド0

Page 4: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

テストでは...

• 実行環境によっては,スレッド1だけが,非常に負荷の高いCPUに割り当てられ,スレッド0や2ばかりが動く,ということもあり得る.

• しかし,テストではそのような環境が再現できるとは限らない.

4

a 10 10 9 9 10 10 9 8 9

スレッド 1 2 0 1 0 2 2 1 0

Page 5: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

モデル検査では

• すべての場合を探索するので,エラーがおこるのなら (原理的には) 必ず見つかる.

5

10 9

th0,th1

th2

th1

th0

th2

th1... 1

th2

th1

th0

th2

th10

th0

err

Page 6: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

モデル検査• 状態機械の状態空間を網羅的に探索することにより、与えら

れた性質が正しいかどうかを判定する検証方法

• 従来の形式手法との比較

– モデル検査

• 完全な自動化が可能

–専門的な知識が必要ない

– 定理証明の手法を応用した検証方法

• 数理論理学の知識が必要

• 取り扱える状態数

– 104 から 105 (初期)

– 10120 (現在)

• 問題点

– 探索空間のサイズ(state explosion problem)6

Page 7: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

古典的モデル検査と現代的モデル検査

• 古典的モデル検査

– 対象: 仕様書,プロトコルなど

– 設計段階など,「上流工程」でモデル検査を適用.

– 仕様書などから検査器にかけられるモデルを (ほとんどの場合) 手動で構築.

• 現代的モデル検査

– 対象: プログラムソースコードなど

– テスト段階など,「下流工程」でモデル検査を適用.ほとんどデバッグの一種.

– ソースコードからモデルを自動的に抽出.7

Page 8: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

ソースコードモデル検査: 代表的なツール

• Java– Java Pathfinder (NASA)– Bandera (Kansas State Uni.)– Bogor (Kansas State Uni.)– JNuke (ETH)

• C/C++– Static Driver Verifier (Microsoft)– ZING (Microsoft)– BLAST (U. of Berkeley)– MAGIC (CMU)

8

Page 9: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

Java Path Finder (JPF)• NASA Ames Research Center

– W. Visser らによって開発された

• 2005 年 4 月以降は sourceforge.net で公開

• Java のバイトコードから状態を生成してモデル検査

• 反例を出力

– 全ての実行系列について探索するので、違反が発見されるまでの経路を出力できる

• 拡張可能

– プロパティクラス、リスナークラスによりユーザが定義する特性の検証が可能

• 独自の VM– 初期の JPF は PROMELA/SPIN に変換していたが、独自の VM に

より実行するように改良された。 Java.awt、java.net には非対応9

Page 10: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

JPFの動作原理 (1)

• Javaのクラスファイルは,Java Virtual Machine (JVM) によって解釈され,実行される.

11

*.class*.jar

Java Virtual Machine

....x ++;

....

(実際にはバイトコード)

a: 0b: 3x: 4 5y: -2

Page 11: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

JPFの動作原理 (2)

• JPFは,自分のJVMを持っている.通常のJVMと同様に,クラスファイルを解釈できる.

• さらに,後戻り (backtrack) したり,スレッドスケジュールを外から与えることもできる.

12

*.class*.jar

Java Virtual Machine for JPF

....x ++;

....

(実際にはバイトコード)

a: 0b: 3x: 4 5y: -2

Page 12: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

JPFの動作原理 (3)

• JPFの中心は,サーチエンジン.これが,JVM for JPF を駆動する.

13

サーチエンジンJVM

for JPF

次のバイトコードを実行せよ

このような状態になった.

これは以前の状態と同じだ.

後戻りして,スケジューリングを変えよ

次のバイトコードを実行せよ

Page 13: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

JPFの動作原理 (4)

• 実際には,状態量が増えすぎないように様々な工夫が行われている.

– 同定可能な範囲でできるだけコンパクトな状態

– スレッド相互間に干渉のない部分は一気に実行 (半順序簡約)

• サーチエンジン,JVMも含め,すべてjavaで書かれている.

14

Page 14: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

JPF構成図

15

Page 15: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

最上位構造

• 2つの中心的な概念: SearchとJVM

• JVM: 状態生成 (右図)

• Search: JVMのドライバ+性質の評価

17

Page 16: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

JPFの入手とバージョン

• 入手可能なバージョン: v3 と v4– v3: 安定版.ソースで配布.配布サイトではv1.0aと書かれている.J2SE1.4 に対応.(Java5では動作しない.)

– v4: 開発版.ソースで配布.頻繁に更新.v3と比べ,基本的な構成は同じ.使い勝手が向上している.Java5に対応.(J2SE1.4では動作しない.)

• ここでは v3 を使用する.http://sourceforge.net/projects/javapathfinder/ からjavapathfinder‐src‐libs‐1.0‐7‐oct‐05.zip をダウンロードして展開.(インストール指示書参照)

19

Page 17: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

JPF の利用方法についての注意

• Java のバージョン

– J2SE 1.4 のみに対応.

– J2SE 1.5 (Java5.0)以降は使わないので注意すること

• Cygwin を用いる.(http://www.cygwin.com/)

• JPF のインストール先

– C:¥JPF¥jpf release

• 設定方法 (次スライド以降)

– 環境変数の設定

– jpf    (C:¥JPF¥jpf release¥bin)20

Page 18: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

環境変数の設定• 以下のディレクトリからファイルbashrcをダウンロードする.

http://hagi.is.s.u‐tokyo.ac.jp/pub/staff/hagiya/kougiroku/0521JPF_tanabe/

• 以下の2つの行の内容を確認し,必要なら書き直す.

• 次のコマンドを実行 (先頭のドットに注意).

• bashrcファイルの内容を ~/.bashrc に追記しておけば,次回から以上の操作は不要.(他の講義の設定と衝突しないかどうか確認すること.)

21

JAVA_HOME="C:¥usr¥local¥java¥j2sdk1.4.2_12"JPF_HOME="C:¥JPF¥jpf release"

$ . bashrc

Page 19: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

22

# bashrc file for JPF#

# Set appropriate directories#JAVA_HOME="C:¥usr¥local¥java¥j2sdk1.4.2_12"JAVA_HOME="C:¥j2sdk1.4.2_14"#JPF_HOME="C:¥JPF¥jpf release"JPF_HOME="C:¥jpfv3¥release"

# Do not edit the following

JAVA_HOME_UNIX=`cygpath -u "${JAVA_HOME}"`JPF_HOME_UNIX=`cygpath -u "${JPF_HOME}"`export CLASSPATH="${JPF_HOME}¥build¥jpf;${JPF_HOME}¥lib;${JPF_HOME}¥examples;."export PATH="${JPF_HOME_UNIX}/bin:${JAVA_HOME_UNIX}/bin:/bin:/usr/bin:/usr/local/bin:${PATH}”

Page 20: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

スクリプト jpf の置き換え• スクリプト ${JPF_HOME}/bin/jpf を,以下のディレクトリにある jpf で置き換える.念のため,オリジナルの jpf は保存しておく.

http://hagi.is.s.u‐tokyo.ac.jp/pub/staff/hagiya/kougiroku/0521JPF_tanabe/

$ diff jpf jpf‐original‐

7d6

< JPF_HOME_UNIX=`cygpath ‐m "${JPF_HOME}"`

37,38c36,37

< #  JAVA_HOME=`cygpath ‐‐path ‐‐windows "$JAVA_HOME"`

< #  CLASSPATH=`cygpath ‐‐path ‐‐windows "$CLASSPATH"`

‐‐‐

>   JAVA_HOME=`cygpath ‐‐path ‐‐windows "$JAVA_HOME"`

>   CLASSPATH=`cygpath ‐‐path ‐‐windows "$CLASSPATH"`

59,60c58

< # echo java $JVM_FLAGS ‐classpath "$CP" gov.nasa.jpf.JPF +jpf.basedir="$JPF_HOME_UNIX" $@

< java $JVM_FLAGS ‐classpath "$CP" gov.nasa.jpf.JPF +jpf.basedir="$JPF_HOME_UNIX" $@

‐‐‐

> java $JVM_FLAGS ‐classpath "$CP" gov.nasa.jpf.JPF +jpf.basedir="$JPF_HOME" $@ 23

Page 21: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

JPFの基本機能

配布された (何もカスタマイズしない) 状態でできること

• デッドロックの検出

• アサーション違反の検出

• 捕捉されない例外の検出

24

Page 22: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

最初の例(Deadlock.java)‐デッドロックの検出

25

$ cd "${JPF_HOME}"

$ javac examples/deadlock/Deadlock.java

$ java deadlock.Deadlock

途中でプログラムが停止

$ jpf deadlock.Deadlock

エラー出力については後のスライドで説明

Page 23: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

26

1 package deadlock;

/*** This example shows a simple deadlock.

5 */public class Deadlock implements Runnable {

/*** A name for the thread.*/

10 String name;

/*** A reference to the other Deadlock object running as a separate thread.*/

15 Deadlock other;

public Deadlock (String name) {this.name = name;

}20public static void main (String[] args) {

Deadlock o1 = new Deadlock("A");Deadlock o2 = new Deadlock("B");

25 o1.other = o2;o2.other = o1;

Page 24: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

27

Thread t1 = new Thread(o1);Thread t2 = new Thread(o2);

30t1.start();t2.start();

}

35 public void run () {while (true) {System.out.println(name + " cycle start");synchronized (this) {other.foo();

40 }

System.out.println(name + " cycle end");}

}45

synchronized void foo () {System.out.println(name + ".foo() was called");}

50 }

Page 25: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

プログラムの説明

• プログラムの並列実行 31, 32

• 自分自身のロックを獲得 38

• 相手オブジェクトのメソッド foo() を呼ぶ 39

• ロックを開放する前に相手オブジェクトからメソッドを呼ばれるとデッドロックに陥る

28

Page 26: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

29

1 C:¥jpf deadlock.DeadlockA cycle startB.foo() was calledA cycle end

5 A cycle startA cycle startB.foo() was calledA cycle endA cycle start

10 B.foo() was calledA cycle endA cycle startB.foo() was calledA cycle end

15 B cycle startA cycle startB.foo() was calledA cycle endA cycle end

20 A cycle start------------------------------------ thread stacksThread: Thread-0

at deadlock.Deadlock.run(deadlock¥Deadlock.java:57)

Thread: Thread-1at deadlock.Deadlock.run(deadlock¥Deadlock.java:57)

------------------------------------ end thread stacks

スレッド#0

スレッド#1

行番号 other.foo()

Page 27: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

30

1Deadlock

----------------------------------- path to error (length: 88)Transition #0 Thread #0

5 deadlock¥Deadlock.java:40 Deadlock o1 = new Deadlock("A");deadlock¥Deadlock.java:35 public Deadlock (String name) {deadlock¥Deadlock.java:36 this.name = name;deadlock¥Deadlock.java:37 }deadlock¥Deadlock.java:40 Deadlock o1 = new Deadlock("A");

10 deadlock¥Deadlock.java:41 Deadlock o2 = new Deadlock("B");deadlock¥Deadlock.java:35 public Deadlock (String name) {deadlock¥Deadlock.java:36 this.name = name;deadlock¥Deadlock.java:37 }deadlock¥Deadlock.java:41 Deadlock o2 = new Deadlock("B");

15 deadlock¥Deadlock.java:43 o1.other = o2;deadlock¥Deadlock.java:44 o2.other = o1;deadlock¥Deadlock.java:46 Thread t1 = new Thread(o1);deadlock¥Deadlock.java:46 Thread t1 = new Thread(o1);deadlock¥Deadlock.java:47 Thread t2 = new Thread(o2);

20(snipped)

deadlock¥Deadlock.java:56 synchronized (this) {Transition #86 Thread #1

25 deadlock¥Deadlock.java:56 synchronized (this) {deadlock¥Deadlock.java:57 other.foo();

Transition #87 Thread #2deadlock¥Deadlock.java:57 other.foo();

------------------------------------ end error path

===================================1 Error Found: Deadlock

===================================

Page 28: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

デッドロックとなる理由

31

synchronized (this) {

other.foo()

}

スレッド1

synchronized (this) {

other.foo()

}

t2

スレッド2

#85,86

#69,80

t1

#86

#87

Page 29: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

(比較) デッドロックとはならない場合

32

synchronized (this) {

other.foo()

}

スレッド1

synchronized (this) {

other.foo();

}

t2

スレッド2

t1

t2t1

Page 30: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

Javaアサーション

• 指定したboolean式の値がtrueになるべきであるという表明.

• 実行時に式の値がfalseになると,実行時エラー(java.lang.AssertionError)になる.

• 形式: assert p : m– p : チェック対象のboolean型の式

– m : エラーメッセージ「: m」の部分は省略可能.

• コンパイルオプション: javac -source 1.4• 実行時オプション: java -ea

33

Page 31: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

JPFとアサーション

• 通常の実行時には,アサーションの位置に制御が渡ったときに,チェックが行われる.→  その実行によって通らないパスでは,チェックが行われない.

• JPFによる実行時には,すべてのパスでチェックが行われる.

34

Page 32: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

例: AssertionTest1.java

• 2つのスレッド a1 と a2

• a1 が先に start.  a2が後から start

• run の内容: 自分自身を「登録する」

• 登録の内容: at1 が空いていたら at1 に,そうでなかったらat2に代入.

• 両方登録が終わったとき,a1 == at1 になるか?

35

Page 33: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

AssertionTest1.java

36

at1 = null; at2 = null;AssertionTest a1 = new AssertionTest(10);

AssertionTest a2 = new AssertionTest(20);

a1.start();a2.start();assert at1.getVal() < at2.getVal();

スレッド0

at1 = a1;at2 = a2;

スレッド1 スレッド2

null pointer exception

テストで検出できる.

JPFも,エラーを報告する.

Page 34: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

JPFエラートレース

37

----------------------------------- path to error (length: 3)Transition #0 Thread #0(略)egs¥AssertionTest1.java:31 a1.start();egs¥AssertionTest1.java:32 a2.start();

Transition #1 Thread #0egs¥AssertionTest1.java:33 assert at1.getVal() < at2.getVal() : "unexpected order";

Transition #2 Thread #0egs¥AssertionTest1.java:33 assert at1.getVal() < at2.getVal() : "unexpected order";

------------------------------------ end error path

------------------------------------ thread stacksThread: Thread-0

at egs.AssertionTest1.run(egs¥AssertionTest1.java:25)

Thread: Thread-1at egs.AssertionTest1.run(egs¥AssertionTest1.java:25)

------------------------------------ end thread stacks

===================================1 Error Found: uncaught exception

===================================

Page 35: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

AssertionTest2.java  (1)

38

at1 = null; at2 = null;AssertionTest a1 = new AssertionTest(10);

AssertionTest a2 = new AssertionTest(20);

a1.start();a2.start();if (at2 != null) { ... }

if (at2 != null) {assert at1.getVal() < at2.getVal();

}

スレッド0

at1 = a1;// at1.getVal() == 10 at2 = a2;

// at2.getVal() == 20

スレッド1 スレッド2

assertion は成功

1CPUマシンでは,こうなることが多い(?)しかし,状況によっては.....

Page 36: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

AssertionTest2.java  (2)

39

at1 = null; at2 = null;AssertionTest a1 = new AssertionTest(10);

AssertionTest a2 = new AssertionTest(20);

a1.start();a2.start();if (at2 != null) { ... }

if (at2 != null) {assert at1.getVal() < at2.getVal();

}

スレッド0

at2 = a1;// at2.getVal() == 10

at1 = a2;// at1.getVal() == 20

スレッド1 スレッド2

assertion は失敗

テストでは検出できるとは限らない.

JPFでは,検出できる.

Page 37: 何故モデル検査が必要なのか?nicosia.is.s.u-tokyo.ac.jp/pub/staff/hagiya/kougiroku/...何故モデル検査が必要なのか?• 多くのソフトウェアが分散処理・並行処理を基

JPFエラートレース

40

----------------------------------- path to error (length: 20)Transition #0 Thread #0(略)egs¥AssertionTest2.java:31 a1.start();egs¥AssertionTest2.java:32 a2.start();

(略)Transition #7 Thread #2egs¥AssertionTest2.java:12 if (at1 == null) {at1 = at; }egs¥AssertionTest2.java:11 synchronized(lockObj) {

(略)Transition #11 Thread #1egs¥AssertionTest2.java:13 else {at2 = at; }egs¥AssertionTest2.java:11 synchronized(lockObj) {

(略)Transition #19 Thread #0egs¥AssertionTest2.java:18 public int getVal() { return val; }egs¥AssertionTest2.java:36 assert at1.getVal() < at2.getVal() : "unexpected order";

(略)------------------------------------ end error path

===================================1 Error Found: uncaught exception

===================================