一種基于cfg的異常信息建立方法
【專利摘要】本發(fā)明公開了一種基于CFG的異常信息建立方法,是應(yīng)用于C++的異常處理代碼中,所述異常處理代碼中包含try塊和對應(yīng)的一個或多個catch處理塊;其特征在于:通過GCC編譯器提供的插件功能獲得初步的異常信息,結(jié)合源代碼的插樁技術(shù),以獲得完整的異常信息。本發(fā)明是對靜態(tài)分析的一次很好補充,通過識別并構(gòu)建程序已有的異常信息,為靜態(tài)源代碼分析做準(zhǔn)備。
【專利說明】一種基于CFG的異常信息建立方法
【技術(shù)領(lǐng)域】
[0001] 本發(fā)明屬于C++靜態(tài)源代碼分析領(lǐng)域,具體地說識別并構(gòu)建C++源代碼的異常信 息,為靜態(tài)源代碼分析作準(zhǔn)備。
【背景技術(shù)】
[0002] 異常機(jī)制是C++非常有用的特性,它涉及大量底層操作,是C++機(jī)制中比較難理解 和掌握的部分,目前理解語言本身的最好手段是編譯器,編譯器內(nèi)部維護(hù)了語言包含的語 義信息,但編譯器為了統(tǒng)一不同語言的中間表示,用自己的一套語言定義了中間代碼。CFG 簡稱控制流圖,由編譯器生成的包含bb基本塊的數(shù)據(jù)結(jié)構(gòu);作為編譯器優(yōu)化的基礎(chǔ),它貼 近真實語言(C/C++)的語義,維護(hù)著底層機(jī)器能理解的流程圖信息,包括C++異常機(jī)制的某 些信息,是源代碼靜態(tài)語義分析的基礎(chǔ)。
[0003] 由于CFG內(nèi)部維護(hù)的異常信息不直觀,單從函數(shù)對應(yīng)的CFG來看,不清楚該CFG的 異常信息中try代碼塊和對應(yīng)catch處理代碼塊之間的關(guān)系,另外不能簡單地通過GCC編 譯器提供的插件功能獲取完整的異常信息,因此需要以CFG圖和源代碼為基礎(chǔ)手動構(gòu)建還 原異常信息,以便為靜態(tài)源代碼分析作準(zhǔn)備。
[0004] 目前關(guān)于C++異常機(jī)制的靜態(tài)源代碼分析包括商業(yè)工具PC-Lint和coverity, PC-Iint從源碼角度提供潛在的異常錯誤可能,包括不一致的異常說明符,catch參數(shù)不是 引用的情況;coverity聲稱能發(fā)現(xiàn)源代碼異常信息中未處理的異常;這兩個工具只是分析 源代碼異常信息的局部問題,但都沒有給出如何完整地得知異常信息,對開發(fā)者獲悉程序 里所有的異常信息帶來困難。
【發(fā)明內(nèi)容】
[0005] 本發(fā)明為克服現(xiàn)有技術(shù)存在的不足之處,提出一種基于CFG的異常信息建立方 法,以期能補充編譯器插件功能的不足,并指出異常信息中try-catch代碼塊之間的嵌套 關(guān)系,從而準(zhǔn)確快速地得獲得C++程序里的異常信息。
[0006] 本發(fā)明為解決技術(shù)問題采用如下技術(shù)方案:
[0007] 本發(fā)明一種基于CFG的異常信息建立方法,是應(yīng)用于C++的異常處理代碼中,所述 異常處理代碼中包含try塊和對應(yīng)的一個或多個catch處理塊;其特點是,所述異常信息建 立方法是按如下步驟進(jìn)行:
[0008] 步驟1、通過插樁方法在所述異常處理代碼中所有try塊的開始位置進(jìn)行標(biāo)記,從 而獲得包含標(biāo)記信息的插樁代碼;
[0009] 步驟2、將所述插樁代碼進(jìn)行編譯,獲得以CFG表示的中間代碼,在所述中間代碼 中根據(jù)所述標(biāo)記信息,提取所有try塊的開始位置,從而形成只包含所述開始位置的try塊 結(jié)點組成的鏈表,并設(shè)為TRY_LIST初始鏈表;
[0010] 步驟3、遍歷所述間代碼中所有catch處理塊,根據(jù)每個catch處理塊自身的開始 位置和結(jié)束位置進(jìn)行提取,從而形成包含開始位置和結(jié)束位置的catch處理塊結(jié)點組成的 鏈表,并設(shè)為CATCH_LIST鏈表;
[0011] 步驟4、遍歷所述CATCH_LIST鏈表,根據(jù)所述CATCH_LIST鏈表中每個catch塊結(jié) 點的開始位置附帶的編號,提取出所有具有相同編號的catch處理塊結(jié)點組織成一個子鏈 表,從而生成catch處理塊列表,所述catch處理塊列表中的每個列表結(jié)點都指向各自具有 相同編號的子鏈表;
[0012] 步驟5、以所述catch處理塊列表中的編號作為關(guān)鍵字對每個列表結(jié)點按從小到 大的順序進(jìn)行排序,形成排序后的catch處理塊列表;
[0013] 步驟6、將所述排序后的catch處理塊列表中的每個列表結(jié)點與所述TRY_LIST初 始鏈表中的每個try塊結(jié)點依次進(jìn)行對應(yīng),使得一個列表結(jié)點只對應(yīng)一個try塊結(jié)點,從而 獲得對應(yīng)后的catch處理塊列表;
[0014] 步驟7、遍歷所述對應(yīng)后的catch處理塊列表,判斷所述子鏈表中是否有一個 catch處理塊結(jié)點的結(jié)束位置包含自身的跳轉(zhuǎn)信息,若有,則根據(jù)所述跳轉(zhuǎn)信息獲得與所述 列表結(jié)點對應(yīng)的try塊結(jié)點的結(jié)束位置;否則,將與所述列表結(jié)點對應(yīng)的try塊的自身結(jié)束 位置標(biāo)記為記號…;從而獲得所有包含開始位置和結(jié)束位置的TRY_LIST鏈表,由所述對應(yīng) 后的catch處理塊列表和所述TRY_LIST鏈表建立try-catch的初步異常信息;
[0015] 步驟8、假設(shè)所述TRY_LIST鏈表中包含有n個try結(jié)點,記為X= UpX2,…,Xi,… ,xn},Xi表示任一 try結(jié)點,1彡i彡n ;將所述任一 try結(jié)點Xi的開始位置和結(jié)束位置分別 記為x丨和右;
[0016] 步驟9、遍歷所述TRY_LIST鏈表的每個try結(jié)點,判斷當(dāng)前遍歷的try結(jié)點Xi是 否為空;若是,則表示所述TRY_LIST鏈表中try結(jié)點之間的父子關(guān)系建立完成,從而使得所 述初步異常信息生成完整異常信息,并執(zhí)行步驟11 ;否則,執(zhí)行步驟10 ;
[0017] 步驟10、判斷try結(jié)點Xj是否為空,i+1彡j彡n ;若為空,則將i+1的值賦給i, 并執(zhí)行步驟9 ;否則,判斷try結(jié)點Xi的結(jié)束位置<是否包含記號…,若包含,則將i+1的 值賦給i,并執(zhí)行步驟9 ;否則,判斷try結(jié)點的結(jié)束位置<是否包含記號…,若包含,則 將j+1的值賦給j,并執(zhí)行步驟10 ;否則,將try結(jié)點Xi的開始位置<和結(jié)束位置<分別與 try結(jié)點xi+1的開始位置'和結(jié)束位置A依次進(jìn)行比較,若 < <<且,則將try結(jié) 點Xi作為try結(jié)點Xj的父結(jié)點,若< 2^)且< <,則將try結(jié)點Xj作為try結(jié)點Xi的父 結(jié)點;將j+1的值賦給j,并執(zhí)行步驟10 ;
[0018] 步驟11、以所述完整異常信息作為所述異常代碼對應(yīng)的異常信息。
[0019] 與現(xiàn)有技術(shù)相比,本發(fā)明的有益效果在于:
[0020] 本發(fā)明通過源代碼插樁,解決了以CFG表示的中間代碼中不能定位try開始位置 的問題;通過編譯器技術(shù),保持了源程序完整的語義,維護(hù)了一個準(zhǔn)確的異常信息;通過簡 單的排序算法,維護(hù)了源程序中自上而下的try-catch處理代碼的關(guān)系;通過不同區(qū)間的 開始位置和結(jié)束位置之間的關(guān)系,解決了 try-catch處理代碼之間的嵌套關(guān)系;經(jīng)測試,采 用本發(fā)明方法能快速并準(zhǔn)確的維護(hù)了 C++程序里的所有異常信息。
【專利附圖】
【附圖說明】
[0021] 圖1為本發(fā)明C++程序中異常源代碼的示例圖;
[0022] 圖2為本發(fā)明通過編譯器生成的代碼示例圖;
[0023] 圖3為本發(fā)明初始化的TRY_LIST鏈表;
[0024] 圖4為本發(fā)明CATCH_LIST鏈表;
[0025] 圖5為本發(fā)明排序后的catch處理塊列表;
[0026] 圖6為本發(fā)明最終完整異常信息示意圖。
【具體實施方式】
[0027] 本發(fā)明基于以CFG表示的中間代碼為基礎(chǔ),通過CFG生成的異常處理部分,還原生 成每個函數(shù)的異常處理數(shù)據(jù)結(jié)構(gòu),以便執(zhí)行異常處理代碼部分;通過GCC編譯器提供的插 件功能獲得初步的異常信息,結(jié)合源代碼的插樁技術(shù),探索出一套完整的異常信息識別和 建立方法,以獲得完整的異常信息;對于核心代碼包括異常信息中try代碼塊和catch代碼 處理塊之間對應(yīng)關(guān)系的獲得,以及try-catch代碼塊之間的嵌套關(guān)系。本發(fā)明是對靜態(tài)分 析的一次很好補充,通過識別并構(gòu)建程序已有的異常信息,從而在程序運行之前獲得可能 的異常發(fā)生過程,為靜態(tài)源代碼分析做準(zhǔn)備。
[0028] 具體地,一種基于CFG的異常信息建立方法是按如下過程進(jìn)行:
[0029] 步驟1、通過插樁方法在所述異常處理代碼中所有try塊的開始位置進(jìn)行標(biāo)記,從 而獲得包含標(biāo)記信息的插樁代碼;
[0030] 步驟2、將所述插樁代碼進(jìn)行編譯,獲得以CFG表示的中間代碼,在所述中間代碼 中根據(jù)所述標(biāo)記信息,提取所有try塊的開始位置,從而形成只包含所述開始位置的try塊 結(jié)點組成的鏈表,并設(shè)為TRY_LIST初始鏈表;
[0031] 步驟3、遍歷所述間代碼中所有catch處理塊,根據(jù)每個catch處理塊自身的開始 位置和結(jié)束位置進(jìn)行提取,從而形成包含開始位置和結(jié)束位置的catch處理塊結(jié)點組成的 鏈表,并設(shè)為CATCH_LIST鏈表;
[0032] 步驟4、遍歷所述CATCH_LIST鏈表,根據(jù)所述CATCH_LIST鏈表中每個catch塊結(jié) 點的開始位置附帶的編號,提取出所有具有相同編號的catch處理塊結(jié)點組織成一個子鏈 表,從而生成catch處理塊列表,所述catch處理塊列表中的每個列表結(jié)點都指向各自具有 相同編號的子鏈表;
[0033] 步驟5、以所述catch處理塊列表中的編號作為關(guān)鍵字對每個列表結(jié)點按從小到 大的順序進(jìn)行排序,形成排序后的catch處理塊列表;
[0034] 步驟6、將所述排序后的catch處理塊列表中的每個列表結(jié)點與所述TRY_LIST初 始鏈表中的每個try塊結(jié)點依次進(jìn)行對應(yīng),使得一個列表結(jié)點只對應(yīng)一個try塊結(jié)點,從而 獲得對應(yīng)后的catch處理塊列表;
[0035] 步驟7、遍歷所述對應(yīng)后的catch處理塊列表,判斷所述子鏈表中是否有一個 catch處理塊結(jié)點的結(jié)束位置包含自身的跳轉(zhuǎn)信息,若有,則根據(jù)所述跳轉(zhuǎn)信息獲得與所述 列表結(jié)點對應(yīng)的try塊結(jié)點的結(jié)束位置;否則,將與所述列表結(jié)點對應(yīng)的try塊的自身結(jié)束 位置標(biāo)記為記號…;從而獲得所有包含開始位置和結(jié)束位置的TRY_LIST鏈表,由所述對應(yīng) 后的catch處理塊列表和所述TRY_LIST鏈表建立try-catch的初步異常信息;
[0036] 步驟8、假設(shè)所述TRY_LIST鏈表中包含有n個try結(jié)點,記為X= Ix1, X2,…,Xi,… ,xn},Xi表示任一 try結(jié)點,1彡i彡n ;將所述任一 try結(jié)點Xi的開始位置和結(jié)束位置分別 記為右和xf;
[0037] 步驟9、遍歷所述TRY_LIST鏈表的每個try結(jié)點,判斷當(dāng)前遍歷的try結(jié)點Xi是 否為空;若是,則表示所述TRY_LIST鏈表中try結(jié)點之間的父子關(guān)系建立完成,從而使得所 述初步異常信息生成完整異常信息,并執(zhí)行步驟11 ;否則,執(zhí)行步驟10 ;
[0038] 步驟10、判斷try結(jié)點Xj是否為空,i+1彡j彡n ;若為空,則將i+1的值賦給i, 并執(zhí)行步驟9 ;否則,判斷try結(jié)點Xi的結(jié)束位置<是否包含記號…,若包含,則將i+1的值 賦給i,并執(zhí)行步驟9 ;否則,判斷try結(jié)點&的結(jié)束位置<是否包含記號…,若包含,則將 j+1的值賦給j,并執(zhí)行步驟10 ;否則,將try結(jié)點Xi的開始位置右和結(jié)束位置右分別與try結(jié)點xi+1的開始位置和結(jié)束位置依次進(jìn)行比較,若<<<且則將try結(jié)點Xi 作為try結(jié)點?的父結(jié)點,若且<<<,則將try結(jié)點?作為try結(jié)點Xi的父結(jié)點; 將j+1的值賦給j,并執(zhí)行步驟10 ;
[0039] 步驟11、以所述完整異常信息作為所述異常代碼對應(yīng)的異常信息。
[0040] 本實施例中,為了方便闡述,以簡單的C++程序中異常源代碼為例如圖1所示;其 中,最左邊的一列表示行數(shù);圖1結(jié)構(gòu)中包含嵌套的try-catch代碼塊,第一個try代碼塊 中包含第二個try代碼塊,每個try代碼塊對應(yīng)兩個catch處理塊。
[0041] 圖1的代碼通過編譯器生成的以CFG表示的中間代碼大概結(jié)構(gòu)為如圖2中未加斜 體部分的代碼,實質(zhì)上該結(jié)果里分為兩部分,上部分為包含try的正常代碼塊,下部分為所 有的catch處理代碼塊。
[0042] 首先我們處理包含try的正常代碼塊,從圖2中未加斜體部分的代碼可知編譯后 生成的結(jié)果已沒有了源代碼中的try關(guān)鍵字,因此需要在源代碼中插樁代碼,即通過步驟 1,在圖1的(1)、(2)位置之前插入如下代碼:{cout〈〈 "try begin";},該代碼表示try的 開始位置,這樣圖2即為插樁后生成的以CFG表示的中間代碼。從圖2中斜體部分的代碼 可標(biāo)識try的開始位置,形成初始化TRY_LIST鏈表,如圖3所示,圖3即為步驟2的操作結(jié) 果。
[0043] 圖3中初始化TRY_LIST鏈表的每個結(jié)點中的開始位置用插樁代碼對應(yīng)所在bb塊 的數(shù)字編號來代替(如在圖2中出現(xiàn)"<bb 2>"時,表示bb塊的數(shù)字編號為2),這樣為步驟 10做準(zhǔn)備。
[0044] 接下處理圖2中所有的catch處理代碼塊,根據(jù)步驟3,通過每個catch處理塊的 開始位置和結(jié)束位置,形成如圖4的CATCH_LIST鏈表,該鏈表里的每個結(jié)點在開始位置附 帶了編號(如在圖2中第12行出現(xiàn)的"_builtin_eh_pointer (2) ",表示附帶的編號為2), 在結(jié)束位置附帶了跳轉(zhuǎn)信息(若有的話,如圖2中第17行出現(xiàn)的"goto〈bb 5>",表示跳轉(zhuǎn) 到第5個bb塊,以數(shù)字5來表示)。
[0045] 遍歷CATCH_LIST鏈表,根據(jù)步驟4和步驟5,以CATCH_LIST鏈表中每個結(jié)點的開 始位置附帶的編號為關(guān)鍵字,按照從小到大順序,形成排序后的catch處理塊列表,如圖5, catch處理塊列表的每個結(jié)點包含了帶數(shù)字的編號和指向catch處理塊子鏈表。
[0046] 根據(jù)步驟6,實質(zhì)上獲得了圖5和圖3中每個結(jié)點之間一一對應(yīng)。
[0047] 根據(jù)步驟7,可確定初始化的TRY_LIST鏈表中每個結(jié)點的結(jié)束位置,并最終形成 了包含開始位置和結(jié)束位置的TRY_LIST鏈表。由步驟6和步驟7可形成了 try-catch的 初步異常信息,如圖6中未加虛線的部分。
[0048] 根據(jù)步驟8、步驟9和步驟10的形式化描述,判斷try 1結(jié)點和try 2結(jié)點的位置 區(qū)間的關(guān)系,由于3>2并且55,因此try 2結(jié)點的父結(jié)點指向try 1結(jié)點,如圖6中添加的 虛線部分,表明了 try 2結(jié)點是嵌套在try 1結(jié)點內(nèi)。
[0049] 圖6中可由TRY_LIST鏈表中每個結(jié)點的開始位置和結(jié)束位置獲得每個try代碼 塊對應(yīng)圖2中的try代碼分布,以及try代碼塊之間的嵌套關(guān)系;由catch處理塊列表獲得 每個catch處理代碼塊對應(yīng)圖2中的catch代碼分布,這樣形成了圖1中的代碼對應(yīng)的最 終完整的異常信息。
[0050] 針對實際項目中更復(fù)雜的C++代碼,經(jīng)過編譯器編譯后生成的以CFG表示的中間 代碼,本質(zhì)上與圖2的結(jié)果在框架上是類似的。因此,綜合使用本發(fā)明的基于CFG的異常信 息建立方法后,經(jīng)測試,針對任何C++開發(fā)的工程代碼,都能快速并準(zhǔn)確的維護(hù)了 C++程序 里的所有異常信息。
【權(quán)利要求】
1. 一種基于CFG的異常信息建立方法,是應(yīng)用于C++的異常處理代碼中,所述異常處理 代碼中包含try塊和對應(yīng)的一個或多個catch處理塊;其特征是,所述異常信息建立方法是 按如下步驟進(jìn)行: 步驟1、通過插樁方法在所述異常處理代碼中所有try塊的開始位置進(jìn)行標(biāo)記,從而獲 得包含標(biāo)記信息的插樁代碼; 步驟2、將所述插樁代碼進(jìn)行編譯,獲得以CFG表示的中間代碼,在所述中間代碼中根 據(jù)所述標(biāo)記信息,提取所有try塊的開始位置,從而形成只包含所述開始位置的try塊結(jié)點 組成的鏈表,并設(shè)為TRY_LIST初始鏈表; 步驟3、遍歷所述間代碼中所有catch處理塊,根據(jù)每個catch處理塊自身的開始位 置和結(jié)束位置進(jìn)行提取,從而形成包含開始位置和結(jié)束位置的catch處理塊結(jié)點組成的鏈 表,并設(shè)為CATCH_LIST鏈表; 步驟4、遍歷所述CATCH_LIST鏈表,根據(jù)所述CATCH_LIST鏈表中每個catch塊結(jié)點的 開始位置附帶的編號,提取出所有具有相同編號的catch處理塊結(jié)點組織成一個子鏈表, 從而生成catch處理塊列表,所述catch處理塊列表中的每個列表結(jié)點都指向各自具有相 同編號的子鏈表; 步驟5、以所述catch處理塊列表中的編號作為關(guān)鍵字對每個列表結(jié)點按從小到大的 順序進(jìn)行排序,形成排序后的catch處理塊列表; 步驟6、將所述排序后的catch處理塊列表中的每個列表結(jié)點與所述TRY_LIST初始鏈 表中的每個try塊結(jié)點依次進(jìn)行對應(yīng),使得一個列表結(jié)點只對應(yīng)一個try塊結(jié)點,從而獲得 對應(yīng)后的catch處理塊列表; 步驟7、遍歷所述對應(yīng)后的catch處理塊列表,判斷所述子鏈表中是否有一個catch處 理塊結(jié)點的結(jié)束位置包含自身的跳轉(zhuǎn)信息,若有,則根據(jù)所述跳轉(zhuǎn)信息獲得與所述列表結(jié) 點對應(yīng)的try塊結(jié)點的結(jié)束位置;否則,將與所述列表結(jié)點對應(yīng)的try塊的自身結(jié)束位置 標(biāo)記為記號;從而獲得所有包含開始位置和結(jié)束位置的TRY_LIST鏈表,由所述對應(yīng)后的 catch處理塊列表和所述TRY_LIST鏈表建立try-catch的初步異常信息; 步驟8、假設(shè)所述TRY_LIST鏈表中包含有n個try結(jié)點,記為X={xpx2,…,Xi,…,xn},Xi表示任一try結(jié)點,1彡i彡n;將所述任一try結(jié)點Xi的開始位置和結(jié)束位置分別記為 xf' 和X,"; 步驟9、遍歷所述TRY_LIST鏈表的每個try結(jié)點,判斷當(dāng)前遍歷的try結(jié)點Xi是否為 空;若是,則表示所述TRY_LIST鏈表中try結(jié)點之間的父子關(guān)系建立完成,從而使得所述初 步異常信息生成完整異常信息,并執(zhí)行步驟11 ;否則,執(zhí)行步驟10 ; 步驟10、判斷try結(jié)點&是否為空,i+1彡j彡n;若為空,則將i+1的值賦給i,并執(zhí) 行步驟9 ;否則,判斷try結(jié)點Xi的結(jié)束位置是否包含記號…,若包含,則將i+1的值賦給 i,并執(zhí)行步驟9;否則,判斷try結(jié)點&的結(jié)束位置<是否包含記號…,若包含,則將j+1的 值賦給j,并執(zhí)行步驟10 ;否則,將try結(jié)點Xi的開始位置<和結(jié)束位置右分別與try結(jié)點 xi+1的開始位置<+1和結(jié)束位置'依次進(jìn)行比較,若 < < < 且,則將try結(jié)點Xi作為 try結(jié)點Xj的父結(jié)點,若< 丨且;vf ,則將try結(jié)點Xj作為try結(jié)點Xi的父結(jié)點;將 j+1的值賦給j,并執(zhí)行步驟10 ; 步驟11、以所述完整異常信息作為所述異常代碼對應(yīng)的異常信息。
【文檔編號】G06F9/44GK104407858SQ201410658922
【公開日】2015年3月11日 申請日期:2014年11月18日 優(yōu)先權(quán)日:2014年11月18日
【發(fā)明者】顧乃杰, 黃理, 任開新, 杜云開 申請人:合肥康捷信息科技有限公司