本發(fā)明涉及一種軟件可靠性技術(shù)。具體地說,主要實(shí)現(xiàn)對軟件運(yùn)行結(jié)果進(jìn)行反向演繹推理,尋找產(chǎn)生這種結(jié)果的原因及其傳播路徑。進(jìn)一步講,本發(fā)明主要針對賦值程序,建立演繹其最弱前置條件的模型及設(shè)計相應(yīng)的實(shí)現(xiàn)算法。
背景技術(shù):
在程序的測試過程中,測試者常常遇到這樣一種情況:程序沒有任何語義和語法錯誤,但程序運(yùn)行結(jié)果卻不正確。將最弱前置條件推理技術(shù)應(yīng)用于程序分析,則程序中潛在的bug(bug導(dǎo)致了錯誤或意想不到的結(jié)果)及其演繹傳播路徑將得到推斷。對于一定程序,演繹給定后置條件的程序的最弱前置條件過程就是構(gòu)建軟件故障樹的失效路徑的過程。
最弱前置條件直接建立了問題到原因的推理機(jī)制,因而,它是軟件可靠性研究中的故障分析和定位探索的直接動因。然而,程序受各種復(fù)雜因素的影響(比如:多變量、多狀態(tài)、多條件約束、多結(jié)構(gòu)形式、存儲手段、分支判斷、循環(huán)處理等),要通過最弱前置條件來實(shí)現(xiàn)對程序的反向推理實(shí)際是非常困難的。存在許多難以解決或需改進(jìn)完善的模型(實(shí)現(xiàn)技術(shù))。
(1)程序正確性證明中對選擇結(jié)構(gòu)各分支的最弱前置條件進(jìn)行合取操作在可靠性研究中并不合適。其理由如下:
<1>將兩個獨(dú)立的最弱前置條件蘊(yùn)含合并成一個最終簡化的結(jié)果,則有可能將最弱前置條件所表示的條件強(qiáng)化。這對精確搜索路徑中潛在的bug是非常不利的,因為它有可能遺漏真正的bug;
<2>在大多數(shù)情況下,對于具有只有兩條分支的選擇結(jié)構(gòu),它們的執(zhí)行條件是互斥的。蘊(yùn)含合并互斥條件下目標(biāo)代碼的最弱前置條件通常是無意義的。
(2)作為反向推理技術(shù),演繹程序的最弱前置條件可能會遇到許多未知的約束條件。在大多數(shù)情況下,最弱前置條件只能由推理規(guī)則確定,其推理的自動化程度受到空前挑戰(zhàn)。對于while循環(huán)結(jié)構(gòu),計算其最弱前置條件比計算順序語句的最弱前置條件更加困難,因為while循環(huán)結(jié)構(gòu)的迭代次數(shù)并不總是能夠提前確定。在while循環(huán)結(jié)構(gòu)的公理性語義中,一個關(guān)鍵的步驟是找到一個循環(huán)不變式斷言,而循環(huán)不變式對于尋找最弱前置條件則是至關(guān)重要的。盡管有一些尋找不變式的策略,然而,至今沒有一個統(tǒng)一規(guī)律來尋找while循環(huán)結(jié)構(gòu)的循環(huán)不變式。
(3)計算最弱前置條件涉及適當(dāng)?shù)姆栍嬎?,這將大大增加算法的復(fù)雜性。目前,可用的符號計算相對簡單。然而,由于算法復(fù)雜和表達(dá)式冗長,解決復(fù)雜的數(shù)學(xué)問題將是一個挑戰(zhàn)。一般說來,解決多變量數(shù)學(xué)或邏輯方程需要設(shè)計相應(yīng)的算法。如果這些方程涉及數(shù)組、結(jié)構(gòu)體、循環(huán)及嵌套結(jié)構(gòu),則符號計算相關(guān)的算法的復(fù)雜度(時間和空間)將是巨大的。
(4)分析程序結(jié)構(gòu)和為演繹最弱前置條件而設(shè)計有效的存儲結(jié)構(gòu)需要恰當(dāng)?shù)募记?。演繹最弱前置條件的第一步在于建立模型來自動分析和識別程序。因此,通過運(yùn)用恰當(dāng)?shù)某绦蚓幾g技術(shù)和定義適當(dāng)?shù)哪K結(jié)構(gòu)以對程序進(jìn)行明確的描述(比如:識別關(guān)鍵字以劃分節(jié)點(diǎn))是非常必要的。另一方面,設(shè)計統(tǒng)一的表達(dá)方法和相應(yīng)的存儲結(jié)構(gòu)有助于實(shí)現(xiàn)以上目標(biāo)。在演繹最弱前置條件的過程中,結(jié)構(gòu)化模塊及其嵌套形式的存在將大大增加程序識別、表達(dá)和存儲的復(fù)雜性。
(5)對于實(shí)際的程序,演繹其最弱前置條件需要建立一套適應(yīng)典型結(jié)構(gòu)的通用實(shí)現(xiàn)方法,通用方法的核心涉及具體的路徑擴(kuò)展、存儲銜接及入口處理等模型。
技術(shù)實(shí)現(xiàn)要素:
本發(fā)明的目的在于提供一種最弱前置條件的演繹模型和實(shí)現(xiàn)算法,從不同角度不同程度解決現(xiàn)有技術(shù)(模型和實(shí)現(xiàn)方法)中存在的上述問題。為軟件可靠性分析中的故障樹建模奠定標(biāo)準(zhǔn)化及實(shí)用化基礎(chǔ)。
為了實(shí)現(xiàn)上述目的,本發(fā)明采用如下技術(shù)方案。
(1)改進(jìn)最弱前置條件的表述。對于一般的選擇結(jié)構(gòu),其兩種可能的執(zhí)行路徑都考慮為演繹最弱前置條件的合理路徑。以析取的方式來并行分析兩條最弱前置條件的傳播路徑。在演繹目標(biāo)代碼的最弱前置條件時,也同時演繹執(zhí)行條件的最弱前置條件。此分支思想也用于演繹while循環(huán)結(jié)構(gòu)的最弱前置條件。
(2)提出最弱前置條件的演繹模型:路徑擴(kuò)展模型、最內(nèi)層連接模型和條件跳越模型。這些模型為算法設(shè)計提供演繹依據(jù)。
(3)給出算法表述的統(tǒng)一定義。描述程序的節(jié)點(diǎn)概念并以元胞數(shù)組作為其存儲結(jié)構(gòu),其目的是有效地分析和識別程序的結(jié)構(gòu)。此外,為演繹最弱前置條件而定義類似的元胞數(shù)組存儲結(jié)構(gòu)。這些定義為設(shè)計演繹算法奠定統(tǒng)一的表述方式。
(4)以演繹模型為依據(jù),統(tǒng)一定義為表述手段,設(shè)計演繹算法:
<1>演繹第一節(jié)點(diǎn)的最弱前置條件;
<2>演繹其余節(jié)點(diǎn)的最弱前置條件;
<3>提取執(zhí)行條件及形成剩余代碼。
所述方案中的第(2)部分描述的模型細(xì)化如下:a.路徑擴(kuò)展表示演繹最弱前置條件的過程中,傳播路徑將在模塊位置開始擴(kuò)展;b.最內(nèi)層連接表示任何非第一個節(jié)點(diǎn)的最弱前置條件將連接在它上一個兄弟節(jié)點(diǎn)的最弱前置條件的最內(nèi)層終端之后;c.條件跳躍表示演繹執(zhí)行條件的最弱前置條件將“跳過”當(dāng)前條件對應(yīng)的目標(biāo)代碼,以當(dāng)前模塊的下一個兄弟節(jié)點(diǎn)為演繹入口。
所述方案的第(3)部分描述的定義細(xì)化如下:a.程序節(jié)點(diǎn)以程序語句或結(jié)構(gòu)的特殊標(biāo)志作為識別和劃分依據(jù)。b.程序節(jié)點(diǎn)用1×3cell形式的元胞數(shù)組來描述。每個元胞表示特定的含義(第一元胞為節(jié)點(diǎn)索引,第二元胞為節(jié)點(diǎn)類型,第三元胞為節(jié)點(diǎn)內(nèi)容)。根據(jù)語句類型,節(jié)點(diǎn)劃分為4種類型。如果節(jié)點(diǎn)內(nèi)容為模塊,則該位置將進(jìn)行1×3cell形式的嵌套定義。c.演繹最弱前置條件的存儲結(jié)構(gòu)仍用1×3cell形式的元胞數(shù)組來描述,每個元胞表示特定含義(第一元胞為最弱前置條件或1×3cell形式的嵌套元胞數(shù)組,第二元胞為賦值語句或節(jié)點(diǎn)類型,第三元胞為后置條件)。d.根據(jù)模塊的固有特征,采用堆棧思想來識別和提取程序中的模塊(包括嵌套子模塊)——以零值初始化判別變量;搜索時一旦識別到模塊的起始特征字符,則判別變量值增加1,一旦識別到模塊的結(jié)束特征字符,則判別變量減少1;只要判別變量的值再次變?yōu)榱?,則最外層模塊得到識別。繼續(xù)采用此法,識別和提取模塊中的任何子模塊。
進(jìn)一步地,所述方案中的第(4)部分描述的算法分析如下:
<1>演繹第一個節(jié)點(diǎn)的最弱前置條件算法被命名為:sft_wp_module。輸入?yún)?shù)為module和post_con,前者代表判斷分析的對象(或為普通節(jié)點(diǎn)——賦值語句,或為特殊節(jié)點(diǎn)——模塊,或為特殊節(jié)點(diǎn)的進(jìn)一步擴(kuò)展形式),后者代表后置條件。設(shè)計從判斷節(jié)點(diǎn)是否為賦值節(jié)點(diǎn)開始,首先定義一個空元胞結(jié)構(gòu)(命名為t_wp),用以存儲在當(dāng)前兄弟節(jié)點(diǎn)中第一次出現(xiàn)的模塊的最弱前置條件,這種設(shè)計讓所有出現(xiàn)在第一個模塊之后的兄弟節(jié)點(diǎn)的最弱前置條件能直接(間接)放置在該模塊的最弱前置條件的最內(nèi)層終端位置之后。執(zhí)行時,以輸入?yún)?shù)module的行數(shù)為邊界進(jìn)行循環(huán)判斷和演繹。如果t_wp非空,則表明演繹同一層節(jié)點(diǎn)的過程中,第一個模塊已經(jīng)出現(xiàn),后續(xù)節(jié)點(diǎn)的最弱前置條件直接或間接地放在第一個模塊的最內(nèi)層之后。演繹后得到的最弱前置條件結(jié)構(gòu)將被固定在模塊出現(xiàn)的索引位置。如果t_wp為空,則繼續(xù)判斷輸入?yún)?shù)module是否為普通節(jié)點(diǎn),如果是普通節(jié)點(diǎn),則直接演繹其最弱前置條件,并將演繹結(jié)果作為演繹下一個節(jié)點(diǎn)的后置條件,此外,被演繹的普通節(jié)點(diǎn)如果是當(dāng)前層的最后一個節(jié)點(diǎn)且得到的最弱前置條件不是“真”和“假”,那么在獲得的最弱前置條件后,算法設(shè)置一個1×3cell形式的空元胞數(shù)組,為存儲該節(jié)點(diǎn)的下一個叔父節(jié)點(diǎn)的最弱前置條件結(jié)構(gòu)做準(zhǔn)備。如果輸入?yún)?shù)module是模塊的擴(kuò)展形式,則以模塊的擴(kuò)展形式和獲得后置條件為輸入?yún)?shù),遞歸調(diào)用本算法——sft_wp_module。默認(rèn)判斷情況下,參數(shù)module為模塊,在存儲當(dāng)前模塊的索引位置后,以當(dāng)前模塊和獲得的后置條件為輸入?yún)?shù),遞歸調(diào)用本算法——sft_wp_module。
<2>演繹其余節(jié)點(diǎn)的最弱前置條件算法被命名為:sft_wp_extend。輸入?yún)?shù)為in_wp_cond和new_node,前者代表輸入的最弱前置條件結(jié)構(gòu)——新節(jié)點(diǎn)的后置條件,后者代表新節(jié)點(diǎn)——需要演繹的節(jié)點(diǎn)。算法首先判斷輸入的最弱前置條件結(jié)構(gòu)的第一個子元胞,如果該子元胞非空且非字符,則遞歸調(diào)用本算法——sft_wp_extend。如果輸入的最弱前置條件結(jié)構(gòu)的第一個子元胞為空,則表明算法已經(jīng)遞歸搜索到該最弱前置條件結(jié)構(gòu)的最內(nèi)層終端位置。在最內(nèi)層終端位置的倒數(shù)第二個位置獲得最弱前置條件。以獲得的最弱前置條件(新節(jié)點(diǎn)的后置條件)和新節(jié)點(diǎn)為參數(shù),調(diào)用第一個算法——sft_wp_module。獲得的新節(jié)點(diǎn)的最弱前置條件結(jié)構(gòu)被放置在搜索到的上一個節(jié)點(diǎn)的最內(nèi)層終端的空元胞數(shù)組中。
<3>提取執(zhí)行條件及形成剩余代碼算法被命名為:sft_wp_path。輸入?yún)?shù)為module,為倒序索引形式的程序節(jié)點(diǎn)或模塊的擴(kuò)展形式。算法以程序節(jié)點(diǎn)數(shù)(或模塊的擴(kuò)展支路數(shù))為邊界進(jìn)行循環(huán)搜索,以提取模塊的執(zhí)行條件、局部剩余代碼和全局剩余代碼。在任何一次循環(huán)過程中,首先判斷module對應(yīng)的子成員,如果該子成員為賦值語句,則結(jié)束本次循環(huán);如果該子成員是模塊的擴(kuò)展形式,則以擴(kuò)展形式的內(nèi)容為輸入?yún)?shù),遞歸調(diào)用本算法——sft_con_path;默認(rèn)情況下該子成員為模塊,在層索引值增加1之后,提取當(dāng)前模塊的執(zhí)行條件,得到執(zhí)行條件的局部剩余代碼,進(jìn)而形成全局剩余代碼——由所在層的局部剩余代碼開始,由內(nèi)到外依次排列各層的局部剩余代碼。如果當(dāng)前模塊非for循環(huán)結(jié)構(gòu),則對立執(zhí)行條件和相應(yīng)的全局剩余代碼分別通過復(fù)制的方式得到。為進(jìn)一步搜索當(dāng)前模塊的內(nèi)容,以當(dāng)前模塊內(nèi)容為輸入?yún)?shù),繼續(xù)調(diào)用本算法——sft_con_path。為保證后續(xù)搜索過程中的層索引、執(zhí)行條件和局部剩余代碼能夠完全匹配,模塊內(nèi)容搜索結(jié)束并返回到當(dāng)前層后,層索引值及時減少1。本算法中涉及的層索引和全局剩余代碼索引都為全局變量,局部存儲剩余代碼和全局剩余代碼的結(jié)構(gòu)都為全局元胞數(shù)組。
對于循環(huán)結(jié)構(gòu),本發(fā)明利用程序函數(shù)(涉及預(yù)先確定循環(huán)迭代次數(shù))來代替循環(huán)體。此外,本發(fā)明僅針對簡單線性賦值程序,以單獨(dú)不等式(等式)類型作為后置條件,程序中的執(zhí)行條件也僅考慮簡單條件(非復(fù)合條件)。程序?qū)ο蟀ㄙx值語句、if-else選擇結(jié)構(gòu)、循環(huán)結(jié)構(gòu)(while結(jié)構(gòu)和for結(jié)構(gòu))及其相應(yīng)的嵌套結(jié)構(gòu)。研究對象和算法設(shè)計用到的編程語言均為matlab語言。
與現(xiàn)有技術(shù)相比,本發(fā)明的有益效果在于:<1>對軟件系統(tǒng)的可靠性評價和維護(hù)策略、故障診斷和測試提供參考依據(jù);<2>為形成具有自主知識產(chǎn)權(quán)的軟件故障樹分析評估軟件提供技術(shù)基礎(chǔ);<3>為軟件故障樹研究和分析的模型化、標(biāo)準(zhǔn)化、實(shí)用化發(fā)展開辟方向。
附圖說明
圖1為最弱前置條件的路徑擴(kuò)展模型。
圖2為最弱前置條件的最內(nèi)層連接模型。
圖3為最弱前置條件的條件跳躍模型。
圖4為主算法框圖。
圖5為演繹第一節(jié)點(diǎn)的最弱前置條件算法。
圖6為搜索最弱前置條件結(jié)構(gòu)的最內(nèi)層終端位置及最內(nèi)層連接示意圖。
圖7為演繹其余節(jié)點(diǎn)的最弱前置條件算法。
圖8為提取執(zhí)行條件及形成剩余代碼算法。
具體實(shí)施方式
根據(jù)上面給出的發(fā)明方案和相應(yīng)的附圖說明,下面具體說明方案的細(xì)節(jié)。
(1)典型結(jié)構(gòu)的最弱前置條件及改進(jìn)表述方法
<1>賦值語句的最弱前置條件
賦值語句是程序中最基本最常用的語句。本發(fā)明考慮賦值語句的三種演繹情況:左側(cè)變量在后置條件中;左側(cè)變量不在后置條件中;空語句。演繹賦值語句的最弱前置條件表示為:
本質(zhì)上講,本發(fā)明方案的一切技術(shù)都是圍繞序列結(jié)構(gòu)的最弱前置條件建模和相應(yīng)的演繹算法設(shè)計而展開。
<2>選擇結(jié)構(gòu)的最弱前置條件
對于一個給定的選擇結(jié)構(gòu),反向演繹其最弱前置條件時,很難提前知道哪一條分支應(yīng)該被視為一個唯一的傳播路徑。單獨(dú)考慮最弱前置條件的每條演繹路徑以滿足所有可能的情況是軟件可靠性分析與程序正確性證明之間的一個顯著區(qū)別。因此,本發(fā)明以軟件可靠性為背景,定義選擇結(jié)構(gòu)的析取形式的最弱前置條件(標(biāo)識為:
定義1:對于如下典型形式的if-else-end選擇結(jié)構(gòu):
…ifps1;elses2;end…
其關(guān)于后置條件q的最弱前置條件的傳播路徑劃分為兩個獨(dú)立的形式:
分支條件是保證目標(biāo)代碼執(zhí)行的充分條件。一般說來,這樣的條件在程序中不是憑空產(chǎn)生的,它的產(chǎn)生必定有一定的原因,本發(fā)明中的推理技術(shù)也一同考慮如何演繹執(zhí)行條件的最弱前置條件。此外,如果選擇結(jié)構(gòu)是if-end形式的結(jié)構(gòu)(它的默認(rèn)else部分是空語句),其兩條獨(dú)立的最弱前置條件傳播路徑也加以嚴(yán)格區(qū)分。while循環(huán)結(jié)構(gòu)在一定條件下可以看成一種選擇結(jié)構(gòu)。對于while循環(huán)結(jié)構(gòu),演繹推理也采用上述類似的架構(gòu)。
<3>循環(huán)結(jié)構(gòu)
當(dāng)循環(huán)機(jī)構(gòu)中的循環(huán)體有多條賦值語句時,它們的變量的初始狀態(tài)和最終狀態(tài)之間的唯一映射關(guān)系與序列依賴關(guān)系是不兼容的。因此,本發(fā)明利用了條件同時賦值概念——將序列賦值語句轉(zhuǎn)化為同時賦值語句。比如:x=2x+y;y=x-2y;第二條語句的值依賴于第一條語句及變量x和y的初始值,假設(shè),x和y的初始值分別為x0和y0,則上述依賴語句可以轉(zhuǎn)化為同時賦值的函數(shù)關(guān)系:x=2x0+y0,y=2x0-y0。程序函數(shù)只反映了幾個獨(dú)立變量的初態(tài)和終態(tài)間的映射關(guān)系。在演繹最弱前置條件時,如有必要的,一些變量之間的依賴關(guān)系將在程序函數(shù)的基礎(chǔ)上進(jìn)行重建。
當(dāng)演繹while循環(huán)結(jié)構(gòu)的最弱前置條件時,有必要考慮條件不成立(循環(huán)體將不被執(zhí)行)時的情形。因此,結(jié)合上面的討論,while循環(huán)結(jié)構(gòu)的最弱前置條件在本發(fā)明中予以重新定義:
定義2:對于如下典型形式的while循環(huán)結(jié)構(gòu):
…whileps;end…
其關(guān)于后置條件q的最弱前置條件的傳播路徑劃分為兩個獨(dú)立的形式:
其中,
(2)演繹最弱前置條件的三個模型
<1>路徑擴(kuò)展
結(jié)構(gòu)化程序通常包括選擇結(jié)構(gòu)和/或循環(huán)結(jié)構(gòu)及其嵌套形式。在演繹最弱前置條件的過程中,最弱前置條件的傳播路徑將從這些結(jié)構(gòu)所在的位置進(jìn)行擴(kuò)展。傳播路徑從最初的一條擴(kuò)展為多條(圖1)。
在圖1中,黑色圓圈代表節(jié)點(diǎn)(任何賦值語句、選擇結(jié)構(gòu)、循環(huán)結(jié)構(gòu)及其嵌套形式可劃分為一個節(jié)點(diǎn)。選擇結(jié)構(gòu)、循環(huán)結(jié)構(gòu)及其嵌套形式也稱為特殊節(jié)點(diǎn)——模塊,而賦值語句則稱為普通節(jié)點(diǎn))?;疑珗A圈代表對應(yīng)的語句,最弱前置條件正是通過語句進(jìn)行演繹的。每條箭頭扮演兩個角色:其一,輸出當(dāng)前節(jié)點(diǎn)的最弱前置條件;其二,輸入下一節(jié)點(diǎn)的后置條件(比如:節(jié)點(diǎn)1和節(jié)點(diǎn)2之間的箭頭既表示節(jié)點(diǎn)1的最弱前置條件,又表示節(jié)點(diǎn)2的后置條件)。需要強(qiáng)調(diào)的是,相關(guān)的后置條件都單獨(dú)輸入到某個節(jié)點(diǎn),然后各自演繹相應(yīng)該節(jié)點(diǎn)的最弱的前置條件。例如,對于節(jié)點(diǎn)4,在執(zhí)行條件p的控制下,語句有2個輸入的后置條件(來自于節(jié)點(diǎn)3的兩個獨(dú)立的最弱前置條件)。在這兩個后置條件的作用下,該語句被演繹出2個獨(dú)立的最弱前置條件。
從節(jié)點(diǎn)1到節(jié)點(diǎn)6,一條最弱前置條件被擴(kuò)展成4條最弱前置條件。在最弱前置條件的演繹過程中,有兩個因素影響著最弱前置條件的擴(kuò)展度。一方面,當(dāng)前模塊嵌套其他模塊越多,則當(dāng)前模塊的最弱前置條件的路徑擴(kuò)展就越多。另一方面,在搜索路徑中,位于當(dāng)前節(jié)點(diǎn)后面的模塊越多,則當(dāng)前節(jié)點(diǎn)的最弱前置條件被擴(kuò)展的路徑就越多。
需要指明的是,最弱條件的路徑擴(kuò)展代表著反向演繹的各種可能情形。在這些擴(kuò)展的路徑中,盡管只存在唯一條正確的演繹路徑(事先并不知道),但通過各種可能情形的演繹,則最終滿足各種條件的唯一路徑會被篩選出來,而其它路徑一定會因為各種演繹矛盾而被摒棄。這樣的路徑擴(kuò)展策略為程序測試中的故障定位(識別)奠定了可操作的基礎(chǔ)。因而在軟件可靠性研究中具有重要的理論意義和實(shí)踐價值。
<2>最內(nèi)層連接
既然程序在本質(zhì)上可以看成一種序列結(jié)構(gòu),演繹程序的最弱前置條件一定涉及到存儲方式的設(shè)計,根據(jù)式②,本發(fā)明技術(shù)方案中的最內(nèi)層連接模型有三層含義:其一,對于任何兩個相鄰的普通節(jié)點(diǎn),后者的最弱前置條件結(jié)構(gòu)連接在前者的最弱前置條件結(jié)構(gòu)后面;其二,對于任何特定的節(jié)點(diǎn)(選擇性結(jié)構(gòu)或循環(huán)結(jié)構(gòu))的程序,其最弱前置條件直接(或間接)放置在通過遞歸搜索每層的第一個特殊子節(jié)點(diǎn)而得到的最內(nèi)層的最后一個賦值語句的最弱前置條件之后;其三,任何節(jié)點(diǎn),如果它在第一個特殊節(jié)點(diǎn)之后,前者的最弱前置條件(如果前者為特殊節(jié)點(diǎn),則其最弱前置條件由其第一層的最后一個子節(jié)點(diǎn)和輸入的后置條件演繹得到。而輸入的后置條件則是前者的上一個兄弟節(jié)點(diǎn)的最弱前置條件)將連接在上一個兄弟節(jié)點(diǎn)的最弱前置條件結(jié)構(gòu)的最內(nèi)層終端之后。在本發(fā)明中,這種建模特征被稱為最內(nèi)層連接。本發(fā)明之所以提出這樣一個建模特征是因為基于以下三個因素的考慮:其一,使用這種模型可以清楚地揭示任何節(jié)點(diǎn)的最弱前置條件是如何演繹的。其二,設(shè)計這樣的模型可以突出位于第一個特殊節(jié)點(diǎn)之后的節(jié)點(diǎn)的最弱前置條件的傳播路徑是如何被控制的,因此,最弱前置條件的路徑擴(kuò)展模型可以方便地加以表述。其三,演繹整個程序的最弱前置條件需要設(shè)計特殊的存儲結(jié)構(gòu)。最內(nèi)層連接模型能夠很好地匹配演繹最弱前置條件所需要的嵌套存儲結(jié)構(gòu)。圖2給出了一個簡單的最內(nèi)層連接模型。
在圖2中,黑色圓表示節(jié)點(diǎn),深灰色圓表示用于演繹最弱前置條件的語句。淺灰色圓表示演繹的最弱前置條件(本例中僅給出了四個)。指向語句(標(biāo)記為語句1、語句2等)的箭頭表示輸入的后置條件(即,上一個兄弟節(jié)點(diǎn)的最弱前置條件),離開語句的箭頭表示輸出語句的最弱前置條件。
當(dāng)后置條件(即:節(jié)點(diǎn)1的最弱前置條件——wp1)輸入到語句2,語句2的最弱前置條件被演繹出。對語句3和語句4依次進(jìn)行類似的操作,則語句4的最弱前置條件(標(biāo)為wp_stm4)也同樣被演繹出。演繹后得到的最弱前置條件wp_stm4作為語句5的后置條件,則語句5的最弱前置條件(標(biāo)為wp2)被演繹出(事實(shí)上,這個最弱前置條件是節(jié)點(diǎn)2的一條可能的最弱前置條件分支)。wp2被連在wp_stm4之后,而wp_stm4恰好是節(jié)點(diǎn)2的一條分支的最內(nèi)層的末尾代碼(語句4)的最弱前置條件。采用類似的操作,由wp2導(dǎo)出的語句6(即:節(jié)點(diǎn)3)的最弱的前置條件(標(biāo)為wp3)連接在wp2之后。
<3>條件跳越
每個執(zhí)行條件將保證它的目標(biāo)代碼(本發(fā)明中將執(zhí)行條件下運(yùn)行的代碼稱為目標(biāo)代碼)被執(zhí)行,但執(zhí)行條件本身仍然是一個謂詞,受相應(yīng)最弱前置條件約束。
演繹執(zhí)行條件的最弱前置條件的核心在于如何選擇合適的位置作為入口。在反向推理時,演繹目標(biāo)代碼的最弱前置條件可能涉及到執(zhí)行條件中的變量,但演繹執(zhí)行條件的最弱前置條件本身卻與目標(biāo)代碼無關(guān),故演繹執(zhí)行條件最弱的前置條件時,不能將執(zhí)行條件下的目標(biāo)代碼作為有效的演繹入口。反之,當(dāng)前模塊之后的兄弟節(jié)點(diǎn)的反向起始位置則是一個合理的演繹入口。因此,在后向推理過程中,演繹執(zhí)行條件的最弱前置條件必須“越過”它的目標(biāo)代碼。本發(fā)明把這種建模特性叫做條件跳越。不但如此,對于任何執(zhí)行條件,不管它在嵌套模塊中與否,演繹其最弱前置條件都要“飛越”其對應(yīng)的目標(biāo)代碼(注:演繹執(zhí)行條件的最弱前置條件的實(shí)質(zhì)是將執(zhí)行條件作為后置條件,反向演繹特定的代碼,從而得到執(zhí)行條件所對應(yīng)的最弱前置條件)。圖3給出一個例子來說明執(zhí)行條件如何“飛越”相應(yīng)的目標(biāo)代碼而到達(dá)演繹入口。
在圖3中,黑色圓表示節(jié)點(diǎn)(節(jié)點(diǎn)2是一個嵌套的結(jié)構(gòu),用三類大小不同的黑色圓來體現(xiàn))?;疑珗A表示語句。灰色虛線箭頭指示所有的執(zhí)行條件應(yīng)取其相應(yīng)的入口位置作為演繹的起始位置。作為節(jié)點(diǎn)2的一個分支執(zhí)行條件,p1“飛越”了它的所有目標(biāo)代碼(即:第二層中用中等大小的黑色圓表示的子節(jié)點(diǎn)),指向節(jié)點(diǎn)3(即:語句7)并將其作為演繹的入口位置。作為當(dāng)循環(huán)模塊的執(zhí)行條件,p2也“飛越”了它的目標(biāo)代碼(即:循環(huán)體——第三層中用黑色小圓表示的子節(jié)點(diǎn)),到達(dá)語句5并以其作為演繹的入口。類似的“飛越”操作用于其它執(zhí)行條件,即可獲得相應(yīng)的演繹入口位置。本發(fā)明稱從演繹的入口位置到程序結(jié)束之間的代碼為執(zhí)行條件的全局剩余代碼,稱從演繹入口位置到當(dāng)前層的結(jié)束位置之間的代碼為執(zhí)行條件的局部剩余代碼。
(3)演繹算法的描述基礎(chǔ)——幾個定義
<1>程序節(jié)點(diǎn)
提取程序節(jié)點(diǎn)是演繹最弱前置條件的第一步。由于常常有必要進(jìn)一步分析模塊的結(jié)構(gòu),因此提取程序的節(jié)點(diǎn)是一個執(zhí)行頻率較高的操作。所有發(fā)明活動都基于程序節(jié)點(diǎn)的識別、提取、分析和演繹。程序節(jié)點(diǎn)的定義如下。
定義3:在matlab程序中,以分號和關(guān)鍵詞(如:if、else、for、while、end等)作為識別標(biāo)志,任何一個賦值語句、選擇結(jié)構(gòu)、循環(huán)結(jié)構(gòu)及其嵌套結(jié)構(gòu)(如果存在的話)被定義為一個程序節(jié)點(diǎn)。
為了準(zhǔn)確地識別和提取程序節(jié)點(diǎn),程序中的所有分號和關(guān)鍵詞的位置應(yīng)該被識別和標(biāo)記。此外,識別后的關(guān)鍵詞的位置需做升序排序。為了完整清楚地描述定義的節(jié)點(diǎn),節(jié)點(diǎn)的幾個關(guān)鍵信息需進(jìn)一步得到細(xì)化。
<2>程序節(jié)點(diǎn)的存儲結(jié)構(gòu)
首先,設(shè)計節(jié)點(diǎn)的存儲結(jié)構(gòu)。任何節(jié)點(diǎn)都應(yīng)該包含三方面的信息:1)節(jié)點(diǎn)的索引;2)節(jié)點(diǎn)的類型(即:賦值語句、選擇性結(jié)構(gòu)或循環(huán)結(jié)構(gòu)等);3)節(jié)點(diǎn)的內(nèi)容。其次,根據(jù)不同的節(jié)點(diǎn)類型,對其相應(yīng)的關(guān)鍵字進(jìn)行記錄以形成節(jié)點(diǎn)的內(nèi)容:1)記錄起始字符及其位置;2)記錄最終字符及其位置。最后,如果節(jié)點(diǎn)是一個模塊,則它的內(nèi)容應(yīng)該通過一個嵌套存儲結(jié)構(gòu)來描述。根據(jù)上述分析,節(jié)點(diǎn)的存儲結(jié)構(gòu)被定義如下:
定義4:對于一個給定的matlab程序,其節(jié)點(diǎn)的基本存儲結(jié)構(gòu)定義為1×3cell形式的元胞數(shù)組。四種典型節(jié)點(diǎn)的存儲結(jié)構(gòu)設(shè)計如下:
1)賦值語句
{[索引號]}{'assign'}{賦值語句}
2)選擇結(jié)構(gòu)(if形式)
{[索引號]}{'if-select'}{2×3cell}
2×3cell結(jié)構(gòu)擴(kuò)展如下:
{'if'}{執(zhí)行條件}{n×3cell}
{'else'}{對立執(zhí)行條件}{n×3cell或空語句}
3)循環(huán)結(jié)構(gòu)(for循環(huán)形式)
{[索引號]}{'for-loop'}{1×3cell}
1×3cell結(jié)構(gòu)擴(kuò)展如下:
{'for'}{循環(huán)條件}{n×3cell}
4)循環(huán)結(jié)構(gòu)(while循環(huán)形式)
{[索引號]}{'while-loop'}{2×3cell}
2×3cell結(jié)構(gòu)擴(kuò)展如下:
{'while'}{執(zhí)行條件}{n×3cell}
{'while'}{對立執(zhí)行條件}{空語句}。
這里,{n×3cell}表示當(dāng)前元胞存儲空間將擴(kuò)展成n個并列的具有相同節(jié)點(diǎn)空間的存儲結(jié)構(gòu)(即:n個1×3cell結(jié)構(gòu),n表示子節(jié)點(diǎn)數(shù))。
如果當(dāng)前模塊嵌套多個模塊,則模塊的最外層結(jié)構(gòu)應(yīng)該首先被識別和提取。以“if”、“for”、“while”和“end”為標(biāo)志,本發(fā)明采用堆棧思想來識別模塊的最外層結(jié)構(gòu)。即:假設(shè)給定一個變量end_mark并對其賦初值0,一旦算法識別出新模塊的標(biāo)志(即:“if”、“for”或“while”),那么讓end_mark的值增加1。反之,一旦算法識別到關(guān)鍵詞“end”,則讓end_mark的值減少1。只要end_mark的值變?yōu)?,則模塊的最外層結(jié)構(gòu)得到識別和提取。重復(fù)運(yùn)用上述設(shè)計方法,當(dāng)前嵌套模塊的所有子模塊都將被識別和提取。
<3>演繹最弱前置條件的存儲結(jié)構(gòu)
在正式設(shè)計演繹算法之前,需要定義演繹最弱前置條件的存儲結(jié)構(gòu)。
定義5:對于一個給定的matlab程序,演繹最弱前置條件的存儲結(jié)構(gòu)定義為1×3cell形式的元胞數(shù)組。四種典型類型的演繹存儲結(jié)構(gòu)設(shè)計如下:
1)賦值結(jié)構(gòu)
{最弱前置條件}{賦值語句}{后置條件}
2)選擇結(jié)構(gòu)(if形式)
{2×3cell}{'if-select'}{后置條件}
2×3cell結(jié)構(gòu)擴(kuò)展如下:
{n×3cell}{對立執(zhí)行條件}{后置條件}
{n×3cell}{執(zhí)行條件}{后置條件}
3)循環(huán)結(jié)構(gòu)(for循環(huán)形式)
{1×3cell}{'for-loop'}{后置條件}
1×3cell結(jié)構(gòu)擴(kuò)展如下:
{n×3cell}{循環(huán)條件}{后置條件}
4)循環(huán)結(jié)構(gòu)(while循環(huán)形式)
{2×3cell}{'while-loop'}{后置條件}
2×3cell結(jié)構(gòu)擴(kuò)展如下:
{n×3cell}{對立循環(huán)條件}{后置條件}
{n×3cell}{循環(huán)條件}{后置條件}
這里,{2×3cell}表示當(dāng)前元胞存儲空間將擴(kuò)展為2個并列的具有相同空間的演繹結(jié)構(gòu)(2表示兩條獨(dú)立的傳播路徑)。{n×3cell}表示當(dāng)前元胞存儲空間將被擴(kuò)展為n個序列演繹結(jié)構(gòu),這些演繹結(jié)構(gòu)都是1×3cell形式的元胞數(shù)組。
根據(jù)上述定義,如果節(jié)點(diǎn)是一個模塊,演繹其最弱前置條件的存儲結(jié)構(gòu)直接(或間接)包含三方面的信息。例如,對于選擇結(jié)構(gòu),第一方面的信息為:{2×3cell}{'if-select'}{后置條件},該信息主要包含:后置條件,模塊的特性(即,'if-select')和傳播路徑信息(即,{2×3cell});第二方面信息為:{n×3cell}{對立執(zhí)行條件}{后置條件}和{n×3cell}{執(zhí)行條件}{后置條件},這些信息主要包含:后置條件,執(zhí)行條件(或?qū)α?zhí)行條件)和序列演繹結(jié)構(gòu)(即:{n×3cell});第三方面信息表示序列演繹結(jié)構(gòu),該演繹結(jié)構(gòu)由具體的程序確定(這里沒有表示出來)。用于演繹賦值語句的最弱前置條件的存儲結(jié)構(gòu)只包含一方面的信息。值得注意的是:在序列演繹結(jié)構(gòu)中(即:{n×3cell}),第n個1×3cell結(jié)構(gòu)是為存儲新節(jié)點(diǎn)的最弱前置條件而提前準(zhǔn)備的。
(4)三個演繹算法
本發(fā)明以簡單的線性matlab賦值程序為研究對象,建模并設(shè)計算法來演繹程序的最弱前置條件。matlab語言有著獨(dú)特的語法特征,因而很容易被辨識。此外,matlab軟件集成了一個重要的符號計算函數(shù)——maple。該函數(shù)在某種程度上能求解等式或不等式。需要強(qiáng)調(diào)的是本發(fā)明只考慮在一些簡單情況下(如:整數(shù)變量,單一執(zhí)行條件及后置條件為不等式)演繹程序的最弱前置條件。本發(fā)明不但關(guān)注選擇結(jié)構(gòu)和while循環(huán)結(jié)構(gòu)的執(zhí)行條件對演繹其目標(biāo)代碼的最弱前置條件的影響,而且考慮如何得到執(zhí)行條件的最弱前置條件及其傳播路徑。此外,本發(fā)明需要提前獲得循環(huán)結(jié)構(gòu)的程序函數(shù)來演繹其最弱前置條件。
總體上講,算法主要包括三個功能相關(guān)的部分。首先,以節(jié)點(diǎn)的定義為基礎(chǔ),第一部分利用遞歸調(diào)用方法及使用堆棧思想來獲得給定程序的節(jié)點(diǎn)。這部分包括兩個算法:第一,識別程序中的關(guān)鍵詞,第二,形成程序的節(jié)點(diǎn)。其次,以倒序形式的程序節(jié)點(diǎn)為研究對象,結(jié)合定義的最弱前置條件的存儲結(jié)構(gòu),第二部分主要利用遞歸調(diào)用方法和深度優(yōu)先搜索(depthfirstsearch,dfs)技術(shù)來演繹程序的最弱前置條件及其傳播路徑(不考慮執(zhí)行條件本身)。該部分設(shè)計兩個算法:第一,演繹程序的第一個節(jié)點(diǎn)的最弱前置條件(標(biāo)為wp);第二,演繹其余節(jié)點(diǎn)的最弱前置條件。最后,以獲得的節(jié)點(diǎn)為研究對象,第三部分同樣利用遞歸調(diào)用方法來獲取模塊的重要信息:執(zhí)行條件、演繹入口及剩余代碼。獲得模塊的重要信息后,本部分通過重用上述第二部分算法來演繹執(zhí)行條件的最弱前置條件及其演繹路徑。在完成相關(guān)算法的設(shè)計后,只需將獲得的最弱前置條件結(jié)構(gòu)中的執(zhí)行條件用其對應(yīng)的最弱前置條件代替即可完整地實(shí)現(xiàn)程序的最弱前置條件及其演繹路徑。圖4給出了上述主要算法的框圖。需要強(qiáng)調(diào)的是:本發(fā)明省略了第一部分(即:part1)算法的具體設(shè)計過程,而給出了用堆棧思想來提取模塊(即特殊節(jié)點(diǎn))的方法。這樣安排的主要原因在于突出后兩部分(即:part2和part3)的算法設(shè)計,從而與發(fā)明方案中的演繹模型相匹配。
<1>演繹第一個節(jié)點(diǎn)的最弱前置條件
根據(jù)定義4所述,可以得出一個重要結(jié)論:任何節(jié)點(diǎn)只要不是賦值語句(即:節(jié)點(diǎn)的第二個成員不是“assign”),則它將被擴(kuò)展。此外,所有節(jié)點(diǎn)可以劃分兩種類型,即。賦值節(jié)點(diǎn)和非賦值節(jié)點(diǎn)。因此,算法設(shè)計從這種劃分開始。圖5是演繹第一個節(jié)點(diǎn)的最弱前置條件的偽代碼。
該算法被命名為:sft_wp_module。輸入?yún)?shù)為module和post_con,前者代表判斷分析的對象(或為普通節(jié)點(diǎn)——賦值語句,或為特殊節(jié)點(diǎn)——模塊,或為特殊節(jié)點(diǎn)的進(jìn)一步擴(kuò)展形式),后者代表后置條件。算法首先設(shè)計一個空元胞結(jié)構(gòu)(命名為t_wp)來存儲在當(dāng)前兄弟節(jié)點(diǎn)中第一次出現(xiàn)的模塊的最弱前置條件,這種設(shè)計讓所有出現(xiàn)在第一個模塊之后的兄弟節(jié)點(diǎn)的最弱前置條件能直接(間接)放置在該模塊的最弱前置條件的最內(nèi)層終端位置之后。只要t_wp是空的(這意味著第一個模塊沒有出現(xiàn)),那么,賦值節(jié)點(diǎn)和那些第一個成員是“if”,“else”或“while”的擴(kuò)展結(jié)構(gòu)的最弱前置條件不需要存儲到t_wp中,但那些第二個成員必定為“if-select”、“while-loop”或“for-loop”的模塊(默認(rèn)情況下)必須被存儲,這樣存儲的目的是為連接當(dāng)前模塊的下一個兄弟節(jié)點(diǎn)的最弱前置條件做準(zhǔn)備。一旦t_wp非空(這意味著兄弟節(jié)點(diǎn)中首次出現(xiàn)的模塊的最弱前置條件結(jié)構(gòu)已經(jīng)存儲),則位于當(dāng)前模塊后的那些節(jié)點(diǎn)的最弱前置條件結(jié)構(gòu)將直接或間接連接在t_wp的最內(nèi)層的終端之后。
在圖5中,第7行~17行意味著當(dāng)前節(jié)點(diǎn)是一個純粹的賦值語句,其最弱前置條件的信息來自幾個關(guān)鍵行:(i)當(dāng)前節(jié)點(diǎn)的最弱前置條件在第11行生成(通過調(diào)用一個命名為sft_wp_assign的函數(shù),其主要功能是根據(jù)表達(dá)式①來演繹賦值語句的最弱前置條件。該函數(shù)包含兩個要點(diǎn):其一,在該函數(shù)中,作為符號計算工具,maple函數(shù)被用來求解決等式或不等式;其二,當(dāng)演繹的最弱前置條件是一個常量表達(dá)式時,則根據(jù)常量表達(dá)式的邏輯值給出最弱前置條件的結(jié)果為“真”或“假”);(ii)設(shè)置第12行的目的是獲取下一個兄弟節(jié)點(diǎn)的后置條件;(iii)如果當(dāng)前節(jié)點(diǎn)是賦值語句,且它是其父節(jié)點(diǎn)的最后一個子節(jié)點(diǎn),同時該節(jié)點(diǎn)的最弱前置條件不是“真”和“假”,那么第13行~到17行用來設(shè)計一個帶三個空元胞的存儲結(jié)構(gòu),從而存儲當(dāng)前節(jié)點(diǎn)的下一個叔父節(jié)點(diǎn)的演繹結(jié)果。這樣的設(shè)計也意味著如果當(dāng)前賦值語句不是它的父節(jié)點(diǎn)的最后一個子節(jié)點(diǎn)或者當(dāng)前賦值語句的最弱前置條件是“真”或“假”,則不必設(shè)計1×3cell形式的空元胞結(jié)構(gòu)。對于第一種情況(即:當(dāng)前賦值語句不是它的父節(jié)點(diǎn)的最后一個子節(jié)點(diǎn)),當(dāng)前賦值語句的最弱前置條件的將直接作為下一個兄弟節(jié)點(diǎn)的后置條件。至于第二種情況(即:當(dāng)前賦值語句的最弱前置條件為“真”或“假”),算法將自動終止演繹隨后節(jié)點(diǎn)的最弱前置條件。
第18行~第21行代碼意味著當(dāng)前節(jié)點(diǎn)僅為模塊的擴(kuò)展形式(例如,對于正常的選擇性結(jié)構(gòu),其擴(kuò)展形式為if部分和else部分),其最弱前置條件通過遞歸調(diào)用當(dāng)前算法本身(即:sft_wp_module)來實(shí)現(xiàn)。第22行~第32行代碼揭示了這樣的事實(shí):(i)當(dāng)前節(jié)點(diǎn)是一個模塊,其最弱前置條件是通過調(diào)用當(dāng)前算法本身來實(shí)現(xiàn)(第28行給出);(ii)當(dāng)前變量i專門賦給變量fix_var(通過設(shè)計第23行~第25行來實(shí)現(xiàn))來固定當(dāng)前模塊的最弱前置條件結(jié)構(gòu)的索引;(iii)當(dāng)前模塊的最弱前置條件結(jié)構(gòu)存儲在t_wp中(通過執(zhí)行第29行~31行來實(shí)現(xiàn)),其目的是為演繹下一個兄弟節(jié)點(diǎn)(命名為t_mod)的最弱前置條件做準(zhǔn)備。t_mod的最弱前置條件結(jié)構(gòu)將連接在t_wp的最內(nèi)層的終端位置之后。
第33行~第41行代碼暗示了這樣的信息:(i)存儲在t_mod中的當(dāng)前節(jié)點(diǎn)(通過執(zhí)行第34行~36行來實(shí)現(xiàn))必然在它的第一個出現(xiàn)的兄弟模塊之后,(ii)存儲第一次出現(xiàn)的模塊的最弱前置條后,元胞變量t_wp非空;(iii)通過調(diào)用命名為sft_wp_extend的新函數(shù)(通過執(zhí)行第37行代碼來實(shí)現(xiàn)),元胞變量t_wp也用于連接或嵌入當(dāng)前節(jié)點(diǎn)(即:t_mod)的最弱前置條件結(jié)構(gòu);(iv)通過執(zhí)行第38行~40行,從當(dāng)前節(jié)點(diǎn)t_mod演繹出的最弱前置條件結(jié)構(gòu)t_wp總是固定在變量fix_var所存儲的位置(所在層中第一次出現(xiàn)的模塊的序列號)。
<2>演繹其余節(jié)點(diǎn)的最弱前置條件
除了第一個節(jié)點(diǎn)外,演繹其余節(jié)點(diǎn)的最弱前置條件都將基于上一個兄弟節(jié)點(diǎn)的最弱前置條件結(jié)構(gòu)。同時,如果當(dāng)前節(jié)點(diǎn)在上一個兄弟節(jié)點(diǎn)且該兄弟節(jié)點(diǎn)為模塊之后,則當(dāng)前節(jié)點(diǎn)的最弱前置條件將連接到上一個兄弟節(jié)點(diǎn)的最弱前置條件結(jié)構(gòu)的最內(nèi)層終端位置之后。從本質(zhì)上講,這兩種情形的算法是相同的。
根據(jù)定義5,1×3cell形式的元胞結(jié)構(gòu)的第一個成員用于存儲最弱前置條件。然而,該成員可能嵌套另一個元胞結(jié)構(gòu),不但如此,這樣的嵌套形式還可能是多重的。因此,本算法的關(guān)鍵在于如何進(jìn)入嵌套形式的元胞結(jié)構(gòu)的最內(nèi)層終端位置。同樣地,dfs技術(shù)被應(yīng)來獲取嵌套結(jié)構(gòu)的最內(nèi)層終端位置。在最內(nèi)層終端位置,所需要的最弱前置條件可以很容易地得到。提取到的最弱前置條件以后置條件的形式作用于目標(biāo)節(jié)點(diǎn),則目標(biāo)節(jié)點(diǎn)的最弱前置條件通過演繹得到。以if-select模塊為例,圖6揭示了兩方面信息:其一,搜索如何到達(dá)模塊的最弱前置條件結(jié)構(gòu)的最內(nèi)層的終端位置;其二,下一個兄弟節(jié)點(diǎn)(命名為new_node)的最弱前置條件如何連接在當(dāng)前模塊的最弱前置條件結(jié)構(gòu)的最內(nèi)層終端之后。
在圖6中,if部分和else部分的黑色實(shí)線箭頭指示了兩條最弱前置條件傳播路徑(僅顯示了else部分)。從黑色點(diǎn)線所指示的方向看,給定的后置條件傳遞到語句1(標(biāo)為:statement1)后,語句1的最弱前置條件(標(biāo)為wp1)被演繹得到。隨后,語句2(標(biāo)為:statement2)的最弱前置條件(標(biāo)為wp2)被相應(yīng)演繹出。作為else分支的最弱前置條件,wp2放在此分支的最后一條語句(即:語句2)的后面。沿著else部分的黑色箭頭,每層中的1×3cell結(jié)構(gòu)的第一個元胞的內(nèi)容可以通dfs技術(shù)來獲取判斷。一旦黑色箭頭指向第一個空元胞(用灰色標(biāo)注),則該分支的最弱前置條件結(jié)構(gòu)的最內(nèi)層終端位置實(shí)際已經(jīng)到達(dá)。用灰色標(biāo)識的三個空元胞結(jié)構(gòu)(注:這三個空元胞結(jié)構(gòu)預(yù)先通過圖5中的第13行~17行設(shè)計來給定)用來存儲新節(jié)點(diǎn)(即:new_node)的最弱前置條件結(jié)構(gòu)。需要注意的是:從if-select模塊的角度來看,新節(jié)點(diǎn)被稱為下一個兄弟節(jié)點(diǎn)(標(biāo)為:brother-node),但從語句2角度看,新節(jié)點(diǎn)被稱為下一個叔父節(jié)點(diǎn)(標(biāo)為:uncle-node)。結(jié)果,下一個兄弟節(jié)點(diǎn)的最弱前置條件(即:new_wp)連接在當(dāng)前模塊的最弱前置條件的最內(nèi)層終端位置之后。
圖7給出的偽代碼顯示了這樣的功能:在上一個兄弟節(jié)點(diǎn)的最弱前置條件結(jié)構(gòu)的基礎(chǔ)上演繹當(dāng)前節(jié)點(diǎn)的最弱前置條件。該算法命名為sft_wp_extend:輸入?yún)?shù)in_wp_cond表示上一個兄弟節(jié)點(diǎn)的最弱前置條件結(jié)構(gòu)——新節(jié)點(diǎn)的后置條件結(jié)構(gòu),另一個輸入?yún)?shù)new_node表示新節(jié)點(diǎn)(該算法的目標(biāo)就是要演繹新節(jié)點(diǎn)的最弱前置條件)。該算法分為兩個部分。對于第一部分,第5行~第8行的功能是進(jìn)入最弱前置條件結(jié)構(gòu)in_wp_cond的最內(nèi)層終端位置。第5行代碼意味著當(dāng)前最弱前置條件結(jié)構(gòu)存在,而第6行意味著它是它是嵌套元胞結(jié)構(gòu)形式,因而需要再次搜索到達(dá)最內(nèi)層的終端位置。因此,第7行遞歸地調(diào)用當(dāng)前函數(shù)sft_wp_extend本身。至于第二部分,第9行~23行表明搜索已經(jīng)到達(dá)上一個兄弟節(jié)點(diǎn)的最弱前置條件結(jié)構(gòu)的內(nèi)層終端位置,然后,輸入節(jié)點(diǎn)(即:new_node)的最弱前置條件得到演繹。第10行意味著上一個兄弟節(jié)點(diǎn)的最弱前置條件結(jié)構(gòu)的最內(nèi)層終端位置是空元胞。所以,根據(jù)圖5中第13行~17行的設(shè)計,在最內(nèi)層終端位置的倒數(shù)第二個索引位置(即;第i-1個索引位置)處,上一兄弟節(jié)點(diǎn)的最弱前置條件(即:in_wp_cond{i-1})被作為當(dāng)前節(jié)點(diǎn)new_node的后置條件,從而演繹new_node的最弱前置條件。盡管第12行和第19行調(diào)用了相同的函數(shù)(即:圖5中設(shè)計的sft_wp_module函數(shù)),但它們的返回值是不一樣的。前者是一個用于存儲特殊節(jié)點(diǎn)(即:模塊)的最弱前置條件的嵌套結(jié)構(gòu),后者只是普通節(jié)點(diǎn)(即:賦值語句)的最弱前置條件。此外,如果搜索到的后置條件是“true”或“false”,它不會作為輸入?yún)?shù)輸入到函數(shù)sft_wp_module(換句話說,第12行或第19行不會被執(zhí)行)。在這種情況下,返回的結(jié)果仍然是“ture”或“false”。因此,一旦上一個兄弟節(jié)點(diǎn)的演繹結(jié)果是“true”或“false”,那些在上一個兄弟節(jié)點(diǎn)之后的那些節(jié)點(diǎn)的后置條件將不會被演繹。在這個意義上講,一旦一個節(jié)點(diǎn)的最弱前置條件是“true”或“false”,針對該節(jié)點(diǎn)之后的節(jié)點(diǎn)的演繹將會自動停止。
<3>提取執(zhí)行條件及其剩余代碼
在本節(jié)中,有兩個關(guān)鍵問題需要很好地得到解決。其一,只要搜索到一個模塊,則需要獲取其執(zhí)行條件及對應(yīng)的全局剩余代碼;其二,在搜索一個嵌套模塊的過程中,獲得的層索引必須是可以改變的。層索引需要改變的主要原因可以解釋如下:一旦搜索從下一個鄰近子層返回到當(dāng)前層,當(dāng)前層中隨后的執(zhí)行條件與相應(yīng)的局部剩余代碼將不同于進(jìn)入子層前的執(zhí)行條件及相應(yīng)的局部剩余代碼(雖然這兩種情況具有相同的層索引)。此外,執(zhí)行條件與其對應(yīng)的剩余代碼必須重新匹配層索引。
任何模塊可以根據(jù)存儲在1×3元胞結(jié)構(gòu)中的第二個元胞成員中的信息來識別。因此,算法從搜索每個模塊(如果它存在的話)開始,無論它是否嵌套其它模塊。一旦搜索到一個模塊,它的執(zhí)行條件、對立執(zhí)行條件、局部剩余代碼和全局剩余代碼都需要存儲。與此同時,當(dāng)前層的層索引需要增加1。通過遞歸調(diào)用當(dāng)前算法本身,這樣的設(shè)計方法將進(jìn)一步用于分析當(dāng)前模塊的子模塊(如果它存在的話)。為了能夠正確地匹配執(zhí)行條件、局部剩余代碼和層索引,一旦與子模塊相關(guān)的遞歸調(diào)用結(jié)束并返回到當(dāng)前模塊層,層索引數(shù)必須立即減少1。圖8顯示了如何設(shè)計該算法。
該算法被命名為:sft_wp_path。輸入?yún)?shù)module為倒序索引形式的程序節(jié)點(diǎn)或模塊的擴(kuò)展形式。在圖8中,全局變量l用來存儲模塊的層索引數(shù)。全局變量m用于存儲最外層程序節(jié)點(diǎn)的索引,全局變量n用來存儲執(zhí)行條件的索引。所有這些全局變量都在主函數(shù)中初始化為0。全局元胞結(jié)構(gòu)con_path用來存儲執(zhí)行條件及對應(yīng)的全局剩余代碼。全局元胞結(jié)構(gòu)reve_node用于存儲倒序索引的最外層程序節(jié)點(diǎn)。匹配于全局變量l,全局元胞結(jié)構(gòu)rem_arr用來存儲與執(zhí)行條件相關(guān)的局部剩余代碼。
第9行~39行表明當(dāng)前節(jié)點(diǎn)是一個模塊。然后,第10行和11行分別讓層索引l和執(zhí)行條件的索引n增加1。如果l等于1,那么搜索必定在最外層位置,進(jìn)而只需存儲最外層的剩余代碼(存儲過程通過第13行來實(shí)現(xiàn))。在這種情況下,局部剩余代碼和全局剩余代碼是相同的。第15行表明當(dāng)前模塊必定為子模塊,它的局部剩余代碼也必定從當(dāng)前層獲得。第13行和第15行也表明了這樣一個事實(shí),執(zhí)行條件的演繹入口是當(dāng)前模塊的下一個兄弟節(jié)點(diǎn)。第19行~30行的功能是得到當(dāng)前執(zhí)行條件的全局剩余代碼。其形成方法分析如下:對于元胞結(jié)構(gòu)rem_arr,它的每一個存儲于元胞成員中的特定局部剩余代碼以倒序的方式放到全局元胞結(jié)構(gòu)con_path中,用以形成當(dāng)前執(zhí)行條件的全局剩余代碼。把局部剩余代碼以倒序的方式存儲到con_path中的原因是搜索總是從外到內(nèi)進(jìn)行的。因此,形成當(dāng)前執(zhí)行條件的全局剩余代碼必須從放置當(dāng)前局部剩余代碼開始,然后放置外層局部剩余碼,等等,直到放置最外層局部剩余代碼。設(shè)置第31行的目的是為了獲取并存儲當(dāng)前模塊的執(zhí)行條件。第32行到第36行表明,只要當(dāng)前模塊不是for循環(huán)結(jié)構(gòu),其對立執(zhí)行條件及其全局剩余代碼直接通過復(fù)制得到。第34行表明對立執(zhí)行條件的全局剩余代碼通過直接復(fù)制執(zhí)行條件的全局剩余代碼來得到。第35行表明對立執(zhí)行條件來自當(dāng)前模塊的子成員。設(shè)計第37行的目的是搜索當(dāng)前模塊的第三個子成員。一旦搜索子成員(該子成員為模塊)過程結(jié)束并返回到當(dāng)前層,層索引數(shù)l必須及時地減去1以保證層索引數(shù)與新的執(zhí)行條件和對應(yīng)的局部剩余代碼相匹配。這樣的任務(wù)通過設(shè)計第38行來實(shí)現(xiàn)。第7行~8行表明:當(dāng)前的輸入?yún)?shù)(即:module,它表示模塊的擴(kuò)展形式,例如,根據(jù)定義4,if選擇結(jié)構(gòu)將進(jìn)一步用兩條分支來解釋)需要得到進(jìn)一步搜索。第6行表明:如果當(dāng)前節(jié)點(diǎn)(即:輸入?yún)?shù)module)是一條賦值語句,那么不需要搜索該節(jié)點(diǎn)的成員。因此,在這種情況下,不需要設(shè)計任何執(zhí)行代碼就會自動結(jié)束當(dāng)前循環(huán)。
發(fā)明方案的意義和有益效果
最弱前置條件的演繹模型和算法是一系列理論與實(shí)踐相結(jié)合的體系。本發(fā)明結(jié)合軟件故障樹研究和分析的要求,抓住軟件運(yùn)行過程的特征,深入研究建模方法和實(shí)現(xiàn)技術(shù),實(shí)現(xiàn)符合實(shí)際的演繹模型和算法。綜合起來,本發(fā)明具有如下工程意義和效果:
(1)該建模方法和算法將對軟件系統(tǒng)的可靠性評價和維護(hù)策略、故障診斷和測試提供重要的參考依據(jù)。
考慮程序最弱前置條件的傳播路徑分支的可能性和存在性,本發(fā)明不僅關(guān)注各分支執(zhí)行條件下的目標(biāo)代碼的最弱前置條件,而且擴(kuò)展演繹執(zhí)行條件本身的最弱前置條件。對于一個給定后置條件的程序,產(chǎn)生不恰當(dāng)賦值或約束關(guān)系的原因能夠準(zhǔn)確地在最弱前置條件的傳播路徑中顯示出來。此外,最弱前置條件的其它潛在傳播路徑可以為程序測試(故障診斷)人員修改不適當(dāng)?shù)膱?zhí)行條件、賦值或者約束關(guān)系提供重要的參考信息。從這個意義上講,本發(fā)明的建模方法關(guān)注程序中的某些bug的演繹和定位,能夠為測試人員做進(jìn)一步分析奠定基礎(chǔ)。
(2)該建模方法和算法能為形成具有自主知識產(chǎn)權(quán)的軟件故障樹分析評估軟件提供較為重要的技術(shù)基礎(chǔ)。
具有自主知識產(chǎn)權(quán)的軟件故障樹建模分析與評估軟件的核心在于軟件的功能在模型、方法和技術(shù)實(shí)現(xiàn)上有獨(dú)特的創(chuàng)新體系。面向過程的軟件故障樹自動化建模需要解決好兩個基本邏輯門(即:與門和或門)的形成和演繹技術(shù)。本發(fā)明以最弱前置條件為推演手段,合理考慮選擇結(jié)構(gòu)(循序結(jié)構(gòu))的分支路徑,實(shí)際上就是為邏輯或門的形成奠定基礎(chǔ),而充分考慮選擇結(jié)構(gòu)(循環(huán)結(jié)構(gòu))的執(zhí)行條件,則為邏輯與門的形成奠定基礎(chǔ)。為了實(shí)現(xiàn)這樣的目標(biāo),本發(fā)明中提出的演繹模型和設(shè)計算法體現(xiàn)了獨(dú)特的技術(shù)方法和表現(xiàn)手段,具有較為完整的框架體系。
(3)該建模方法和算法能為軟件故障樹研究和分析的模型化、標(biāo)準(zhǔn)化、實(shí)用化發(fā)展開辟方向。
本發(fā)明中提出并實(shí)現(xiàn)的建模方法針對通用的順序結(jié)構(gòu)、選擇結(jié)構(gòu)和循環(huán)結(jié)構(gòu)建立了典型的演繹模型。為實(shí)現(xiàn)演繹算法而提出的節(jié)點(diǎn)定義、模塊識別及存儲技術(shù)力圖實(shí)現(xiàn)一種模式化表現(xiàn)手段。即使所針對的對象是matlab程序,但節(jié)點(diǎn)定義和模塊識別的方法具有較為顯著的標(biāo)準(zhǔn)化特征。實(shí)現(xiàn)算法所采用的語言是matlab語言,但使用的嵌套元胞存儲技術(shù)和樹型邏輯存儲結(jié)構(gòu)的思想和功能完全類似。本發(fā)明的建模方法和算法能為促進(jìn)軟件故障樹研究和分析的模型化、標(biāo)準(zhǔn)化、實(shí)用化發(fā)展開辟方向。