本發明涉及軟件測試技術領域,具體涉及一種基于約束求解的原子違背探測方法。
背景技術:
隨著多核處理器的普及,并發編程技術得到了廣泛的應用。由于并發程序的執行交織空間大、運行不確定,并發程序錯誤的測試、調試以及修復十分困難。其中,原子違背是其中最常見的并發錯誤,約占非死鎖類型并發錯誤的65%。現有的原子違背探測技術大致分為三類:靜態探測技術、運行時監測技術和運行時預測技術。其中,靜態探測技術可在程序源代碼級別識別出潛在的原子違背錯誤,但其無法處理鎖以外的其他類型的同步原語,誤檢率高。運行時監測技術監測并發程序執行,探測在程序實際執行中暴露出的原子違背錯誤,其誤檢率低,但漏檢率高。運行時預測技術通過對程序執行序列進行分析和處理,可探測出隱藏在程序執行序列中尚未暴露的原子違背。然而,現有很多運行時預測技術或者由于采用了保守的并發程序模型,其探測結果具有較高的誤檢率,或者由于搜索交織空間有限,具有較高的漏檢率。
若某執行軌跡至少滿足Happened-Before和鎖保護兩個約束,則稱其為合法軌跡。其中,Happened-Before關系約束,包含以下三個方面:
●若事件ei,ej屬于同一線程,且ei發生在ej之前,那么在任何情況下ei都在ej之前執行;
●若事件ei開啟了ej所在的線程,那么ei必須在ej前發生;
●若事件ej等待來在ei發送的信息,那么ei在ej前發生;
鎖約束(Lock Constraint):每一個鎖對(acquire-release)都不能與其他操作同一鎖變量的鎖對產生交織,即在任何情況下對于任何一個鎖只能被一個線程擁有,以保證互斥訪問。
對同一共享變量進行訪問的原子違背有如下五種模式,如表1,其中ti表示線程,Ri,Wj分別表示線程ti的讀事件與寫事件,m表示事件所存取的內存位置。
表1:原子違背的各種模式
技術實現要素:
針對現有技術的不足,本發明提出一種基于約束求解的原子違背探測方法,將原子違背的探測問題轉化為約束等式的求解問題,可有效降低原子違背探測的誤檢率,提高其探測能力。
為實現上述方面目的,本發明采用如下技術方案:
一種基于約束求解的原子違背探測方法,利用并發程序原始執行軌跡,結合原子違背的各種錯誤模式,建立原始執行軌跡中事件之間執行先后順序的約束關系,并求解,當約束有解時,該解對應的新的執行軌跡中存在原子違背現象,當約束無解時,則不存在原子違背現象。
進一步的,包括以下步驟:
步驟1):記錄原始執行軌跡:
步驟11):對原始程序進行插樁,以便在運行時記錄需要的執行軌跡信息;
步驟12):執行原始程序,記錄執行軌跡,一個執行軌跡是一個事件序列,表示為δ=<e1,e2,…ei,…,en>,其中每個事件ei包含下列屬性:
ti:事件ei所屬的線程;
mi:事件ei所存取的內存位置;
li:當事件ei執行時,其所擁有的鎖;
ai:事件ei的存取類型,包括讀、寫、獲取鎖、釋放鎖、等待、通知、創建線程和等待線程結束等八種類型;
步驟2):由步驟1)所得的原始執行軌跡和預定義的原子區域模式確定原子性區域,并利用原子區域和原子違背的各種錯誤模式收集潛在的可能會引起不可序列化交織的事件序列:
步驟21):由步驟1)所得的執行軌跡和預定義的原子區域模式,確定原子性區域;將每個synchronized方法,synchronized代碼塊以及鎖保護的代碼塊均視為原子區域;
步驟22):給定a,b,c三個事件,其中thread(a)=thread(b)≠thread(c),若事件a,b屬于步驟21)所得的同一原子性區域,且這三個事件的讀寫類型符合某個原子違背模式中對應的事件讀寫類型,則事件a,b,c是一個潛在的可能會引起不可序列化交織的事件序列;收集這些潛在的可能會引起不可序列化交織的事件序列,對這些收集的事件序列,進一步探測是否存在執行軌跡使這些事件序列中的三個事件的執行順序符合不可序列化交織模式;
步驟3):建立原子違背約束;
對步驟22)中得到的事件序列建立原子違背約束,其中(a,c,b)是某個事件序列中的三個事件,其中thread(a)=thread(b)≠thread(c),且事件a,b來自同一原子性區域,約束內容分為兩部分:
第一部分:在求解出的執行軌跡中事件c要在事件a和事件b之間被執行;
第二部分:事件a,b,c在求解出的執行軌跡中一定會被執行,但不要求事件a,b,c讀寫的值與原執行軌跡中的事件a,b,c讀寫的值一樣;
步驟4):原子違背約束求解
使用Z3約束求解器進行約束求解,當約束有解時,該解對應的新的執行軌跡中存在原子違背現象,否則不存在。
本發明的有益效果為:1、對原始程序軌跡和每個不可序列化的執行交織建立一組約束,將探測原子違背問題轉化為約束的求解問題,提高原子違背探測的精度;
2、本方法屬于運行時預測技術,可根據約束求解出隱藏在原始執行軌跡中沒有暴露出的原子違背錯誤,具有更好的探測原子違背的能力。
附圖說明
圖1為本發明方法的實施流程圖。
具體實施方式
本發明利用并發程序原始執行軌跡,結合原子違背的各種錯誤模式,建立原始執行軌跡中事件之間執行先后順序的約束關系,并求解,當約束有解時,該解對應的新的執行軌跡中存在原子違背現象,否則不存在,具體而言,包括以下步驟:
1.得到執行軌跡:
(1)對原始程序進行插樁,以便在運行時記錄需要的軌跡執行信息;
順序掃描被測程序中的每條語句,在特定的語句前后插樁代碼,如:同步語句、賦值語句、分支語句等,在實際執行時收集與這些語句相關的信息以組合成事件并保存到數據庫中;
(2)執行插樁后的原始并發程序,得到執行軌跡,一個執行軌跡是一個事件序列,表示為δ=<e1,e2,…ei,…,en>,其中每個事件ei包含下列屬性:
ti:事件ei所屬的線程;
mi:事件ei所存取的內存位置;
li:當事件ei執行時,其所擁有的鎖;
ai:事件ei的存取類型,包括讀,寫,獲取鎖,釋放鎖,等待,通知,創建線程和等待線程結束8種類型。
2.利用所得執行軌跡和預定義的原子區域模式確定原子性區域,并利用原子區域和原子違背的各種錯誤模式收集潛在的可能會引起不可序列化交織的事件序列:
(1)本發明中將每個synchronized方法,synchronized代碼塊以及鎖保護的代碼塊均看做原子區域;
執行軌跡中包含進入和退出synchronized方法,synchronized代碼塊和鎖保護區域的acquire和release事件,通過分析執行軌跡得到每個線程訪問每個鎖變量的<acquire,release>對序列,對于每個<acquire,release>事件對,定位acquire和release事件在對應線程執行軌跡中的位置,并將acquire和release事件的位置作為原子區域邊界;將每對原子區域邊界之間的事件序列看作一個原子區域;
(2)a,b,c三個事件,其中thread(a)=thread(b)≠thread(c),事件a,b屬于步驟21)所得的同一原子性區域,且這三個事件的讀寫類型符合某個原子違背模式中對應的事件讀寫類型,則事件a,b,c是一個潛在的可能會引起不可序列化交織的事件序列,收集這些潛在的可能會引起不可序列化交織的事件序列,對收集的這些事件序列,我們進行進一步探測是否存在執行軌跡能使得這些事件序列中的三個事件的執行順序符合不可序列化交織模式;
對每組由三個事件a,b,c組成的可能會引起不可序列化交織的事件序列進行快速檢查,判斷此事件序列是否滿足構成原子違背的前提條件,快速檢查的內容包括:檢查事件c和事件a,b是否被同一把鎖保護,事件c和事件a,b之間是否存在happened-before關系;若滿足這兩個條件的任意一條則表明事件c不會發生在事件a和b之間,即不會構成一個真正的原子違背,因此不需要對此事件序列建立約束。
3.約束的建立與求解,驗證步驟2得到的潛在的可能會引起不可序列化交織的事件序列是否是真正的原子違背;
為驗證步驟2得到的潛在的可能會引起不可序列化交織的事件序列是否是真正的原子違背,需求解是否存在執行軌跡能使所得事件序列中的三個事件的執行順序符合不可序列化交織模式,對步驟1)中得到的執行軌跡和步驟22)中得到的事件序列建立約束并求解,需要建立的約束等式有:happened-before約束、鎖互斥約束、原子違背約束,將原子違背的探測問題轉化為約束等式的求解問題。
(1)建立原子違背約束:
對步驟2中得到的事件序列建立原子違背約束,其中(a,c,b)是某個事件序列中的三個事件,其中thread(a)=thread(b)≠thread(c),且事件a,b來自同一原子性區域,約束內容主要分為兩部分:
(11)事件a,b,c執行的順序約束,在原子違背模式中要求事件c在事件事件a和事件b之間被執行,因此c在事件a和事件b之間被執行是此事件序列構成原子違背的必要條件,因此在求解出的執行軌跡中事件c要在事件a和事件b之間被執行;
(12)需要保證事件a,b,c在求解出的執行軌跡中一定會被執行,但不要求事件a,b,c讀寫的值與原執行軌跡中的事件a,b,c讀寫的值一樣;
由于不要求read和write事件讀寫特定的值,因此影響讀寫事件e的可行性因素除了Happened-before關系和鎖一致性要求以外,還有一些必須發生在e之前的分支(branch)事件;若這些branch事件是不可行的,則事件e也是不可行的,即在事件e在求解出的執行軌跡中不會執行,因此需要保證這些branch事件的可行性;
對每個讀寫事件e只需考慮每個線程距離事件e最近,且和e有偏序關系的branch事件的具體可行性,“具體”表示某事件在求解出的執行軌跡中所有屬性的值都和原執行軌跡中對應的事件相等;branch事件的可行性依賴于在同一線程內在branch事件之前的所有read事件,即約束branch事件所依賴的read事件的值在求解出的執行軌跡中與原執行軌跡中相等;branch事件的可行性約束進而轉化為對read事件可行性的約束,read事件的可行性約束要求read事件讀取的值與原執行軌跡中在此read事件之前發生、距離此read事件最近且與此read事件操作同一共享變量的write事件的值相同;
在對branch事件建立可行性約束時,若假定branch事件的可行性依賴于同一線程內部在branch事件之前所有的read事件,則會引入一些不必要的read事件的可行性約束;實際程序執行時,branch事件讀取的共享變量的值來自同一線程內在branch事件之前且離branch事件最近,讀同一共享共享變量的read事件的值;因此為確保branch事件讀寫共享變量的值不變,只需保證線程內在branch事件之前的所有read事件中,如果有多個read事件操作同一共享變量,則只需確保距離branch事件最近的read事件讀的值不變,而不需要所有的read事件讀的值不變;通過這種方法可以減少對于分支事件可行性建立約束的個數,從而減少約束求解的時間。
(2)約束求解
在本發明中我們借助約束求解器Z3實現約束的求解,將所有的約束組合并調用求解器求解方法,觀察對步驟2中得到的事件序列建立的約束求解是否有解,若有解則說明存在執行軌跡可以按照這種不可序列化交錯序列的順序執行事件序列中的三個事件,即此潛在的可能會引起不可序列化交織的事件序列是一個真實的原子違背。
以上所述僅是本發明的優選實施方式,應當指出,對于本技術領域的普通技術人員來說,在不脫離本發明原理的前提下,還可以做出若干改進和潤飾,這些改進和潤飾也應視為本發明的保護范圍。