• 沒有找到結果。

第一步:對存取陣列當中的索引值設定為criterion,進行program slicing分析,產生slice,

N/A
N/A
Protected

Academic year: 2021

Share "第一步:對存取陣列當中的索引值設定為criterion,進行program slicing分析,產生slice,"

Copied!
36
0
0

加載中.... (立即查看全文)

全文

(1)

第四章 案例探討

RuntimeException 意義為程式設計不當所造成軟體錯誤的情況。本研究探討 了 許 多 Java 程 式 當 中 發 生 RuntimeException 的 例 子 , 像 是 NullPointerException 、 ArithmeticException 、 ArrayStoreException 、 ArrayIndexOutOfBoundsException EmptyStackException NoSuchElementException 等等這些 RuntimeException。也由於對於這些錯誤有 了實際案例的研究,我們將這些錯誤發生的原因歸納了幾點如下:

1. 物 件 數 值 設 定 錯 誤 - 這 種 錯 誤 主 要 在 於 數 值 上 的 錯 誤 , 例 如 ArithmeticException 的 divided by zero 情況,就是其除數設定錯誤(設定 為 0)。以及像是 ArrayIndexOutOfBoundsException 這種存取陣列的索引錯 誤的情況,就是索引值錯誤所導致的 exception。簡單的概念就是因為程式 設計錯誤導致軟體執行時內部變數的值不符合程式碼運作所需要的值的範 圍。

2. 物件存在與否的錯誤-如 NullPointerException 則是對於一個 null 的物件 進行函式呼叫或是存取其 field 值。或是 EmptyStackException 這種當一個 stack 已經沒有存在任何物件,卻又執行 pop 或是 perk 等指令,造成程式發 生 EmptyStackException 的錯誤。此類 exception 發生的原因則在於物件存 在與否所造成之錯誤。

3. 物 件 型 態 的 錯 誤 - 這 種 錯 誤 原 因 出 在 物 件 型 態 上 的 錯 誤 , 以 ArrayStoreException 為例,其發生原因是將一個物件指派至一個陣列當 中,而兩者之間的型態上不符所造成之錯誤。

以下我們便針對這三種 Java 程式當中造成軟體發生錯誤的情況提出案例,跟大 家做說明,並且利用我們設計的分析方法評斷出可能造成其錯誤的敘述。

(2)

4.1 以案例說明物件數值造成之錯誤

z 案例一:ArrayIndexOutOfBoundsException

本案例主要是對 ArrayIndexOutOfBoundException 做探討。當一個軟體發生 此類錯誤,代表程式中存在一個陣列(array),而存取這個陣列的索引值(index) 超出了陣列的範圍。通常這種錯誤以索引值設定為主要原因,但是也不能不考慮 陣列本身在設計上的錯誤(例如長度設定錯誤)。以下案例探討當程式發生此類錯 誤,利用 rule 分析程式並且使用 program slicing 技術為輔助。

本範例為一個比大小的遊戲,程式碼及系統架構如圖 22、圖 23,主要有四 個元件組成。poker元件存在許多card,每一個card有自己的數值。在play table 上有多個player,play table 從poker取得所有牌號數值(getCard)之後存在一 個陣列當中,dealer會根據此陣列大小設定隨機取牌的範圍(CardCount)。dealer 會不斷的發牌(DoDealing)而且會從play table當中牌號陣列的挑一個數值給 (ChooseNumber)player。player自行決定是否要攤牌(showdown),每一次攤牌都 要 把 player 自 己 的 錢 給 扣 除 當 作 賭 金 , 若 數 值 大 於 別 的 player , 則 算 贏 了 (sayWin),player會把錢給加回來。若所有player都決定不showdown,則平手。

本系統在 play table 元件當中會產生 ArrayIndexOutOfBoundsException,

發生在 dealer 從 play table 上的取卡片給 player 的時候。系統發生此錯誤的 原因在於 dealer 從 play table 取得 card 的數量之後,卻在對於隨機取牌的範 圍擅自多加了額外的值。導致 dealer 存取 play table 當中存放牌的陣列時造成 ArrayIndexOutOfBoundsException。

(3)

Component :play table 1 import Poker.poker_obj;

2 import dealer.dealer;

3 import player.player;

4 public class playTable {

5 public static void main(String[] args) { 6 poker_obj po=new poker_obj();

7 Integer allCard[]=po.getCard();

8 dealer d=new dealer();

9 player player1=new player(1);

10 player player2=new player(2);

11 d.CardCount(allCard.length);

12 while(d.DoDealing()){

13 int index =d.ChooseNumber();

14 player1.setOwnCard(allCard[index]);

15 player2.setOwnCard(allCard[index]);

16 if(player1.getOwnNumber().compareTo(player2.getOwnNumber())>0){

17 player1.sayWin();

18 }

19 else if(player1.getOwnNumber().compareTo(player2.getOwnNumber())<0) {

20 player2.sayWin();

21 }

22 }

23 } 24 }

Component :poker 1 package Poker;

2 public class poker_obj {

3 Integer[] card1=new Integer[52];

4 public poker_obj(){

5 for(int a=0;a<card1.length;a++){

6 card1[a]=new Integer(a);

7 }

8 int c=0;

9 while(c<1000){

10 swap((int)(Math.random()*52), (int)(Math.random()*52));

11 c++;

12 }

13 }

14 void swap(int a,int b){

15 Integer temp=card1[a];

16 card1[a]=card1[b];

17 card1[b]=temp;

18 }

19 Integer get(int i){

20 return card1[i];

21 }

22 public Integer[] getCard(){

23 return card1;

24 } 25 }

Component : dealer 1 package dealer;

2 import Poker.poker_obj;

3 public class dealer { 4 int cardNumber;

5 public dealer(){

6 }

7 public boolean DoDealing(){

8 return true;

9 }

10 public int ChooseNumber(){

11 return (int)(Math.random()*(cardNumber +1);

12 }

13 public void CardCount(int i){

14 cardNumber=i;

15 } 16 } Component :player

1 package player;

2 public class player { 3 int playerNumber;

4 Integer ownNumber;

5 int money=100;

6 public player(int a){

7 playerNumber=a;

8 }

9 public void sayWin(){

10 money=money+5;

11 System.out.println("player"+playerNumber+"Win");

12 }

13 public void setOwnCard(Integer a){

14 ownNumber=a;

15 }

16 public Integer getOwnNumber(){

17 if(ownNumber.intValue() < 26) {

18 if((int)(Math.random()*10)<5) 19 return new Integer(0);

20 }

21 money=money-5;

22 return ownNumber;

23 } 24 }

圖 22 案例一(ArrayIndexOutOfBoundsException)程式碼

(4)

圖 23 案例一(ArrayIndexOutOfBoundsException)元件架構圖

z 此案例使用軟體錯誤診斷分析之過程:

Step 1. 當軟體發生錯誤中斷後,Rule Engine當中的Rule Processing Engine 將根據來自Class Loader的錯誤訊息(exception message)分析出軟體 錯誤型態為ArrayIndexOutOfBoundsException,會先去尋找系統當中處 理ArrayIndexOutOfBoundsException的rule script(圖 24),並且根 據此rule script所設定之步驟呼叫rule評估系統。

Step 2. 此 錯 誤 的 rule script 主 要 是 針 對 存 取 陣 列 的 索 引 值 設 定 為 criterion,以及設定陣列本身為 criterion,並且將此兩個 criterion 進行 program slicing 產生多個 slice,並且將這些 slice 聯集起來,

形 成 新 的 slice 作 為 結 果 。 通 常 一 般 而 言 , 軟 體 若 發 生 ArrayIndexOutOfBoundsException,往往是索引值的錯誤,不過我們也 不應該忽略陣列本身是否設計上有誤,因此也必須要對陣列設定成 criterion 進行 program slicing 分析。所以設定索引值為 criterion 進行分析以及設定陣列作為 criterion 進行分析兩者的權重(Weight) 不同,而在 rule script 則對索引值進行分析的 weight 值高於對陣列 進行分析的 weight 值。

目前我們 rule script 所給定的 weight 值都是假設值,未來應該要以實驗數據

(5)

估算出這些 weight 值,以求更精確的評估軟體錯誤元件。

由Class loader所捕捉到的Exception Message

java.lang.ArrayIndexOutOfBoundsException Rule Engine

: 52 at playTable.main(playTable.java:15) Exception in thread "main"

選擇 rule script

根據 exception message 的資訊所使用 ArrayIndexOutOfBoundsException 的 rule script:

第一步:對存取陣列當中的索引值設定為criterion,進行program slicing分析,產生slice,

slice當中的每個敘述將會得到weight的積分值。

(使用Rule 4可以設定陣列當中的索引值進行分析。在此我們設定weight為2。) 第二步:對陣列設定為criterion,進行program slicing分析,產生slice,slice當中的每個敘

述將會得到weight的積分值。

(使用Rule 5可以設定陣列進行分析。在此我們設定weight為1。) 第三步:將上述兩個slice集合聯集成新的slice作為最後結果。

圖 24 案例一,Rule Engine 根據錯誤類別(ArrayIndexOutOfBoundsException) 選取對應的腳本運作

(6)

z 本案例(ArrayIndexOutOfBoundsException)使用rule 4 (設定陣列索引值為 criterion),weight為 2 的所做的分析(圖 25):

當程式中使用索引值存取陣列時發生錯誤,在此判斷此索引值不正確為造成 軟體發生 ArrayIndexOutOfBoundsException 的原因。本次分析將其索引值 (在此為變數 index)設定為 criterion:

Component :play table 1 import Poker.poker_obj;

2 import dealer.dealer;

3 import player.player;

4 public class playTable {

5 public static void main(String[] args) { 6 poker_obj po=new poker_obj();

7 Integer allCard[]=po.getCard();

8 dealer d=new dealer();

9 player player1=new player(1);

10 player player2=new player(2);

11 d.CardCount(allCard.length);

12 while(d.DoDealing()){

13 int index =d.ChooseNumber();

14 player1.setOwnCard(allCard[index]);

15 player2.setOwnCard(allCard[index]);

16 if(player1.getOwnNumber().compareTo(player2.getOwnNumber())>0){

17 player1.sayWin();

18 }

19 else if(player1.getOwnNumber().compareTo(player2.getOwnNumber())<0) {

20 player2.sayWin();

21 }

22 }

23 } 24 }

圖 25 案例一(ArrayIndexOutOfBoundsException)使用 rule 4 分析程式。

(rule 5 分析過程與 rule 4 相同,只是選取的 criterion 不同)

(7)

z 本案例(ArrayIndexOutOfBoundsException)使用rule 4 (設定陣列索引值為 criterion),weight為 2 所產生之結果(圖 26):每一個敘述句以及變數宣 告將會得到weight(在本例weight值為 2)的積分值。雙底線為criterion,底 線代表運作program slicing分析出來之敘述句(player經過分析將被排除在 外)。

Component : dealer 1 package dealer;

2 import Poker.poker_obj;

3 public class dealer { 4 int cardNumber;

5 public dealer(){

6 }

7 public boolean DoDealing(){

8 return true;

9 }

10 public int ChooseNumber(){

11 return (int)(Math.random()*(cardNumber +1);

12 } 13 14 15 16 } Component :play table

1 import Poker.poker_obj;

2 import dealer.dealer;

3 import player.player;

4 public class playTable {

5 public static void main(String[] args) { 6

7

8 dealer d=new dealer();

9 10 11

12 while(d.DoDealing()){

13 int i=d.ChooseNumber();

14 player1.setOwnCard(allCard[index]);

15 player2.setOwnCard(allCard[ index ]);

16 17 18 19 20 21

22 }

23 } 24 }

Score=2+2+2+2=8

圖 26 案例一使用 rule 4 (設定陣列索引值為 criterion)所產生之結果

(8)

z 本 案 例 (ArrayIndexOutOfBoundsException) 使 用 rule 5 ( 設 定 陣 列 為 criterion),將會設定AllCard為criterion(圖 26)。進行program slicing 分析之後結果如下 (圖 27):

每一個敘述句以及變數宣告將會得到 weight(在本例 weight 值為 1)的積分 值。底線代表運作 program slicing 分析出來之敘述句,因為以陣列為 criterion,則將會把設定陣列值的物件分析出來。

Component :poker 1

2 public class poker_obj {

3 Integer[] card1=new Integer[52];

4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

22 public Integer[] getCard(){

23 return card1;

24 } 25 } Component : dealer

1

2 import Poker.poker_obj;

3 public class dealer { 4

5 public dealer(){

6 }

7 public boolean DoDealing(){

8 return true;

9 } 10 11 12 13 14 15 16

17 } Score=1

Score=1+1=2

Component :play table 1 import Poker.poker_obj;

2 import dealer.dealer;

3 import player.player;

4 public class playTable {

5 public static void main(String[] args) { 6 poker_obj po=new poker_obj();

7 Integer allCard[]=po.getCard();

8 dealer d=new dealer();

9 10 11

12 while(d.DoDealing()){

13

14 player1.setOwnCard(allCard[index]);

15 player2.setOwnCard(allCard[index ]);

16 17 18 19 20 21

22 }

23 } 24 }

圖 27 案例一使用 rule 5 (設定陣列為 criterion),所分析出來之結果

(9)

z Rule Processing Engine會將上述兩個rule所產生出來的資訊做集合運算中 的聯集(標粗體敘述為交集共有部份)。當中元件dealer的DoDealing()函式 的第八行敘述為兩個slice共同擁有的部份,因此此Rule Processing Engine 會將兩個slice當中個別積分加總成為聯集過後的積分。於是產生出最後結 果(圖 28):

Component : dealer 1

2 import Poker.poker_obj;

3 public class dealer { 4 int cardNumber;

5 public dealer(){

6 }

7 public boolean DoDealing(){

8 return true;

9 }

10 public int ChooseNumber(){

11 return (int)(Math.random()*(temp.getCardNumber())+1);

12 } 13 14 15 16 }

Component :play table 1 import Poker.poker_obj;

2 import dealer.dealer;

3 import player.player;

4 public class playTable {

5 public static void main(String[] args) { 6 poker_obj po=new poker_obj();

7 Integer allCard[]=po.getCard();

8 dealer d=new dealer();

9 10 11

12 while(d.DoDealing()){

13 int index =d.ChooseNumber();

14 player1.setOwnCard(allCard[index]);

15 player2.setOwnCard(allCard[index ]);

16 17 18 19 20 21

22 }

23 } 24 }

Score=8+1=9

兩個 slice 共同擁有敘述,則此敘述的積分為 在個別兩個 slice 當中此敘述的積分相加。

Criterion= allCard UNION index Score=2

Component :poker 1

2 public class poker_obj {

3 Integer[] card1=new Integer[52];

4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

22 public Integer[] getCard(){

23 return card1;

24 } 25 }

圖 28 Rule Processing Engine聯集以及圖 26以及圖 27所產生之slice

(10)

z 本案例(ArrayIndexOutOfBoundsException)經過分析過後之系統元件架構 圖,以及其積分值(圖 29):

經過分析之後,發現 dealer 的錯誤積分較高,因此對 dealer 元件進行替換。

若新的 dealer 元件修正 ChooseNumber 當中的錯誤。則此程式將不會發生相 同的 ArrayIndexOutOfBoundsException。

圖 29 案例一經過 Rule Engine 評估後所產生各軟體元件架構圖以及其積分值

(11)

4.2 以案例說明物件存在與否所造成之錯誤

z 案例二:NullPointerException-

本 案 例 主 要 是 對 NullPointerException 進 行 探 討 。 程 式 會 發 生 NullPointerException 的原因多在於當一個 null 的物件使用其方法,或是對其 存取 field 值所造成,以下案例也是針對這種情況進行分析。對於一個軟體在執 行的時候發生 NullPointerException 而中斷執行,根據留下的錯誤訊息使用 rule 跟 program slicing 技術來對軟體進行診斷。

探討的系統架構主體分作五個元件(如 圖 30):create object、middle transport以及main program。create object主要生成一個String物件內容值 是"Hello World",生成之後會傳送給middle transport。並且透過middle transport的get_String傳送給main program,讓main program印出字串。create object當中會需要隨機的數值,random value負責提供給create object一個隨 機數值 、epsilon value跟PI value提供特定數值給main program印出字串的元 件。本案例程式碼如圖 31,主要造成錯誤的設計在於component create object 當中物件的生成不正確,如圖 31 案例二 探討(NullPointerException)範例之程 式碼(根據元件區分)component create object當中ObjectCreate的第 16 行控制 敘述設計錯誤導致生成物件的 17 行無法執行。卻又透過middle transport將此 null的物件傳送給main program,main program使用此物件的方法,導致系統產 生NullPointerException。

圖 30 案例二 (NullPointerException)之元件架構圖

(12)

Component :main program 1 import GetEpsilonValue.publicE;

2 import MidTransObj.publicB;

3 import PI_Value.publicF;

4 public class TestNullPointer {

5 public static void main(String[] args) { 6 publicF GetPI_Value = new publicF();

7 publicB S_from_MidTransObj= new publicB();

8 publicE Epsilon=new publicE();

9 int i=(int)Epsilon.GetE_Val();

10 String String_from_PI =GetPI_Value.toString();

11 String String_to_Use=S_from_MidTransObj.get_String();

12

String allString=String_from_PI+String_to_Use.substring(i);

//throw the null pointer exception 13 System.out.println(allString);

14 } 15 }

Component: middle transport 1 package MidTransObj;

2 import randomValue.RandomC;

3 import ObjectCreat_A.ObjCreate;

4 public class MidTrans_B { 5 private double dividor;

6 private String SB_Ex;

7 public MidTrans_B() {

8 }

9 public String get_String(){

10 ObjCreate ObjA=new ObjCreate();

11 AlwaysTrue t =new AlwaysTrue();

12 if(t.getT())

13 SB_Ex=ObjA.GetString();

14 return SB_Ex;

15 } 16 }

1 package MidTransObj;

2 public class AlwaysTrue {

3 public boolean getT(){

4 return true;

5 } 6 public int getI(){

7 return 1;

8 } 9 }

Component:create object 1 package ObjectCreat_A;

2 import randomValue.RandomC;

3 import java.util.Vector;

4 public class ObjCreate { 5 private Object tempA=null;

6 private String SA_Ex;

7 public ObjCreate() { 8 }

9 public int GetA_Val(){

10 RandomC tempC=new RandomC();

11 int temp=(int)tempC.GetRandomVal();

12 return temp;

13 }

14 public String GetString(){

15 RandomC tempC=new RandomC();

16 if(tempC.GetRandomVal()>1){

17 SA_Ex=new String("Hello world");

18 }

19 return SA_Ex;

20 } 21 }

Component:epsilon value 1 package GetEpsilonValue;

2 public class publicE { 3 public publicE() {

4 }

5 public double GetE_Val(){

6 double e_val=Math.E;

7 return e_val;

8 } 9 }

Component:PI Value 1 package PI_Value;

2 public class GetPIValue { 3 public GetPIValue() { 4 }

5 public double GetPI(){

6 return Math。PI;

7 } 8 }

Component:random value 1 package randomValue;

2 public class RandomC { 3 public RandomC() { 4 }

5 public double GetRandomVal(){

6 double temp=(Math.random());

7 return temp;

8 } 9}

圖 31 案例二 探討(NullPointerException)範例之程式碼(根據元件區分)

(13)

z 此案例使用軟體錯誤診斷分析之過程-

當軟體發生錯誤中斷後,Rule Engine當中的Rule Processing Engine將根 據來自Class Loader的錯誤訊息(exception message)分析出軟體錯誤型態為 NullPointerException會先去尋找系統當中處理NullPointerException的rule script ( 如 圖 32 )。 並 且 根 據 此 rule script 所 設 定 之 步 驟 呼 叫 rule(NullPointerException rule script的流程說明請參閱3.3.2使用程式範例 說明Rule Engine)。

由Class loader所捕捉到的exception message

java.lang.NullPointerException Rule Engine

at TestNullPointer.main(TestNullPointer.java:12) Exception in thread "main"

選擇 rule script

根據 exception message 的資訊所使用 NullPointerException 的 rule script

第一步:對於產生NullPointerException錯誤的敘述句,設定造成程式發生

NullPointerException的變數為criterion產生slice,產生的資訊每一個敘述句將得到 weight的積分。

(使用Rule 2 將會找出這些變數並且在此設定Weight為 1)

第二步:對於上一個步驟產生的slice,尋找造成錯誤的變數criterion所指向的物件是否來自其 他元件的生成,並且透過某些指令將其傳遞給criterion,我們標記這些傳遞以及生成的 指令。

(使用Rule 11將會標記這些傳遞或是生成物件給criterion敘述,在此設定Weight為4) 第三步:尋找在slice當中的控制敘述,若被標記的指令被某些控制敘述所影響,則造成criterion

所指向的物件則有可能便是因為這些控制敘述設計不當,導致傳遞給criterion或是生 成物件失敗。

(使用Rule 12將會找尋這些控制敘述,在此設定Weight為10)

圖 32 案例二,Rule Engine 根據錯誤類別(NullPointerException)選取對應運 作的腳本

(14)

z 本案例(NullPointerException)使用rule 2(設定使用方法以及存取field的 物件為criterion),Weight為 1 所進行之分析(如圖 33):

Rule 2 主要是分析當物件呼叫方法或是存取 field 時候,設定此物件為 criterion。例如程式若丟出 NullPointerException 的原因多在於一個 null 的 物 件 呼 叫 方 法 或 是 存 取 field , 所 以 在 此 判 斷 此 物 件 為 造 成 NullPointerException 的 原 因 並 設 定 其 為 criterion 進 行 program slicing。

Component :main program

1 import GetEpsilonValue.publicE;

2 import MidTransObj.publicB;

3 import PI_Value.publicF;

4 public class TestNullPointer {

5 public static void main(String[] args) { 6 publicF GetPI_Value = new publicF();

7 publicB S_from_MidTransObj= new publicB();

8 publicE Epsilon=new publicE();

9 int i=(int)Epsilon.GetE_Val();

10 String String_from_PI =GetPI_Value.toString();

11 String String_to_Use=S_from_MidTransObj.getA_String();

12 String allString=String_from_PI+String_to_Use.substring(i);

NullPointerException TestNullPointer.java Line 12

設定 String_to_Use 為 criterion

圖 33 案例二 (NullPointerException)使用 rule 2(選取使用物件方法或是存取 其 field 值為 criterion)進行分析

z 本案例(NullPointerException)使用rule 2(設定使用方法以及存取field的

(15)

物件為criterion),Weight為 1 所產生之結果(如圖 34):每一個敘述句以 及變數宣告將會得到weight(在本例weight值為 1)的積分值。底線代表運作 program slicing分析出來之敘述句。

Component :main program 1

2 import MidTransObj.publicB;

3

4 public class TestNullPointer {

5 public static void main(String[] args) { 6

7 publicB S_from_MidTransObj= new publicB();

8 9 10

11 String String_to_Use=S_from_MidTransObj.get_String();

12

String allString=String_from_PI+String_to_Use.substring(i);

//throw the null pointer exception 13 System.out.println(allString);

14 } 15 }

Component: middle transport 1 package MidTransObj;

2

3 import ObjectCreat_A.ObjCreate;

4 public class MidTrans_B { 5

6 private String SB_Ex;

7 public MidTrans_B() {

8 }

9 public String get_String(){

10 ObjCreate ObjA=new ObjCreate();

11 AlwaysTrue t =new AlwaysTrue();

12 if(t.getT())

13 SB_Ex=ObjA.GetString();

14 return SB_Ex;

15 } 16 }

1 package MidTransObj;

2 public class AlwaysTrue {

3 public boolean getT(){

4 return true;

5 } 6

7 8 9 }

Component:create object 1 package ObjectCreat_A;

2 import randomValue.RandomC;

3

4 public class ObjCreate { 5

6 private String SA_Ex;

7 public ObjCreate() { 8 }

9 10 11 12 13

14 public String GetString(){

15 RandomC tempC=new RandomC();

16 if(tempC.GetRandomVal()>1){

17 SA_Ex=new String("Hello world");

18 }

19 return SA_Ex;

20 } 21 }

Component:epsilon value 1

2 3 4 5 6 7 8 9

Component:PI Value 1

2 3 4 5 6 7 8

Component:random value 1 package randomValue;

2 public class RandomC { 3 public RandomC() { 4 }

5 public double GetRandomVal(){

6 double temp=(Math.random());

7 return temp;

8 } 9}

Component score:5

Component score:2

Total score:14

Component score:7

圖 34 案例二 (NullPointerException)使用 rule 2 (選取使用物件方法或是存 取其 field 值為 criterion)所產生之結果

z 本案例(NullPointerException)使用rule 11 (追蹤設定criterion的物件傳

(16)

遞生成敘述),weight為 4 所進行之分析。rule 11 主要使用遞迴方法,依序 紀錄直接或間接設定criterion的外部物件。下面是rule 11 的第一個步驟(如 圖 35):

把 criterion : (TestNullPointer , Line 12 , String_to_Use)傳入 rule 11。對每一個在此 rule engine slice 的敘述句有順序的進行分析(只分析 在此 criterion 之前之敘述句)。

如 TestNullPointer 的第 11 行:

“String_to_Use = S_from_MidTransObj.get_String();"

String_to_Use 被一個 S_from_MidTransObj 這個物件當中 get_String()的 回傳值所指派。將此方法的回傳值傳入 rule 11 的遞迴函式開啟新的遞迴呼 叫繼續找尋。在這個案例當中只有 TestNullPointer 的第 11 行直接指派變 數給 String_to_Use,所以這一步驟的遞迴函式將只標記這一行。

Component :Main program 1

2 import MidTransObj.publicB;

3

4 public class TestNullPointer {

5 public static void main(String[] args) { 6

7 publicB S_from_MidTransObj= new publicB();

8 9

10 11 String

String_to_Use=S_from_MidTransObj.get_String();

12

String allString=String_from_PI+String_to_Use.substring(i);

//throw the null pointer exception 13 System.out.println(allString);

14 } 15 }

Component: middle transport 1 package MidTransObj;

2

3 import ObjectCreat_A.ObjCreate;

4 public class MidTrans_B { 5

6 private String SB_Ex;

7 public MidTrans_B() {

8 }

9 public String get_String(){

10 ObjCreate ObjA=new ObjCreate();

11 AlwaysTrue t =new AlwaysTrue();

12 if(t.getT())

13 SB_Ex=ObjA.GetString();

14 return SB_Ex;

15 } 16 }

1 package MidTransObj;

2 public class AlwaysTrue {

3 public boolean getT(){

4 return true;

5 } 6

7 8 9 }

1.Criterion 傳入 Rule 11 之遞迴方法.

3.將此方法(getA_String)之回傳值 (SB_Ex)傳入 Rule 11 的遞迴方法繼續 找尋下去.

2.找尋到符合文法之 statement, 並標記之(line 11)

圖 35 案例二 (NullPointerException)使用 rule 11(追蹤設定 criterion 的物 件傳遞生成敘述)分析步驟之一

z 案例(NullPointerException)使用rule 11 (追蹤criterion的物件傳遞關係)

(17)

的第二步驟(如圖 37):

由 於 上 一 個 遞 迴 將 middle tranport 元 件 當 中 MidTrans_B 的 函 式 Get_String()的回傳值傳入 rule 11 的遞迴方法,所以將 Get_String()回傳 值(MidTrans_B , Line 14 , SB_Ex)

並且透過 rule 11 找出 MidTrans_B 的第 13 行:

SB_Ex=ObjA.GetString();

標記此行,並且將 ObjA 當中的 GetString()的回傳值傳入 rule 11 的遞迴呼 叫開啟新的遞迴函式。

Component: middle transport 1 package MidTransObj;

2

3 import ObjectCreat_A.ObjCreate;

4 public class MidTrans_B { 5

6 private String SB_Ex;

7 public MidTrans_B() {

8 }

9 public String get_String(){

10 ObjCreate ObjA=new ObjCreate();

11 AlwaysTrue t =new AlwaysTrue();

12 if(t.getT())

13 SB_Ex=ObjA.GetString();

14 return SB_Ex;

15 } 16 }

1 package MidTransObj;

2 public class AlwaysTrue {

3 public boolean getT(){

4 return true;

5 } 6

7 8 9 }

Component:create object 1 package ObjectCreat_A;

2 import randomValue.RandomC;

3

4 public class ObjCreate { 5

6 private String SA_Ex;

7 public ObjCreate() { 8 }

9 10 11 12 13

14 public String GetString(){

15 RandomC tempC=new RandomC();

16 if(tempC.GetRandomVal()>1){

17 SA_Ex=new String("Hello world");

18 }

19 return SA_Ex;

20 } }

1.將此回傳值設為

criterion 傳入 Rule 11 之遞迴方法。

2.找尋到符合模式之 statement,

並標記之(line 13)

3.將此方法(Get_String)之回傳值 (SA_EX)傳入 Rule 15 的遞迴方法繼續找尋 下去.

圖 36 案例二(NullPointerException)使用 rule 11(追蹤設定 criterion 的物件 傳遞生成敘述)分析步驟之二

z 案例(NullPointerException)使用rule 11 (追蹤criterion的物件傳遞關係)

(18)

的第三步驟(如圖 37):

上一個步驟的遞迴將 ObjectCreate 當中的函式 GetString()的回傳值傳入 rule 11 開啟新的遞迴。所以本步驟將(ObjectCreate,Line 17,SA_Ex)傳入 rule 11 的遞迴函式。透過分析將會找出第 17 行 SA_Ex 符合文法並標記此行,

而由於在此行當中 SA_Ex 並非由其他物件指派也不是物件方法的回傳值跟 field 值所設定,所以評估第 17 行的 SA_Ex 物件的值為本身所產生,rule 11 並不會再開啟一個新的遞迴呼叫,而是將此敘述再給予加分。

Component:create object 1 package ObjectCreat_A;

2 import randomValue.RandomC;

3

4 public class ObjCreate { 5

6 private String SA_Ex;

7 public ObjCreate() { 8 }

9 10 11 12 13

14 public String GetString(){

15 RandomC tempC=new RandomC();

16 if(tempC.GetRandomVal()>1){

17 SA_Ex=new String("Hello world");

18 }

19 return SA_Ex;

20 }

21 }

1.SA_Ex 傳入 rule11

之遞迴方法。

2.找尋到符合文法之敘述句,

並標記之(line 17)。

3.將此敘述積分加上 weight 值。

4.根據文法分析判斷 SA_Ex 物件 並不是由其他元件所指派,所以根 據 rule 會另外對這敘述句加 weight 值的積分。

圖 37 案例二(NullPointerException)使用 rule 11(追蹤設定 criterion 的物件 傳遞生成敘述)分析步驟之二

z 案例(NullPointerException)使用rule 11 (追蹤criterion的物件傳遞關

(19)

係),weight為 4,分析之後的結果(如圖 38):透過rule 11 分析,將會標 記 3 行敘述句:TestNullPointer的line 11、MidTrans_B的line 13 以及 ObjCreate的line 17。這些敘述句都會被加上weight的積分,而ObjCreate 的 line 17 因為符合"物件為自己生成,並非從其他物件指派"的情況。所以 會額外再給予加分。

1 package MidTransObj;

2 public class AlwaysTrue {

3 public boolean getT(){

4 return true;

5 } 6

7 8 9 }

Component:create object 1 package ObjectCreat_A;

2 import randomValue.RandomC;

3

4 public class ObjCreate { 5

6 private String SA_Ex;

7 public ObjCreate() {

8 } 9 10 11 12 13

14 public String GetString(){

15 RandomC tempC=new RandomC();

16 if(tempC.GetRandomVal()>1){

17 SA_Ex=new String("Hello world");

18 }

19 return SA_Ex;

20 } 21 }

Component:epsilon value 1

2 3 4 5 6 7 8 9

Component:PI Value 1

2 3 4 5 6 7 8

Component:random value 1 package randomValue;

2 public class RandomC { 3 public RandomC() { 4 }

5 public double GetRandomVal(){

6 double temp=(Math.random());

7 return temp;

8 } 9}

Component score:13

Component score:2

Total score:26

Component score:11

Line 11 marked

Line 13 marked

Line 17 marked

Component :Main program

1

2 import MidTransObj.publicB;

3

4 public class TestNullPointer {

5 public static void main(String[] args) { 6

7 publicB S_from_MidTransObj= new publicB();

8 9 10 11 String

String_to_Use=S_from_MidTransObj.get_String();

12

String allString=String_from_PI+String_to_Use.substring(i);

//throw the null pointer exception 13 System.out.println(allString);

14 } 15 }

Component: middle transport 1 package MidTransObj;

2

3 import ObjectCreat_A.ObjCreate;

4 public class MidTrans_B { 5

6 private String SB_Ex;

7 public MidTrans_B() {

8 }

9 public String get_String(){

10 ObjCreate ObjA=new ObjCreate();

11 AlwaysTrue t =new AlwaysTrue();

12 if(t.getT())

13 SB_Ex=ObjA.GetString();

14 return SB_Ex;

15 } 16 }

圖 38 案例二 (NullPointerException)使用 rule 11(追蹤設定 criterion 的物 件傳遞生成敘述)分析之結果

z 本案例(NullPointerException)使用rule 12(找尋可能造成錯誤的控制敘

(20)

述),Weight為 10,所進行之分析(如圖 39、圖 40)。Rule 12 主要用來評 估可能造成錯誤的控制敘述,例如程式在發生NullPointerException原因可 能在於某個物件在被傳遞或是本身生成物件之時候,因為控制敘述錯誤,導 致這些這個物件被指派或是本身生成的敘述沒有被正常執行(該執行而未被 執行)。由上一個rule標記的敘述則就是代表的criterion物件生成以及被指 派的敘述句,而本rule在找尋這些被標記的敘述句,有沒有被控制流程所控 制。

Component :main program 1

2 import MidTransObj.publicB;

3

4 public class TestNullPointer {

5 public static void main(String[] args) { 6

7 publicB S_from_MidTransObj= new publicB();

8 9 10 11 String

String_to_Use=S_from_MidTransObj.get_String();

12

String allString=String_from_PI+String_to_Use.substring(i);

//throw the null pointer exception 13 System.out.println(allString);

14 } 15 }

Component: middle transport 1 package MidTransObj;

2

3 import ObjectCreat_A.ObjCreate;

4 public class MidTrans_B { 5

6 private String SB_Ex;

7 public MidTrans_B() {

8 }

9 public String get_String(){

10 ObjCreate ObjA=new ObjCreate();

11 AlwaysTrue t =new AlwaysTrue();

12 if(t.getT())

13 SB_Ex=ObjA.GetString();

14 return SB_Ex;

15 } 16 }

1 package MidTransObj;

2 public class AlwaysTrue {

3 public boolean getT(){

4 return true;

5 } 6

7 8 9 }

在 Component :main program 並無控制流程 的敘述影響被標記敘述的執行。

Component score:11+10=21

在 Component: middle transport 當中,被標記 的敘述句 line 13 行被一個 if 敘述句所控制(雖 然此控制敘述並無設計錯誤),將此敘述句的積分 加上 weight 值。

圖 39 案例二(NullPointerException)使用 rule 12(找尋可能造成錯誤的控制敘 述)分析之結果(1)

(21)

Component:create object 1 package ObjectCreat_A;

2 import randomValue.RandomC;

3

4 public class ObjCreate { 5

6 private String SA_Ex;

7 public ObjCreate() { 8 }

9 10 11 12 13

14 public String GetString(){

15 RandomC tempC=new RandomC();

16 if(tempC.GetRandomVal()>1){

17 SA_Ex=new String("Hello world");

18 }

19 return SA_Ex;

20 } }

Component:random value 1 package randomValue;

2 public class RandomC { 3 public RandomC() { 4 }

5 public double GetRandomVal(){

6 double temp=(Math.random());

7 return temp;

8 } 9}

Component score:13+10=23

Component score:2

在 Component :random value 並 無被標記敘述。

在 Component: create object 當中,被標記的敘 述句 line 17 行被一個 if 敘述句所控制,將此敘 述句的積分加上 weight 值。

圖 40 案例二(NullPointerException)使用 rule 12(找尋可能造成錯誤的控制敘 述)分析之結果(2)

(22)

z 本案例(NullPointerException)使用rule 12( 評估可能造成錯誤的控制敘 述),Weight為 10 所得出之最後結果(如圖 41):

Component :Main program 1

2 import MidTransObj.publicB;

Component: middle transport 1 package MidTransObj;

2

3 import ObjectCreat_A.ObjCreate;

圖 41 案例二(NullPointerException)使用 rule 12( 評估可能造成錯誤的控制 敘述)之結果

3

4 public class TestNullPointer {

5 public static void main(String[] args) { 6

7 publicB S_from_MidTransObj= new publicB();

8 9

10 11 String

String_to_Use=S_from_MidTransObj.get_String();

12

String allString=String_from_PI+String_to_Use.substring(i);

//throw the null pointer exception 13 System.out.println(allString);

14 } 15 }

4 public class MidTrans_B { 5

6 private String SB_Ex;

7 public MidTrans_B() {

8 }

9 public String get_String(){

10 ObjCreate ObjA=new ObjCreate();

1 package MidTransObj;

2 public class AlwaysTrue {

3 public boolean getT(){

4 return true;

5 } 6

7 8 9 }

11 AlwaysTrue t =new AlwaysTrue();

12 if(t.getT())

13 SB_Ex=ObjA.GetString();

Component score:21 14 return SB_Ex;

15 } 16 }

Component:create object 1 package ObjectCreat_A;

2 import randomValue.RandomC;

Component:random value 1 package randomValue;

2 public class RandomC 3

4 public class ObjCreate

{ 3 public RandomC() {

5

6 private String SA_Ex;

{ 4 }

5 public double GetRandomVal() 7 public ObjCreate()

{ 6 double temp=(Math.random());

{ 8 }

9 10 11 12 13

14 public String GetString()

7 return temp;

8 }

9} Component score:2

{

15 RandomC tempC=new RandomC();

16 if(tempC.GetRandomVal()>1){

17 SA_Ex=new String("Hello world");

18 }

19 return SA_Ex;

Component score:23 20 }

}

Total score:46

(23)

z 本案例(NullPointerException)經過分析過後之系統元件架構圖,以及其積 分值(如圖 42):

經過分析之後 create object 元件的積分值最高,若使用者找到新的 create object 元件並且利用這個跟原本元件的替換。若新的 create object 元件有 修正 ObjCreate 對於傳送出去 String 物件生成之部份,則之後便避免掉此 系統再次發生 NullPointerException 的情況。

圖 42 案例二(NullPointerException)分析過後之系統元件架構圖,以及其積分

(24)

4.3 以案例說明物件型態造成之錯誤

z 案例三:ArrayStoreException

本 案 例 主 要 對 ArrayStoreException 做 探 討 。 當 一 個 軟 體 發 生 ArrayStoreException 而中斷執行,代表程式有一個物件試著存入型態(type)不 同的陣列。這種情況會造成程式產生 ArrayStoreException。

下面我們以一個商店(store)的系統舉例說明。本系統主要有 6 個元件(圖 43、程式碼如圖 44):store是一個商店,store外部有一個warehouse的元件提 供 給 store 存 放 商 品 的 陣 列 。 Store 跟 wholesaler 進 貨 (getProduct) , 而 wholesaler則跟兩家工廠factor_A跟factor_B設定購買的貨品(setObjFromA、

setObjFromB)以及得到貨品(getObjFromA、getObjFromB)。最後buyer會跟store 買(buy)貨物。

在此範例,store 會產生 ArrayStoreException,主要原因是 factor_B 在生 成物件之後,對物件的型態做了轉換(casting)。透過 wholesaler 傳送給 store 時,當此物件要存入 store 當中的商品陣列時就會產生 ArrayStoreException。

為了要分析此錯誤我們的概念是:

1. 造成軟體發生 ArrayStoreException 的原因在於一個物件試圖存入一個陣 列當中而此陣列卻與此物件型態不符。因此有可能造成錯誤的原因一個為物 件,而另一個為陣列。在此為了確保所有找出所有可能造成錯誤的敘述,所 以對於這陣列以及要存入陣列的物件都應該設定為 criterion 進行 program slicing。

2. 對於上述設定為 criterion 的變數,我們希望能找到其 criterion 所指定的 物件是否為在其他元件當中所生成後,透過傳遞的敘述將這些在其他元件生 成的物件設定給這些 criterion。若找出這些指令,比對這些指令是否有 casting 的語法,若有,我們推測有可能這些傳遞給 criterion 的物件在此 行敘述當中其型態被轉換,導致程式當中使用這些物件的型態與原先設計不

(25)

符,使軟體產生 ArrayStoreException。

根據上述兩點概念我們設計了針對ArrayStoreException的分析腳本(如圖 45)。首先在腳本當中第一步則是運作上述分析的第一點概念:對於陣列以及欲 存入陣列的物件設定為criterion並且進行program slicing的分析,之後將其結 果聯集起來成為一個新的slice。而這邊注意的是我們對兩個rule使用時weight 值設計不同,原因在於一般而言ArrayStoreException發生的原因多在於物件本 身型態設計錯誤,比較少會發生在陣列本身設計上的錯誤。因此在此其weight 值,對存入陣列的物件進行分析的weight值高於對陣列進行分析的weight值。第 二步驟則是追蹤criterion物件的生成以及傳遞這些物件的指令,並且將其標 記。透過標記這些指令,將紀錄下這些設定criterion物件來源的指令。第三步 驟將比對這些設定criterion的指令是否有對物件在傳遞時對其進行型態上得轉 換(casting),若這些被標記的指令存在型態上轉換的操作,有可能造成程式執 行時將物件與欲存入的陣列型態不符的原因,便在於此物件在這行指令當中型態 被轉換,導致後來在使用時,此物件型態與原先設計的型態不符。若有比對出設 定criterion物件的指令在傳遞物件的過程當中對於這些物件有進行型態上的轉 換,我們將其定為一種可能導致軟體發生ArrayStoreException的原因,並給於 高於前兩個步驟給予的weight值。

(26)

Component : store

1 import warehouse.StoreArray;

2 import wholesaler.TransProduct;

3 import buyer.buyer;

4 public class Store {

5 public static void main(String[] args) {

6 TransProduct tp =new TransProduct();

7 buyer b=new buyer();

8 buyer b1=new buyer();

9 int i=StoreArray.getArraySize()-1;

10 Object warehouse[] = StoreArray.getArray();

11 Object product=tp.getProduct();

12 while(i>=0){

13 warehouse [i]= product;

14 i--;

15 }

16 while(true){

17 i=(int)(Math.random()*warehouse.length);

18 if(warehouse [i]!=null){

19 b.buy(warehouse [i]);

20 warehouse [i]=null;

21 }

22 }

23 } 24 }

Component : warehouse 1 package warehouse;

2 public class StoreArray {

3 static Object stringArray[]=new String[100];

4 public static Object[] getArray(){

5 return stringArray;

6 }

7 public static int getArraySize(){

8 return stringArray.length;

9 } 7 }

Component : buyer 1 package buyer;

2 public class buyer {

3 public void buy(Object o){

4 System.out.println("someone bought "+o);

5 } 6 }

Component :wholesaler 1 package wholesaler;

2 import factor_A.material_A;

3 import factor_B.material_B;

4 public class TransProduct {

5 material_B productB=new material_B();

6 material_A productA=new material_A();

7 public Object getProduct(){

8 Object transObj;

9 Double i=new Double((Math.random()*10));

10 if(i.intValue()<5){

11 productB.setObjFromB(i);

12 transObj=productA.getObjFromA();

13 }

14 else{

15 productB.setObjFromB(i);

16 transObj=productB.getObjFromB();

17 }

18 return transObj;

19 } 20 }

Component : factor_A 1 package factor_A;

2 public class material_A { 3 private String product_A;

4 public Object getObjFromA(){

5 return product_A;

6 }

7 public void setObjFromA(Object s){

8 product_A=new String(s.toString());

9 } 10 }

Component : factor_B 1 package factor_B;

2 public class material_B { 3 private Object product_B;

4 public Object getObjFromB(){

5 Object s=(Double)product_B;

6 return s;

7 }

8 public void setObjFromB(Object s){

9 product_B=s;

10 } 11}

圖 44 案例三(ArrayStoreeException) 系統程式碼

(27)

z 此案例使用軟體錯誤診斷分析之過程:

Rule Processing Engine 將 exception message 分析出軟體錯誤型態為 ArrayStoreException,其會先去尋找系統當中處理 ArrayStoreException 的 rule scripe。並且根據此 rule script 所設定之步驟呼叫 rule 評估整個 系統。

由Class loader所捕捉到的Exception Message

java.lang.ArrayStoreException Rule Engine

at Store.main(Store.java:13)

Exception in thread "main" 選擇 rule

script

根據 exception message 的資訊所使用 StoreArrayException 的 rule script

第一步:將產生錯誤的敘述句的right hand side的變數設定為criterion進行program slicing產生 slice;並且將產生錯誤的敘述句的left hand side所指定的陣列作為criterion進行program slicing產生slice。將上述兩個slice聯集在一起產生新的slice。

(使用rule 6(設定指派(assign)錯誤的變數為criterion),將可以設定right hand side當中的 變數為criterion,產生slice,此規則的weight值設定為2,代表slice當中所找出來的敘述,每 一個將會得到2點的積分值。而使用rule 7(設定被指派(assign)錯誤的變數為criterion)將會設 定 敘述句當中 的 left hand side的變數 ,在此為欲 被存取的陣 列為 criterion進行 program slicing,設定weight值為1代表在此slice當中每一個敘述將會得到1點的積分。最後將兩個slice 進行聯集產生新的slice)

第二步:透過第一步驟所設定的criterion,對產生的slice進行分析。尋找造成錯誤的變數criterion 所指向的物件是否來自其他元件的生成,並且透過某些指令將其傳遞給criterion,我們標記這 些傳遞以及生成的指令。

(使用Rule 11將會標記這些傳遞或是生成物件給criterion的敘述,在此設定Weight為2) 第三步:對於上述所標記的敘述句,尋找是否有進行型態轉換的敘述句(casting)。若有符合則給予積分

值。

(

使用 rule 13(標記轉換物件型態的敘述句)將會標記這些轉換物件型態的敘述句,設定 weight 值為 15。最後將此 slice 以及軟體內部元件評估的積分值回傳出 Rule Engine 作為最後評估結果。

)

圖 45 案例三,Rule Engine 根據錯誤類別(ArrayStoreException)選取對應分析 的運作腳本

(28)

z 本案例(ArrayStoreException)使用使用 rule 6(設定指派(assign)錯誤的變 數為 criterion),weight 為 2 進行之分析:

Component : store

1 import warehouse.StoreArray;

2 import wholesaler.TransProduct;

3 import buyer.buyer;

4 public class Store {

5 public static void main(String[] args) {

6 TransProduct tp =new TransProduct();

7 buyer b=new buyer();

8 buyer b1=new buyer();

9 int i=StoreArray.getArraySize()-1;

10 Object warehouse[] = StoreArray.getArray();

11 Object product=tp.getProduct();

12 while(i>=0){

13 warehouse [i]= product;

14 i--;

15 }

16 while(true){

17 i=(int)(Math.random()*warehouse.length);

18 if(warehouse [i]!=null){

19 b.buy(warehouse [i]);

20 warehouse [i]=null;

21 }

22 }

23 } 24 }

將會設定當中的第 13 行的 right hand side 的 變 數 product 作 為 criterion , 進 行 program slicing 分析。

圖 46 案例三(ArrayStoreException)使用 rule 6(設定指派(assign)錯誤的變數 為 criterion)進行分析

(rule 7 分析過程與 rule 6 相同,只是選取的 criterion 不同)

(29)

z 本案例(ArrayStoreException)使用使用rule 6(設定指派(assign)錯誤的變 數為criterion進行program slicing分析)-在此例為行號 13 的變數product 為criterion、weight為 2)分析之結果以及其積分(每個被找出來的敘述句以 及變數宣告將會得到 2 分)(如圖 47):

Component : store

1 import warehouse.StoreArray;

2 import wholesaler.TransProduct;

3 import buyer.buyer;

4 public class Store {

5 public static void main(String[] args) {

6 TransProduct tp =new TransProduct();

7 8

9 int i=StoreArray.getArraySize()-1;

10

11 Object product=tp.getProduct();

12 while(i>=0){

13 warehouse [i]= product;

14 i--;

15 }

16 17 18 19 20 21 22 23 24 }

Component : warehouse 1 package warehouse;

2 public class StoreArray {

3 static Object stringArray[]=new String[100];

4 5 6

7 public static int getArraySize(){

8 return stringArray.length;

9 } 10 }

Component : buyer 1

2 3 4 5 6

Component :wholesaler 1 package wholesaler;

2 import factor_A.material_A;

3 import factor_B.material_B;

4 public class TransProduct {

5 material_B productB=new material_B();

6 material_A productA=new material_A();

7 public Object getProduct(){

8 Object transObj;

9 Double i=new Double((Math.random()*10));

10 if(i.intValue()<5){

11

12 transObj=productA.getObjFromA();

13 }

14 else{

15

16 transObj=productB.getObjFromB();

17 }

18 return transObj;

19 } 20 }

Component : factor_A 1 package factor_A;

2 public class material_A { 3 private String product_A;

4 public Object getObjFromA(){

5 return product_A;

6 } 7 8 9 10 }

Component : factor_B 1 package factor_B;

2 public class material_B { 3 private Object product_B;

4 public Object getObjFromB(){

5 Object s=(Double)product_B;

6 return s;

7 } 8 9 10 11}

Component score:4

Component score:16

Component score:4

Component score:6

圖 47 案例三(ArrayStoreException)使用 rule 6(設定指派(assign)錯誤的變數 為 criterion 進行 program slicing 分析)所產生之結果

(30)

z 本案例(ArrayStoreException)使用使用rule 7(設定被指派(assign)錯誤的 變數為criterion進行program slicing,weight為 1)進行分析。透過設定被 指派的變數作為criterion(在此為陣列warehouse)進行program slicing,

將會產生slice。所產生之結果以及元件的積分值如圖 48 :

Component : store

1 import warehouse.StoreArray;

2 import wholesaler.TransProduct;

3 import buyer.buyer;

4 public class Store {

5 public static void main(String[] args) { 6

7 8

9 int i=StoreArray.getArraySize()-1;

10 Object warehouse[] = StoreArray.getArray();

11

12 while(i>=0){

13 warehouse [i]= product;

14 i--;

15 }

16 17 18 19 20 21 22 23 24 }

Component : warehouse 1 package warehouse;

2 public class StoreArray {

3 static Object stringArray[]=new String[100];

4 public static Object[] getArray(){

5 return stringArray;

6 }

7 public static int getArraySize(){

8 return stringArray.length;

9 } 7 }

Component : buyer 1

2 3 4 5 6

Component :wholesaler 1

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Component : factor_A 1

2 3 4 5 6 7 8 9 10

Component : factor_B 1

2 3 4 5 6 7 8 9 10 11

Component score:3

圖 48 案例三(ArrayStoreException)使用 rule 7(設定被指派(assign)錯誤的變 數為 criterion 進行 program slicing 分析)所產生之結果

(31)

z Rule Processing Engine會將上述兩個rule所產生出來的資訊(如圖 49)做 集合運算中的聯集(標粗體的敘述為交集共有部份)。例如在component:

store 第 12 行 的 while 控 制 迴 圈 跟 控 制 變 數 i , 以 及 會 影 響 變 數 i 的 component:warehouse當中作為存放商品倉庫陣列的長度以及陣列的宣告這 兩個部份。在此交集之後,敘述句的積分值若有交集會彼此相加產生新的元 件積分值。

Component : warehouse 1 package warehouse;

2 public class StoreArray {

3 static Object stringArray[]=new String[100];

4 public static Object[] getArray(){

5 return stringArray;

6 }

7 public static int getArraySize(){

8 return stringArray.length;

9 } 7 }

Component : buyer 1

2 3 4 5 6

Component :wholesaler 1 package wholesaler;

2 import factor_A.material_A;

3 import factor_B.material_B;

4 public class TransProduct {

5 material_B productB=new material_B();

6 material_A productA=new material_A();

7 public Object getProduct(){

8 Object transObj;

9 Double i=new Double((Math.random()*10));

10 if(i.intValue()<5){

11

12 transObj=productA.getObjFromA();

13 }

14 else{

15

16 transObj=productB.getObjFromB();

17 }

18 return transObj;

19 } 20 }

Component : factor_A 1 package factor_A;

2 public class material_A { 3 private String product_A;

4 public Object getObjFromA(){

5 return product_A;

6 } 7 8 9 10 }

Component : factor_B 1 package factor_B;

2 public class material_B { 3 private Object product_B;

4 public Object getObjFromB(){

5 Object s=(Double)product_B;

6 return s;

7 } 8 9 10 11}

Component score:4+3

Component score:16

Component score:4

Component score:6

Component : store

1 import warehouse.StoreArray;

2 import wholesaler.TransProduct;

3 import buyer.buyer;

4 public class Store {

5 public static void main(String[] args) {

6 TransProduct tp =new TransProduct();

7 8

9 int i=StoreArray.getArraySize()-1;

10 Object warehouse[] = StoreArray.getArray();

11 Object product=tp.getProduct();

12 while(i>=0){

13 warehouse [i]= product;

14 i--;

15 }

16 17 18 19 20 21 22 23 24 }

圖 49 聯集圖 47以及圖 48兩個slice所產生之新slice

(32)

z 本案例(ArrayStoreException)使用rule 11 (追蹤設定criterion的物件傳 遞生成敘述),weight為 2 所進行之分析。本案例當中有兩個criterion,位 於component :store第 13 行的變數warehouse以及變數product。這兩個變 數都為criterion,根據這兩個變數所將會標記出如圖 50的的敘述句,對於 變數x進行分析的說明如下:

1. 對於陣列變數 x 追蹤設定它的物件將會找到 component : store 當中的 第 10 行的"Object warehouse[] = StoreArray.getArray();",此行 敘述設定了變數 warehouse,因此標記此行。由於其設定變數 warehouse 的形式是一個物件呼叫方法的回傳物件,所以在此設定此物件方法 (StoreArray.getArray())的回傳物件為下一個要追蹤的物件。

2. 在 component :warehouse 當中追蹤 getArray()方法的回傳物件,第 5 行 的 變 數 stringArray 。 並 且 找 到 第 三 行 的 "static Object stringArray[]=new String[100];",此行為此變數的生成敘述,根據 規則除了標記此行之外還會在給予額外積分值。

以上是對變數 x 的物件傳遞進行追蹤的步驟以及標記的指令。下面則是對變 數 product 進行追蹤的步驟:

1. 對於變數product我們將會找到在圖 50裡component : store當中的第 11 行" Object product=tp.getProduct();"此行設定product的設 定,並且且將此物件的呼叫方法(tp.getProduct())的回傳物件作為下 一個要追蹤的物件。

2. 追 蹤 component : wholesaler 當 中 getProduct() 方 法 的 回 傳 物 件 transObj,將會得到在此圖 50 component : wholesaler當中的第 12 行 : "transObj=productA.getObjFromA();" 以 及 第 16 行 : " transObj=productB.getObjFromB();" 此 兩 行 會 設 定 欲 追 蹤 的 物 件 transObj。

3. 在圖 50對於component : factor_A當中的getObjFromA()當中函式的回

(33)

傳物件product_A會被設定為預追蹤的物件。然而在這些slice資訊當中 並沒有找到設定component : factor_A當中的getObjFromA()回傳物件 product_A的指令,所以並沒有標記任何指令。

4. 在圖 50對於component : factor_B當中函式getObjFromB()當中函式的 回傳物件s,則會追蹤到第 5 行"Object s=(Double)product_B;"設定 回傳物件s的值,並且標記之。而物件product_B在往上搜尋並沒有找尋 到設定此物件的敘述,因此此rule到此分析結束。

被 標 記 後 的 敘 述 句 將 會 得 到 weight 為 2 的 積 分 , 而 由 於 圖 50 當 中 的 component :warehouse 被 標 記 的 " static Object stringArray[]=new String[100];"這行敘述,代表這個設定criterion的物件並非從其他元件 取得,而是自己元件內所生成,因此根據規則會再加予weight為 2 的積分。

z 本案例(ArrayStoreException)最後將會使用rule 13(標記轉換物件型態的 敘述句),weight為 15。這個規則將會對設定criterion物件的敘述句,判斷 是否有部份敘述對物件進行了型態的轉換(type casting)。若發現類似敘 述,便給予較高的積分值(如圖 51)。

(34)

Component : warehouse 1 package warehouse;

2 public class StoreArray {

3 static Object stringArray[]=new String[100];

4 public static Object[] getArray(){

5 return stringArray;

6 }

7 public static int getArraySize(){

8 return stringArray.length;

9 } 7 }

Component : store

1 import warehouse.StoreArray;

2 import wholesaler.TransProduct;

3 import buyer.buyer;

4 public class Store {

5 public static void main(String[] args) {

6 TransProduct tp =new TransProduct();

7 8

9 int i=StoreArray.getArraySize()-1;

10 Object warehouse[] = StoreArray.getArray();

11 Object product=tp.getProduct();

12 while(i>=0){

13 warehouse [i]= product;

14 i--;

15 }

16 17 18 19 20 21 22 23 24 }

Component : buyer 1

2 3 4 5 6

Component :wholesaler 1 package wholesaler;

2 import factor_A.material_A;

3 import factor_B.material_B;

4 public class TransProduct {

5 material_B productB=new material_B();

6 material_A productA=new material_A();

7 public Object getProduct(){

8 Object transObj;

9 Double i=new Double((Math.random()*10));

10 if(i.intValue()<5){

11

12 transObj=productA.getObjFromA();

13 }

14 else{

15

16 transObj=productB.getObjFromB();

17 }

18 return transObj;

19 } 20 }

Component : factor_A 1 package factor_A;

2 public class material_A { 3 private String product_A;

4 public Object getObjFromA(){

5 return product_A;

6 } 7 8 9 10 }

Component : factor_B 1 package factor_B;

2 public class material_B { 3 private Object product_B;

4 public Object getObjFromB(){

5 Object s=(Double)product_B;

6 return s;

7 } 8 9 10 11}

Component score:7+2+2

Component score:16+2+2

Component score:4

Component score:6+2

圖 50 案例三(ArrayStoreException)使用 Rule 11(標記設定 criterion 的物件 傳遞生成的敘述)所產生之 slice 以及元件積分值

數據

圖 23 案例一(ArrayIndexOutOfBoundsException)元件架構圖
圖 24 案例一,Rule Engine 根據錯誤類別(ArrayIndexOutOfBoundsException) 選取對應的腳本運作
圖 28 Rule Processing Engine聯集以及圖 26以及圖 27所產生之slice
圖 30 案例二 (NullPointerException)之元件架構圖
+7

參考文獻

相關文件

在這次的實作遊戲中,我們必須要先對所使用到的硬體 和軟體有其基本的認識,這樣我們才能充分利用我們所擁有 的條件,進一步達成目標。首先 DE2-70 繼承了 Altera 一系 列的開發軟體,如

 NULL 不指向任何地方,故不會有值,所 以對 NULL

當天的朗誦分享會分為三個部分:第一部分是殷巧兒女士、馮祿德先 生,以及招祥麒博士的短談,題目為「朗誦對文學作品的體悟與再創造」

(approximation)依次的進行分解,因此能夠將一個原始輸入訊號分 解成許多較低解析(lower resolution)的成分,這個過程如 Figure 3.4.1 所示,在小波轉換中此過程被稱為

微陣列玻片資料庫 (The Microarray Database,以下簡稱 TMD) 為本研究嘗 試建置的一套提供存取、分析微陣列玻片 (Microarray)

4.1 多因子變異數分析 多因子變異數分析 多因子變異數分析 多因子變異數分析與線性迴歸 與線性迴歸 與線性迴歸 與線性迴歸 4.1.1 統計軟體 統計軟體 統計軟體 統計軟體 SPSS 簡介 簡介

在軟體的使用方面,使用 Simulink 來進行。Simulink 是一種分析與模擬動態

儀器附屬分析 FL Solutions 軟體進行 3-D 圖譜之繪製,爾後將其數據 輸出轉成 Excel.csv 檔,原本 Excel.csv 矩陣型之數據,經轉檔後變為 直列型式數據並匯入 Surfer