天天看點

分享實錄 | 阿裡巴巴代碼缺陷檢測探索與實踐阿裡巴巴在缺陷檢測技術方面遇到的三個挑戰産品落地的要求業界和學術界較為流行的缺陷檢測手段和其局限性我們為什麼提出PRECFIX方法實作PRECFIX方法的技術細節

目前PRECFIX技術已經在阿裡巴巴集團内部落地并獲得好評;關于“PRECFIX”技術的論文被國際軟體工程大會(ICSE)收錄。

分享實錄 | 阿裡巴巴代碼缺陷檢測探索與實踐阿裡巴巴在缺陷檢測技術方面遇到的三個挑戰産品落地的要求業界和學術界較為流行的缺陷檢測手段和其局限性我們為什麼提出PRECFIX方法實作PRECFIX方法的技術細節

張昕東(别象) 阿裡巴巴 雲研發事業部 算法工程師

【以下為别象分享實錄】

阿裡巴巴在缺陷檢測技術方面遇到的三個挑戰

編碼是DevOps的重要一環,我所在的部門主要負責阿裡巴巴集團的代碼托管。在平台業務的背後,我們建設了一系列智能化能力用來賦能前線業務。依賴底層的代碼圖譜和離線數倉(離線資料倉庫)的資料能力,代碼智能衍生出了缺陷檢測、代碼生成、代碼克隆、代碼安全等能力。今天主要介紹一下我們在缺陷檢測領域的初步探索和實踐。

缺陷檢測和更新檔推薦幾十年來一直是軟體工程領域的難題,又是研究者和一線開發者最為關心的問題之一。這裡講的缺陷不是網絡漏洞、系統缺陷,而是隐藏在代碼中的缺陷,也就是程式員們戲稱的“八阿哥”(即BUG)。每位開發者都希望有一種智能的缺陷檢測技術來提升代碼品質,避免踩坑。所謂“最迷人的最危險”,如此令人着迷的技術自然有着重重阻礙。

在研究了現有的一些解決方法以及阿裡巴巴内部資料集的特征後,我們将缺陷檢測技術在阿裡巴巴産品落地上的挑戰歸納為三個方面:

分享實錄 | 阿裡巴巴代碼缺陷檢測探索與實踐阿裡巴巴在缺陷檢測技術方面遇到的三個挑戰産品落地的要求業界和學術界較為流行的缺陷檢測手段和其局限性我們為什麼提出PRECFIX方法實作PRECFIX方法的技術細節

複雜的業務環境

首先阿裡巴巴經濟體業務種類繁多,有底層系統中間件的代碼,有物流的代碼,也有安全、人工智能等各個領域的代碼,業務在變,代碼缺陷類型也在變。代碼資料隻增不減,代碼缺陷類型捉摸不透,缺陷檢測的困難不言自明。

以Java語言為例,學術界的Java缺陷公開資料集常用的是Defect4J。Defect4J包含6個代碼庫,有将近400個人工确認的缺陷和更新檔。這些代碼庫是比較基礎正常的代碼庫,缺陷種類容易劃分,一部分研究者也做了特定缺陷種類的研究,對症下藥效果尚可,然而換了一種缺陷類型,那麼檢測的效果就很難令人滿意了。

在阿裡巴巴資料集中,有衆多的缺陷類型難以定義,希望能有一種對缺陷類型泛化能力強的缺陷檢測與更新檔推薦的方法,不說“包治百病藥到病除”,但希望能夠适應不同的“病症”,提高代碼“免疫力”。

有限的輔助資源

第二大挑戰來源于有限的輔助資源,這也是導緻許多學術界相關成果無法直接複現利用的原因。

何謂輔助資源,常用者有三:測試用例,缺陷報告,缺陷标簽。

雖然大多數線上代碼都已經達到了很高的測試覆寫率,但是由于代碼品質參差,有一大部分代碼庫是缺乏測試用例的,我們也缺少足夠的缺陷報告去直接定位缺陷。我們也想嘗試過通過缺陷标簽來學習缺陷模式,然而自動打标簽的方法準确率不高,而人工給如此龐大的資料集打标簽是不太現實的。

産品落地的要求

而最難現實的是第三大挑戰,來自産品的落地要求。

作為一項技術,需要在産品中尋找落地的機會。而真實的落地又對技術有極高的要求:我們構想的主要落地場景是代碼評審中的缺陷靜态掃描及更新檔推薦。産品經理說:“檢測過程要高效,盡量不要給誤報,定位缺陷還不夠,更新檔方案還得讓使用者知道。”

業界和學術界較為流行的缺陷檢測手段和其局限性

搞研究做創新自然不能固步自封,閉門造車。我先來給大家簡單地介紹一些相關領域的一些現有成果。

主要從缺陷檢測,更新檔推薦,以及其他相關的技術應用三個方面做介紹。

缺陷定位技術

關于缺陷定位技術的這些歸納總結主要來自于熊英飛老師(北京大學新體制副教授)的論文。主要方法大類有:基于光譜的缺陷定位,基于突變的缺陷定位,堆棧分析等等。

分享實錄 | 阿裡巴巴代碼缺陷檢測探索與實踐阿裡巴巴在缺陷檢測技術方面遇到的三個挑戰産品落地的要求業界和學術界較為流行的缺陷檢測手段和其局限性我們為什麼提出PRECFIX方法實作PRECFIX方法的技術細節

比如基于光譜的缺陷定位是基于測試用例,通過的測試用例經過的代碼行給予正向分數,失敗的測試用例經過的代碼路徑給予負面分數,類似于光譜的形式将分數較低的一些代碼行歸類為潛在缺陷行。

這些缺陷定位手段大多關注特定缺陷,在定位某些特定缺陷時準确率明顯高于其它缺陷,比如Predicate Switching主要用于檢測條件語句中的bug。

第二個局限在于誤報率較高,以Defect4J資料集測試結果為例,以上方法中準确率最高的是基于光譜的定位,但是TOP1的命中率也隻有37%左右。有研究工作将這些各有所長的缺陷定位手段整合起來一起判斷,但誤報率仍然高于50%。

最重要的一點是,上述的缺陷定位手段不提供更新檔資訊,這一點在實際應用過程中是很緻命的,比如基于光譜的定位會傳回多個潛在缺陷行,但是沒有明确的修複方案,使用者會比較迷茫。

更新檔推薦技術

關于更新檔推薦技術,比較具有代表性的研究是Generate-and-validate approach,這種類型下的研究成果大體思路是基于失敗的測試用例,定位到代碼上下文,然後通過随機替換代碼元素,或基于語義不斷嘗試改變抽象文法樹上的結點,并利用測試用例或其它可驗證資訊去驗證修改的結果,直到測試用例或其他驗證手段跑通。

分享實錄 | 阿裡巴巴代碼缺陷檢測探索與實踐阿裡巴巴在缺陷檢測技術方面遇到的三個挑戰産品落地的要求業界和學術界較為流行的缺陷檢測手段和其局限性我們為什麼提出PRECFIX方法實作PRECFIX方法的技術細節

這些更新檔生成的方法主要有三大局限,首先是準确率低,主要展現在Overfitting(過度拟合)問題上,意思是生成的修複片段和現實中工程師實際的修複方式不同,有些修複甚至是面向測試用例的修複而不是面向真實缺陷的修複。左圖是某論文中一個Overfitting的例子,“Generate-and-validate”方法将if條件修改為了一個無意義的恒等于true的條件,使得該方法每次安全地return,這樣的修改确實能跑通測試用例,但是對真實的bug是無濟于事的。

第二個明顯的局限是耗時長,消耗的計算資源較多,這種修複方法往往是小時級的,而且他是基于編譯的,需要不斷地測試運作,效率較低。

此外,這種方法對測試用例完備性的要求非常高,它既考驗測試的覆寫率,又考驗了測試用例設計的合理性。

其它應用技術

還有一些缺陷檢測或更新檔推薦技術,可能大家有所耳聞,特别是Facebook和Google的,我也簡單地介紹下。

分享實錄 | 阿裡巴巴代碼缺陷檢測探索與實踐阿裡巴巴在缺陷檢測技術方面遇到的三個挑戰産品落地的要求業界和學術界較為流行的缺陷檢測手段和其局限性我們為什麼提出PRECFIX方法實作PRECFIX方法的技術細節

• Simfix和CBCD主要是基于缺陷報告的更新檔生成,利用代碼克隆把缺陷報告和更新檔遷移到新代碼上。

• Ubisoft的CLEVER首先基于特征做了commit級别的缺陷預測,對風險較大的一些commit做二次檢測,二次檢測的方法是将缺陷報告根據代碼的dependency聚類起來,然後做抽象文法樹的節點相似度比較,遊戲代碼往往有一些相似的缺陷。

• Bugram是将代碼解析成token序列,利用Ngram算法來預測出現某一個token的機率,機率低的token可能是個缺陷點,這種方法當代碼複雜度變高或代碼詞彙數量過大後,效果就急劇下降。

• Infer,Getafix,Sapfix都是Facebook提出的,做的都很不錯。Sapfix主要是針對移動手機的UI做類似Fuzzing的缺陷檢測,Infer主要針對代碼的NPE問題做了偏規則的檢查,是以準确率較高,Getafix是在Infer的檢測結果的基礎之上,對工程師修複的更新檔做了模式聚類,将常用的NPE修複模式統計生成出來。

• Tricorder和Findbugs等工具都是比較成熟的代碼檢測器,開發者可以基于這之上定制自己的檢測機制,但比較依賴規則的人工制定。

我們為什麼提出PRECFIX方法

經過調研後,我們發現外部的已有技術方法不能完全解決阿裡巴巴面臨的挑戰和問題,于是我們提出了PRECFIX方法(Patch Recommendation by Empirically Clustering)。

我們首先在阿裡巴巴資料集中複現了一個基于特征工程的commit(代碼送出)級别缺陷風險檢測,這個在之前講Ubisoft的Clever的時候有提過,具體方法是從代碼資料集中根據托管系統Git建立commit父子關系圖,利用改進的SZZ方法對commit進行自動打标簽,然後抽取出一部分特征如下所示,然後利用Xgboost 或者随機森林(Random Forest)對特征和标簽進行訓練,将模型用于commit風險的檢測。特征主要分為規模、代碼分布、目的、開發者經驗以及檔案修改五大次元,共14個子特征。

分享實錄 | 阿裡巴巴代碼缺陷檢測探索與實踐阿裡巴巴在缺陷檢測技術方面遇到的三個挑戰産品落地的要求業界和學術界較為流行的缺陷檢測手段和其局限性我們為什麼提出PRECFIX方法實作PRECFIX方法的技術細節

以SZZ算法作為标簽資料的模型在準确率上有瓶頸。SZZ算法雖然邏輯合理,在公開資料集上有比較好的表現,然而在我們的代碼資料集上,準确率不高,人工觀察了數百條SZZ算法标注的缺陷commit,其中僅有53%是真實的修複行為。“噪聲點”主要來自以下幾種場景:業務型的修複與代碼無關,注解日志的改動,測試類的調整,代碼風格的優化,代碼改動本身是用于“debug”的是以message中帶有“debug”資訊等等。而更進一步,僅有37%的修複型代碼改動可以遷移到新的代碼上,這也就意味着有些代碼改動雖然是真實的修複,但是由于改動量過于複雜,或者隻與特定環境,特定上下文相關,沒有可借鑒的價值。

通過對标簽資料的細緻分析,我們認為自動化的标簽不滿足我們的需求,而且打缺陷标簽對打标者的技術要求較高,對海量的代碼改動曆史打标簽也是不現實的。

我們開始不盲目尋找和複現方法,而是用心去感受和發現開發者在日常開發過程中的修複行為,我們總結了以下幾點:首先,借鑒于SZZ算法,commit message中往往包含了使用者的修複意圖,可以依據commit message來過濾出一部分資料。另外我們在調研SZZ算法資料時,發現75%的修複送出都有這樣的模式:删除一些缺陷代碼,然後新增一些代碼,比如修改了一個參數,在diff(差異檔案)中便是删除了一行,新增了一行。

分享實錄 | 阿裡巴巴代碼缺陷檢測探索與實踐阿裡巴巴在缺陷檢測技術方面遇到的三個挑戰産品落地的要求業界和學術界較為流行的缺陷檢測手段和其局限性我們為什麼提出PRECFIX方法實作PRECFIX方法的技術細節

還觀察到一個細節就是一個修複的操作往往涉及的檔案數不超過兩個,而一些不太規範的commit裡面含有大量的檔案,即使裡面包含了修複行為,也會被稀釋掉,引入不被歡迎的噪音。

同時我們也調研了在代碼評審階段使用者比較關心的缺陷,如故障點、重構點、代碼風格、性能問題等等,很多問題都有重複出現、重複修改的記錄。我們萌生了從海量的送出曆史中挖掘出重複常見的缺陷,防止開發者再次犯錯的想法。

于是我們提出了PRECFIX,Patch Recommendation by Empirically Clustering,也是這次ICSE收錄的論文中描述的方法,後期會在雲效産品中使用。其實思路方法比較直接簡潔,主要分為三步,首先從代碼送出資料中提取“缺陷修複對”,然後将相似的“缺陷修複對”聚類,最後對聚類結果進行模闆提取,這個缺陷檢測和更新檔推薦技術可以用于代碼評審,全庫離線掃描等等。使用者的回報以及我們人工的審查可以進一步提高模型推薦品質。

分享實錄 | 阿裡巴巴代碼缺陷檢測探索與實踐阿裡巴巴在缺陷檢測技術方面遇到的三個挑戰産品落地的要求業界和學術界較為流行的缺陷檢測手段和其局限性我們為什麼提出PRECFIX方法實作PRECFIX方法的技術細節

實作PRECFIX方法的技術細節

接下來我們聊一下實作PRECFIX方法的技術細節。首先是“缺陷修複對提取”。有朋友可能會有疑問,何為“缺陷修複對”?“缺陷修複對”如何提取?

分享實錄 | 阿裡巴巴代碼缺陷檢測探索與實踐阿裡巴巴在缺陷檢測技術方面遇到的三個挑戰産品落地的要求業界和學術界較為流行的缺陷檢測手段和其局限性我們為什麼提出PRECFIX方法實作PRECFIX方法的技術細節

缺陷修複對提取

這得先從幾個數字講起。SZZ算法利用Blame資訊去追溯引入缺陷的commit以及缺陷行,我們觀察發現,有25%的檔案的缺陷行源自多個檔案,這就意味着利用blame資訊去溯源可能會将一個缺陷追溯到兩個源頭,而将一個缺陷的代碼行一分為二很有可能是沒有意義的。

通過blame資訊去追溯缺陷代碼行不夠準确,而我們想要的缺陷相關的代碼上下文實際上就是這次修複型commit送出前該檔案最後一次送出的内容,我們可以直接通過本次送出的檔案和對應的diff還原出本次送出前的檔案内容。

我們發現,大多數的修複行為是以方法為機關的,是以我們提出了以方法為機關的“缺陷修複對”提取方法,即将方法體内的diff chunks(差異檔案區塊)合并,生成一個缺陷修複對。當然也可以不以方法體為範圍,直接以diff chunk為機關去提取缺陷修複對,這些都各有利弊,如果以diff chunk為機關去提取,那就不需要源代碼資訊了,直接解析diff即可。

在提取過程中有個小tips就是将缺陷片段和修複片段歸一化,比如将空格和換行符去掉,然後比較兩者,将相同的缺陷修複對過濾掉,這樣能過濾掉一部分代碼格式修改。

我們發現60%的commit僅包含了1-2個檔案,但也存在小部分的不規範commit包含了數十個甚至上百個檔案。如之前所說,我們認為一次修複行為關聯的檔案往往在三個以下,為了減小噪聲的引入,在提取缺陷修複對的過程中建立過濾機制。其實這個commit檔案數量的限制是準确率和召回率的權衡,在真實實踐中我們為了召回率略微放寬了限制,将門檻值設為了5。

通過SZZ算法标注的代碼缺陷47%不夠準确。我們沿用了SZZ的利用commit message的資料采集步驟,是以這個缺陷修複對的提取過程還是會存在大量的噪聲難以去除。我們想到了聚類,将常見的缺陷與更新檔聚類起來,總結成模闆,一些噪聲或沒有借鑒意義的缺陷修複會被自然地過濾。

缺陷修複對聚類

提取完缺陷修複對後,為了盡量減少噪音,并且我們的目的是提取共性缺陷修複記錄,于是采用了聚類的方法,将相似的缺陷修複對聚類在一起,得到一些共性的缺陷。

分享實錄 | 阿裡巴巴代碼缺陷檢測探索與實踐阿裡巴巴在缺陷檢測技術方面遇到的三個挑戰産品落地的要求業界和學術界較為流行的缺陷檢測手段和其局限性我們為什麼提出PRECFIX方法實作PRECFIX方法的技術細節

由于事前無法預測類簇數量,我們沒有使用Kmeans聚類算法,采用了目前比較成熟的基于密度的DBSCAN算法,當然也可以使用pairwise的比較和合并,也就是所有情況都比一遍。

聚類方式上,我們嘗試過很多種,有單獨聚類缺陷片段的,效果不錯,但是修複片段的分析成為了難點,因為同樣一段缺陷片段有不同的修複方案,很難自動化地分析。我們最後嘗試了同時聚類缺陷和修複片段,這樣聚類的方式可以在比對上缺陷片段時直接給出修複片段,不用再另外考慮如何做修複推薦。

直接使用DBSCAN效率較低,以我們的實驗資料量來講,大概需要70個小時。于是,我們在DBSCAN的基礎上做了一定的優化,主要有圖表上的幾種方式。我們基于MapReduce實作聚類,Mapper階段做缺陷修複對的預處理,Reducer階段跑DBSCAN。第一種優化方式是在Mapper階段采用KDTree或者SimHash算法将比較相近的缺陷修複對分發到一個Reducer中做并行聚類,時間性能大概提升了4倍。類簇損失率主要是和基礎版的DBSCAN算法相比,大概損失了6%。

大多數的缺陷修複對互相之間是沒有任何關聯的,而我們利用代碼克隆技術比較兩個片段又是最耗時的部分,圖上的APISEQ便是我們優化“不必要比較”的方法。我們洞察了這批缺陷修複對資料集,發現幾乎所有的片段都或多或少包含了方法調用,沒有方法調用的片段大機率是一些無意義的噪聲,是以我們可以在聚類比較的過程中先比較兩個片段是否含有相同的API,如果有的話再進行比較,通過這個方法時間性能又提高了四倍。

我們也嘗試了比較新穎的并行DBSCAN算法,速度非常快,但是類簇損失相對較大。這個資料處理的過程是定期的離線計算,頻率較低。最終權衡之下,我們選擇了耗時相對較短,損失率較小的KDTree或APISEQ+KDTREE的聚類方法。

至于聚類過程中的兩個片段的代碼克隆比較方式,我們發現兩種互補的計算方式的結果明顯優于單個計算方式,我們的最佳實踐是“編輯距離”和“Jaccard”的權重平均,因為“編輯距離”能夠捕捉到token(代碼元素)的順序關系,而Jaccard能計算token重合比例。

模版提取與比對

最後是“模版提取”:為了提升使用者體驗,我們希望将同一類簇的片段聚合起來提取出模闆,降低使用者的了解成本。

分享實錄 | 阿裡巴巴代碼缺陷檢測探索與實踐阿裡巴巴在缺陷檢測技術方面遇到的三個挑戰産品落地的要求業界和學術界較為流行的缺陷檢測手段和其局限性我們為什麼提出PRECFIX方法實作PRECFIX方法的技術細節

如上圖所示,同一類簇的兩個片段非常相似,我們先遞歸地使用最長子序列算法,黃色部分為比對的内容。一些不比對的内容除了左邊的片段多了一句以外,其他部分實際上是變量名不同,我們将不同的變量名分析提取出來,存儲為“@Para”的格式友善後期比對。

當掃描到新的缺陷片段時,我們基于模闆識别出它的變量名,并直接用新的變量名替換更新檔模闆中的“@Para”參數,然後自動推薦出帶有新參數的修複建議。

下面來看幾個PRECFIX聚類得到的模闆。第一大類是“合理性檢查”,修複片段做了長度的判斷,合理性檢查也包括了空值檢查。

第二個類是“API變更”, API的參數發生了改變,增加了Gpu id,第一個參數的來源也做了修改。API變更還包括了方法名的改動,參數的增删改,這是非常常見的類型。

還有一個大類是做檢視聚類結果之前沒想到的,就是“API封裝”,工程師往往會把功能獨立,經常複用的代碼段封裝起來,減少代碼重複度和維護成本,而且工具類會将方法寫的比較完善,減少開發者在編寫時産生的不必要的失誤。

當然Precfix也不是代碼缺陷的特效藥,隻是提供了一種從代碼庫中挖掘缺陷的思路。模闆數量和誤報率需要持續地跟進和維護。

分享實錄 | 阿裡巴巴代碼缺陷檢測探索與實踐阿裡巴巴在缺陷檢測技術方面遇到的三個挑戰産品落地的要求業界和學術界較為流行的缺陷檢測手段和其局限性我們為什麼提出PRECFIX方法實作PRECFIX方法的技術細節

PRECFIX方法已經在阿裡巴巴集團内部落地,在内部公開庫中掃描出了800多種缺陷類型,3萬多個缺陷,并将結果對使用者進行了訪談,獲得了普遍的好評。後續,該方法也會在“雲效”産品中應用,供更多開發者使用。

以上内容來自别象在“雲效開發者交流群”中的視訊直播課程,您可以釘釘搜尋群号(23362009)入群,收看視訊回放。

分享實錄 | 阿裡巴巴代碼缺陷檢測探索與實踐阿裡巴巴在缺陷檢測技術方面遇到的三個挑戰産品落地的要求業界和學術界較為流行的缺陷檢測手段和其局限性我們為什麼提出PRECFIX方法實作PRECFIX方法的技術細節

關于雲效:

雲效,企業級一站式DevOps平台,源于阿裡巴巴先進的管理理念和工程實踐,緻力于成為數字企業的研發效能引擎!雲效提供從“需求 ->開發->測試->釋出->運維->營運”端到端的線上協同服務和研發工具,通過人工智能、雲原生技術的應用助力開發者提升研發效能,持續傳遞有效價值。