王克朝,王甜甜,蘇小紅,馬培軍,童志祥
(1.哈爾濱工業(yè)大學(xué) 計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院,150001 哈爾濱;2.哈爾濱學(xué)院 軟件學(xué)院,150086 哈爾濱)
程序理解[1]是通過對(duì)程序的分析、抽象及推 理獲取知識(shí)的一個(gè)演繹過程,需要解決數(shù)據(jù)收集、知識(shí)組織及信息瀏覽3個(gè)方面的問題.解決這些問題的一個(gè)關(guān)鍵是程序的中間表示.
K.J.Ottenstein 等[2]提出了程序依賴圖的概念.S.Horwitz等[3]將程序依賴圖擴(kuò)展為系統(tǒng)依賴圖,捕獲過程間的調(diào)用關(guān)系.系統(tǒng)依賴圖是程序基于圖形的中間表示,能清晰地表示出程序中的各種控制依賴和數(shù)據(jù)依賴關(guān)系及程序的語法與語義信息,因此在編譯器優(yōu)化[4-5]、程序切片[6]、軟件審查[7]、軟件測(cè)試[8]、編程題自動(dòng)評(píng)分[9-11]、克隆代碼檢測(cè)[12-13]以及軟件缺陷檢測(cè)[14-15]等領(lǐng)域得到了廣泛的應(yīng)用.系統(tǒng)依賴圖的構(gòu)建方法也得到了廣泛的研究,近年來提出了面向?qū)ο螅?6]、面向方面[17]以及函數(shù)式程序[18]的系統(tǒng)依賴圖的創(chuàng)建方法.
然而,程序理解過程中,常常需要按需的程序分析,如果程序規(guī)模較大,則很難一次理解、分析所有的系統(tǒng)依賴圖節(jié)點(diǎn)及邊;此外,由于編程語言的語法多樣性,同一個(gè)編程任務(wù)可由多種語法結(jié)構(gòu)實(shí)現(xiàn),這種現(xiàn)象稱為代碼多樣化,增加了程序理解的難度.因此,本文采取控制依賴和數(shù)據(jù)依賴分別求解,在控制依賴子圖的基礎(chǔ)上,按需進(jìn)行數(shù)據(jù)流分析,降低了算法復(fù)雜度,使之適合于分析大規(guī)模代碼;將選擇語句和循環(huán)語句統(tǒng)一表示,將表達(dá)式表示為抽象語法樹,為實(shí)現(xiàn)程序標(biāo)準(zhǔn)化時(shí)進(jìn)行語義等價(jià)的程序轉(zhuǎn)換和程序匹配提供了方便.
定義1 程序依賴圖(Program Dependence Graph,PDG)單過程程序P的PDGG=(V,E)是一個(gè)有向圖.其中:V為節(jié)點(diǎn)集合,表示程序中的語句和謂詞;E?V×V為邊集合,表示節(jié)點(diǎn)間的數(shù)據(jù)依賴或控制依賴關(guān)系.
定義2 系統(tǒng)依賴圖(System Dependence Graph,SDG)多過程程序 P的SDGG={GPDGs,EInterpro}是一個(gè)有向圖.其中:GPDGs為PDG集合,每個(gè)過程(函數(shù))表示為一個(gè)PDG;EInterpro為過程間調(diào)用邊與依賴邊的集合,過程間的調(diào)用邊將函數(shù)調(diào)用位置與被調(diào)函數(shù)的entry相連,過程間的數(shù)據(jù)依賴邊表示實(shí)參和形參間的數(shù)據(jù)流.
系統(tǒng)依賴圖包含控制依賴子圖和數(shù)據(jù)依賴子圖.
定義3 控制依賴子圖(Control Dependence Sub-graph,CDS)由節(jié)點(diǎn)和控制依賴邊構(gòu)成,表示程序的控制流信息.
定義4 數(shù)據(jù)依賴子圖(Data Dependence Sub-graph,DDS)由節(jié)點(diǎn)和數(shù)據(jù)依賴邊構(gòu)成,表示程序的數(shù)據(jù)流信息.
依賴圖中的邊主要有4種依賴關(guān)系:控制依賴、流依賴、聲明依賴和過程調(diào)用依賴.令v1,v2分別為依賴圖中的兩個(gè)節(jié)點(diǎn),分別定義如下:
定義5(控制依賴) 如果v2的執(zhí)行是由v1表示的謂詞在執(zhí)行時(shí)確定的,那么v2控制依賴于v1.不從屬于任何控制謂詞的節(jié)點(diǎn)控制依賴于entry節(jié)點(diǎn).
定義6(流依賴) 如果有一條從v1到v2的路徑,且存在一個(gè)在v2中定義并在v1中使用的變量,且該變量在從v1到v2的路徑上的其他任何地方?jīng)]有被重新定義,則稱v2流依賴于v1.
定義7(聲明依賴) 從聲明某變量的節(jié)點(diǎn)v1到后面的各個(gè)定義該變量的節(jié)點(diǎn)v2間的特殊的數(shù)據(jù)依賴.
定義8(過程調(diào)用依賴) 從函數(shù)調(diào)用節(jié)點(diǎn)v1到被調(diào)函數(shù)入口節(jié)點(diǎn)v2的邊.
1)傳統(tǒng)SDG數(shù)據(jù)流分析的復(fù)雜度高,不適合于大規(guī)模軟件分析,因此本文將SDG分解為CDS和DDS,基本操作基于CDS,只在需要數(shù)據(jù)流信息時(shí),在CDS的基礎(chǔ)上計(jì)算數(shù)據(jù)流信息,這樣既可利用SDG能夠表示程序語法與語義信息及便于程序匹配的優(yōu)點(diǎn),又可降低數(shù)據(jù)流分析的復(fù)雜度,節(jié)省空間和時(shí)間,使之適合于分析大規(guī)模代碼.
2)傳統(tǒng)SDG以不同的形式表示各種選擇結(jié)構(gòu)語句和循環(huán)語句,不利于代碼標(biāo)準(zhǔn)化操作,因此本文在SDG中新增加了選擇結(jié)構(gòu)節(jié)點(diǎn)和循環(huán)結(jié)構(gòu)節(jié)點(diǎn)類型.選擇結(jié)構(gòu)節(jié)點(diǎn)包括selection節(jié)點(diǎn)和selector節(jié)點(diǎn),統(tǒng)一了所有選擇結(jié)構(gòu)語句if、if-else、switch和選擇運(yùn)算符(?:)的表示形式,其中:selection節(jié)點(diǎn)為選擇結(jié)構(gòu);selector節(jié)點(diǎn)及其子節(jié)點(diǎn)為選擇分支.循環(huán)結(jié)構(gòu)節(jié)點(diǎn)包括iteration節(jié)點(diǎn)和init-sub節(jié)點(diǎn),統(tǒng)一了 for、while和 do-while的表示形式.其中iteration節(jié)點(diǎn)表示選擇結(jié)構(gòu),其子節(jié)點(diǎn)表示循環(huán)體中的語句,init-sub節(jié)點(diǎn)用于dowhile語句中.統(tǒng)一了選擇語句和循環(huán)語句表示,便于消除選擇結(jié)構(gòu)和循環(huán)結(jié)構(gòu)的語法表示的多樣化.
3)傳統(tǒng)的SDG將表達(dá)式表示為節(jié)點(diǎn)中的token串,這種表示方式不能充分表示表達(dá)式的語法結(jié)構(gòu),本文將表達(dá)式表示為抽象語法樹,連接到語句節(jié)點(diǎn)上.這樣,使得控制依賴樹不但可以表示控制流,還可以充分表示語法信息,便于執(zhí)行指針分析和程序轉(zhuǎn)換.
根據(jù)源程序SDG的特點(diǎn),本文基于程序理解的基本原理將整個(gè)SDG自動(dòng)生成過程劃分為:程序信息的提取、CDS的構(gòu)造和DDS的構(gòu)造.圖1給出了面向程序理解的SDG自動(dòng)生成的模型.
圖1 面向程序理解的SDG自動(dòng)生成模型
CDS是根據(jù)程序信息提取階段創(chuàng)建的token串、符號(hào)表和函數(shù)列表來構(gòu)建的,在創(chuàng)建系統(tǒng)CDS的同時(shí)處理程序的某些語法錯(cuò)誤.
DDS的構(gòu)造本質(zhì)上是建立流依賴邊和聲明依賴邊,可歸結(jié)到程序中到達(dá)-定值信息的求解.由于CDS包含控制流信息,可通過CDS獲得節(jié)點(diǎn)之間的控制依賴關(guān)系,從而獲得各個(gè)節(jié)點(diǎn)的到達(dá)-定值信息,因此可在創(chuàng)建完CDS后對(duì)其執(zhí)行數(shù)據(jù)流分析,構(gòu)建DDS.
進(jìn)一步分析程序信息提取階段創(chuàng)建的token串、符號(hào)表和函數(shù)列表來構(gòu)建CDS,算法如圖2所示.其中:GS為語法棧,用來保存分析過程中需要記錄的語法信息;hQ為控制依賴節(jié)點(diǎn)隊(duì)列,用以記錄節(jié)點(diǎn)間的控制依賴關(guān)系.該算法識(shí)別程序的語法元素,并建立各個(gè)語句節(jié)點(diǎn)間的控制依賴關(guān)系,從而生成CDS.
圖2 系統(tǒng)CDS構(gòu)建算法
數(shù)據(jù)依賴是節(jié)點(diǎn)表示的語句之間數(shù)據(jù)的定義和使用關(guān)系.數(shù)據(jù)依賴可分為不同的類型,如流依賴、聲明依賴等.
本文自底向上按需分析給定程序模塊的函數(shù)調(diào)用關(guān)系:對(duì)給定程序模塊的函數(shù)調(diào)用圖,首先計(jì)算其終端節(jié)點(diǎn)函數(shù)的數(shù)據(jù)依賴,然后自底向上分析該函數(shù)的主調(diào)函數(shù)的數(shù)據(jù)依賴,當(dāng)終端節(jié)點(diǎn)存在多個(gè)主調(diào)函數(shù)時(shí),只需分析終端節(jié)點(diǎn)一次,無需重復(fù)分析終端節(jié)點(diǎn),也無需多個(gè)過程依賴圖拷貝.可以對(duì)給定程序模塊執(zhí)行局部數(shù)據(jù)依賴分析,因此適用于分析大規(guī)模程序.
基于編譯器代碼優(yōu)化領(lǐng)域中經(jīng)典的迭代數(shù)據(jù)流分析算法,在CDS的基礎(chǔ)上計(jì)算數(shù)據(jù)依賴信息,建立DDS,其構(gòu)建模型如圖3所示.
圖3 系統(tǒng)DDS構(gòu)建模型
要建立各種數(shù)據(jù)依賴邊應(yīng)首先求節(jié)點(diǎn)間的到達(dá)-定值信息.到達(dá)-定值的相關(guān)概念如表1所示.
表1 數(shù)據(jù)流方程的定義
其中:
所有患者均順利完成手術(shù)。2組患者術(shù)前腰椎側(cè)凸Cobb角及腰椎前凸角差異無統(tǒng)計(jì)學(xué)意義(P >0.05,表1);2組術(shù)后2周及1年腰椎側(cè)凸Cobb角及腰椎前凸角均較術(shù)前顯著改善,差異有統(tǒng)計(jì)學(xué)意義(P < 0.05,表1);A組術(shù)后1年腰椎側(cè)凸矯正率為79.2%,B組為81.4%,差異無統(tǒng)計(jì)學(xué)意義(P > 0.05)。2組患者術(shù)前頂椎旋轉(zhuǎn)程度差異無統(tǒng)計(jì)學(xué)意義(P > 0.05);術(shù)后2周及1年頂椎去旋轉(zhuǎn)程度B組優(yōu)于A組,差異有統(tǒng)計(jì)學(xué)意義(P < 0.05,表2)。
1)變量x的定值是一個(gè)語句,它賦值或可能賦值給x.最普通的定值是對(duì)x的賦值或讀值到x中的語句.
2)如果有路徑從緊跟d的點(diǎn)到達(dá)p,并且在這條路徑上d沒有被注銷,則定值d到達(dá)p.
3)如果某個(gè)變量a的定值d到達(dá)點(diǎn)p,那么p引用a的最新定值可能在d點(diǎn).如果沿著這條路徑的某兩點(diǎn)間是讀a或?qū)的賦值,那么注銷變量a的定值d.
為了計(jì)算到達(dá)程序中每個(gè)語句的定值的集合,首先計(jì)算局部的定值信息,然后通過控制依賴邊進(jìn)行傳播.數(shù)據(jù)流信息可以由建立和解方程來收集,這些方程聯(lián)系程序不同點(diǎn)的信息.
當(dāng)控制流通過一個(gè)語句時(shí),語句末尾的信息是在這個(gè)語句中產(chǎn)生的信息或是進(jìn)入語句開始點(diǎn)并且沒有被這個(gè)語句注銷的信息.由數(shù)據(jù)流方程可看出,算法的關(guān)鍵在于各個(gè)控制流節(jié)點(diǎn)的GEN和KILL集合的計(jì)算,而生成GEN和KILL集合則需要知道各個(gè)節(jié)點(diǎn)定值和使用了那些變量,用DEF與REF集合來表示.
4.1.1 計(jì)算REF與DEF集合
CDS中節(jié)點(diǎn)的 GEN、KILL、IN、OUT集合的計(jì)算都是基于各節(jié)點(diǎn)的REF與DEF信息的,所以從CDS的節(jié)點(diǎn)中收集REF與DEF信息對(duì)于到達(dá)-定值的計(jì)算是十分關(guān)鍵的.
CDS中每個(gè)節(jié)點(diǎn)都有一個(gè)REF和DEF集合.一個(gè)節(jié)點(diǎn)的REF集合包含了該節(jié)點(diǎn)進(jìn)行計(jì)算時(shí)引用的所有變量,DEF集合包含了該節(jié)點(diǎn)計(jì)算的變量.如表2所示.
表2 基本表達(dá)式的REF集合定義
在建立好CDS后,便可以后根序遍歷CDS,根據(jù)節(jié)點(diǎn)的不同類型,采用表3中相應(yīng)的表達(dá)式求其REF和DEF集合.
表3 各種不同類型的語句的REF和DEF集合定義
4.1.2 計(jì)算GEN和KILL集合
在獲得CDS中各個(gè)節(jié)點(diǎn)的REF和DEF集合信息后,GEN集合的生成將十分直接:在遍歷CDS時(shí),如果當(dāng)前節(jié)點(diǎn)是賦值語句節(jié)點(diǎn)或scanf語句節(jié)點(diǎn),則根據(jù)它的DEF集合,由當(dāng)前的節(jié)點(diǎn)號(hào)和DEF中的變量名組成GEN集合中一個(gè)元素,從而建立GEN集合.
KILL集合的生成需要對(duì)整個(gè)CDS中的節(jié)點(diǎn)進(jìn)行多次遍歷.算法描述如圖4所示.
圖4 KILL集合求解算法
4.1.3 計(jì)算IN和OUT集合
為了傳播數(shù)據(jù)流信息,在計(jì)算到達(dá)-定值信息時(shí)需要使用IN和OUT集合.一個(gè)節(jié)點(diǎn)的IN集合由到達(dá)該節(jié)點(diǎn)的前一點(diǎn)的定值組成,OUT集合由到達(dá)該節(jié)點(diǎn)下一點(diǎn)的定值組成.由于一個(gè)語句節(jié)點(diǎn)的IN和OUT集合可能不同,本文為CDS中的每個(gè)語句節(jié)點(diǎn)都計(jì)算這兩個(gè)集合.
采用迭代法求各個(gè)節(jié)點(diǎn)的IN和OUT集合.在每次迭代時(shí)對(duì)CDS中每個(gè)節(jié)點(diǎn)N,使用KILL和GEN集合計(jì)算IN與OUT集合.IN[N]等于節(jié)點(diǎn)N在CDS中前驅(qū)節(jié)點(diǎn)的OUT集合,OUT[N]是用IN[N]、GEN[N]、KILL[N]生成的.算法描述如圖5所示.
圖5 到達(dá)-定值信息的求解算法
到此為止,CDS中每個(gè)節(jié)點(diǎn)的到達(dá)-定值信息就計(jì)算完畢了.
在獲得了各個(gè)節(jié)點(diǎn)的IN和OUT集合后,后根序遍歷CDS,利用各節(jié)點(diǎn)的IN集合和REF集合即可獲得節(jié)點(diǎn)間的數(shù)據(jù)依賴關(guān)系.具體的規(guī)則是如果當(dāng)前節(jié)點(diǎn)的REF集合中某個(gè)變量名和IN集合中某個(gè)二元組中的變量名相同,則認(rèn)為當(dāng)前節(jié)點(diǎn)和IN集合同一個(gè)二元組中給出的節(jié)點(diǎn)之間存在流依賴關(guān)系,并將生成的流依賴關(guān)系放入表中存儲(chǔ).建立流依賴邊和聲明依賴邊的算法如圖6所示.
圖6 程序系統(tǒng)DDS建立算法
如圖7,8中所示的兩個(gè)示例程序,均實(shí)現(xiàn)相同的功能,但循環(huán)結(jié)構(gòu)和選擇結(jié)構(gòu)采用了不同的語法表示形式,Horwitz方法采用不同的形式表示這兩個(gè)程序,而本文創(chuàng)建的SDG可將這兩個(gè)語義等價(jià)程序表示成相同的形式,如圖9所示,從而可以統(tǒng)一分析、理解這兩個(gè)程序,降低了程序理解的復(fù)雜度.在此基礎(chǔ)上,可以進(jìn)一步執(zhí)行程序標(biāo)準(zhǔn)化轉(zhuǎn)換,消除代碼多樣化.
圖7 示例程序1
圖9 系統(tǒng)依賴圖實(shí)例
此外,與Horwitz方法相比,本文方法直接基于控制依賴子圖分析數(shù)據(jù)流信息,并且可實(shí)現(xiàn)按需的數(shù)據(jù)流分析,降低了數(shù)據(jù)流分析的復(fù)雜度,節(jié)省空間和時(shí)間,使之適合于分析大規(guī)模代碼.
圖8 與示例程序1語義等價(jià)的示例程序2
本文提出的系統(tǒng)依賴圖生成算法已在“基于程序理解的C語言編程題自動(dòng)評(píng)分系統(tǒng)”中得到了應(yīng)用,整個(gè)評(píng)分過程劃分為3個(gè)階段:將程序代碼轉(zhuǎn)換成SDG;根據(jù)控制流和數(shù)據(jù)流對(duì)SDG進(jìn)行標(biāo)準(zhǔn)化轉(zhuǎn)換;最后匹配標(biāo)準(zhǔn)化后的學(xué)生程序與模板程序控制依賴子圖,并根據(jù)匹配結(jié)果給出評(píng)分.由此可看到,編程題自動(dòng)評(píng)分系統(tǒng)的基礎(chǔ)和關(guān)鍵是SDG.
本文算法還被應(yīng)用于“語義相似的程序識(shí)別”中,識(shí)別大規(guī)模程序中語義相似的程序代碼[19].其基本思想是:分別將待檢測(cè)的兩段源代碼解析為兩棵系統(tǒng)依賴圖的控制依賴樹,并分別執(zhí)行基本代碼標(biāo)準(zhǔn)化;利用度量值方法提取兩棵基本代碼標(biāo)準(zhǔn)化后的控制依賴樹的候選相似代碼控制依賴樹;對(duì)提取的候選相似代碼,進(jìn)行數(shù)據(jù)流分析,執(zhí)行高級(jí)代碼標(biāo)準(zhǔn)化操作;計(jì)算語義相似度,獲得相似度結(jié)果,從而識(shí)別語義相似的程序代碼.
應(yīng)用結(jié)果表明:本文構(gòu)建的SDG能夠充分表示程序的語法和語義,既可應(yīng)用于分析小規(guī)模程序代碼,也可應(yīng)用于分析大規(guī)模程序代碼,對(duì)可執(zhí)行按需數(shù)據(jù)流分析,具有較低的復(fù)雜度和較高的準(zhǔn)確性,并為程序標(biāo)準(zhǔn)化與語義分析提供了方便.
1)提出了一種面向程序理解的SDG構(gòu)建算法,包含程序信息的提取、CDS的構(gòu)建和DDS的構(gòu)建3個(gè)階段.
2)改進(jìn)了傳統(tǒng)的SDG,直接基于CDS分析數(shù)據(jù)流信息,統(tǒng)一表示選擇語句和循環(huán)語句,將表達(dá)式表示為抽象語法樹.
3)提出的SDG構(gòu)建算法已被應(yīng)用于基于程序理解的編程題自動(dòng)評(píng)分系統(tǒng)和大規(guī)模程序的語義相似程序代碼識(shí)別中,結(jié)果表明該SDG能夠充分表示程序的語法和語義,且按需進(jìn)行數(shù)據(jù)流分析的方法降低了程序理解和分析的復(fù)雜度.
[1] EXTON C.Constructivism and program comprehension strategies[C]//Proceedings of the 10th International WorkshoponProgram Comprehension(IWPC'02).Washington,DC:IEEE Computer Society,2002:282-283.
[2] OTTENSTEIN K J,LOTTENSTEIN M.The program dependence graph in a software development environment[C]//Proceedings of the First ACM SIGSOFT/SIGPLAN Software Engineering Symposium on Practical Software Development Environments.New York:ACM,1984:177-184.
[3]HORWITZ S,REPS T,BINKLEY D.Interprocedural slicing using dependence graphs[J].ACM Transactions on Programming Languages and Systems,1990,12(1):26-60.
[4] MATSUMOTO T,SAITO P,F(xiàn)UJITA P.Equivalence checking of C programs by locally performing symbolic simulation on dependence graphs[C]//Proceedings of the 7th International Symposium on Quality Electronic Design(ISQED'06). Washington, DC:IEEE Computer Society,2006:370-375.
[5]逄龍,王甜甜,蘇小紅,等.支持多程序語言的靜態(tài)信息提取方法[J].哈爾濱工業(yè)大學(xué)學(xué)報(bào),2011,43(3):62-66.
[6]SRIDHARAN M,F(xiàn)INK P J,BODIK R.Thin slicing[C]//Proceedingsofthe2007 ACM SIGPLAN Conference on Programming Language Design and Implementation.New York:ACM,2007:112-122.
[7]ANDERSON P,ZARINS M.The codesurfer software understanding platform[C]//Proceedings of the 13th International Workshop on Program Comprehension.Washington,DC:IEEE Computer Society,2005:147-148.
[8]MILLER J,REFORMAT M,ZHANG H.Automatic test data generation using genetic algorithm and program dependence graphs[J].Information and Software Technology,2006,48(7):586-605.
[9] WANG Tiantian,SU Xiaohong,MA Peijun,et al.Ability-training-oriented automated assessment in introductory programming course[J].Computers &Education,2011,56(1):220-226.
[10]WANG Tiantian,SU Xiaohong,WANG Yuying,et al.Semantic similarity-based grading of student programs[J].Information and Software Technology,2007,49(2):99-107.
[11]馬培軍,王甜甜,蘇小紅.基于程序理解的編程題自動(dòng)評(píng)分方法[J].計(jì)算機(jī)研究與發(fā)展,2009,46(7):1136-1142.
[12]楊軼,蘇璞睿,應(yīng)凌云,等.基于行為依賴特征的惡意代碼相似性比較方法[J].軟件學(xué)報(bào),2011,22(10):2438-2453.
[13]WANG Tiantian,SU Xiaohong,MA Peijun.Program normalization for removing code variations[C]//International Conference on Computer Science and Software Engineering. Washington, DC:IEEE Computer Society,2008:306-309.
[14]SNELTING G,ROBSCHINK T,KRINKE J.Efficient path conditions in dependence graphs for software safety analysis[J].ACM Transactions on Software Engineering and Methodology,2006,15(4):410-457.
[15]王甜甜,蘇小紅,馬培軍.程序標(biāo)準(zhǔn)化轉(zhuǎn)換中的指針分析算法研究 [J].電子學(xué)報(bào),2009.37(5):1104-1108.
[16]DU Lin,XIAO Guorong,LI Daming.A novel approach to construct object-oriented system dependence graph and algorithm design[J].Journal of Software,2012,7(1):133-170.
[17]ZHAO Jianjun,RINARD M.System Dependence Graph Construction for Aspect-Oriented Programs[R].MIT-LCSTR-891,MIT:Laboratory for Computer Science,2003.
[18]SILVA J TAMARIT S,TOMáS C.System dependence graphs in sequential erlang[C]//Proceedings of the 15th International Conference on Fundamental Approaches to Software Engineering.Washington,DC:IEEE Computer Society,2012:486-500.
[19]王甜甜,馬培軍,蘇小紅,等.一種基于程序源代碼語義分析的代碼相似度檢測(cè)方法:中國(guó),200910073094.4[P].2009.