測(cè)試(三十八)——面向?qū)ο罄^承體系的靜態(tài)測(cè)試技術(shù):虛函數(shù)調(diào)用解析與多態(tài)路徑覆蓋)
?? 我的個(gè)人專(zhuān)欄《智能軟件工程AI4SE》《嵌入式面試總結(jié)》《嵌入式處理器架構(gòu)解析》《嵌入式與虛擬化》《嵌入式軟件測(cè)試》 Simplicity is the ultimate sophistication摘要本文面向面向?qū)ο笄度胧杰浖撵o態(tài)測(cè)試場(chǎng)景圍繞虛函數(shù)調(diào)用解析與多態(tài)路徑覆蓋兩大核心技術(shù)展開(kāi)。文章首先介紹虛函數(shù)調(diào)用解析的基本原理說(shuō)明如何依據(jù)靜態(tài)類(lèi)型、構(gòu)造路徑與類(lèi)型轉(zhuǎn)換信息推斷動(dòng)態(tài)綁定目標(biāo)隨后系統(tǒng)梳理調(diào)用點(diǎn)覆蓋、綁定目標(biāo)覆蓋與組合路徑覆蓋三種多態(tài)路徑覆蓋策略并通過(guò)對(duì)比表格給出選型建議。在此基礎(chǔ)上文章闡述增強(qiáng)調(diào)用圖的構(gòu)建過(guò)程結(jié)合多個(gè)連續(xù)虛函數(shù)調(diào)用的 C 示例演示候選綁定目標(biāo)集合的生成與組合路徑覆蓋流程最后介紹覆蓋度度量指標(biāo)、報(bào)告方式及工程實(shí)踐中的注意事項(xiàng)為多態(tài)代碼的靜態(tài)測(cè)試充分性提升提供完整參考。1. 引言在面向?qū)ο笄度胧杰浖欣^承與多態(tài)是提升代碼復(fù)用性和可維護(hù)性的重要手段但也給靜態(tài)測(cè)試帶來(lái)了顯著挑戰(zhàn)。虛函數(shù)調(diào)用在運(yùn)行時(shí)才確定具體實(shí)現(xiàn)導(dǎo)致靜態(tài)分析難以準(zhǔn)確判斷實(shí)際執(zhí)行路徑。本文圍繞虛函數(shù)調(diào)用解析與多態(tài)路徑覆蓋兩大核心技術(shù)展開(kāi)介紹如何在靜態(tài)測(cè)試階段識(shí)別多態(tài)行為、構(gòu)建調(diào)用圖并實(shí)現(xiàn)路徑覆蓋。2. 虛函數(shù)調(diào)用解析的基本原理虛函數(shù)調(diào)用解析的目標(biāo)是在編譯或靜態(tài)分析階段盡可能準(zhǔn)確地推斷出虛函數(shù)在運(yùn)行時(shí)的實(shí)際綁定目標(biāo)。其核心依據(jù)包括對(duì)象的靜態(tài)類(lèi)型、構(gòu)造路徑、賦值關(guān)系以及類(lèi)型轉(zhuǎn)換信息。在嵌入式 C 代碼中虛函數(shù)調(diào)用通常通過(guò)虛函數(shù)表vtable間接完成。靜態(tài)分析工具需要結(jié)合以下信息進(jìn)行解析對(duì)象聲明類(lèi)型變量聲明時(shí)的靜態(tài)類(lèi)型決定了可調(diào)用的虛函數(shù)集合。構(gòu)造與賦值路徑對(duì)象實(shí)際指向的動(dòng)態(tài)類(lèi)型往往由構(gòu)造調(diào)用或賦值語(yǔ)句決定。類(lèi)型轉(zhuǎn)換向上或向下轉(zhuǎn)型會(huì)影響虛函數(shù)綁定的準(zhǔn)確性。當(dāng)靜態(tài)分析無(wú)法唯一確定調(diào)用目標(biāo)時(shí)會(huì)生成一個(gè)候選集合供后續(xù)路徑覆蓋分析使用。3. 多態(tài)路徑覆蓋的核心策略多態(tài)路徑覆蓋要求在靜態(tài)測(cè)試中覆蓋虛函數(shù)在不同動(dòng)態(tài)類(lèi)型下的執(zhí)行路徑。與普通路徑覆蓋相比它需要額外考慮每個(gè)調(diào)用點(diǎn)的候選目標(biāo)集合。常用的覆蓋策略包括調(diào)用點(diǎn)覆蓋確保每個(gè)虛函數(shù)調(diào)用點(diǎn)至少被解析到一次。綁定目標(biāo)覆蓋對(duì)每個(gè)調(diào)用點(diǎn)覆蓋其所有可能的動(dòng)態(tài)綁定目標(biāo)。組合路徑覆蓋在存在多個(gè)連續(xù)虛調(diào)用時(shí)覆蓋不同綁定組合形成的路徑。在實(shí)際工程中受限于狀態(tài)空間爆炸問(wèn)題通常采用基于約束求解的符號(hào)執(zhí)行方法對(duì)候選目標(biāo)進(jìn)行篩選和剪枝。下表從覆蓋粒度、適用場(chǎng)景、實(shí)現(xiàn)復(fù)雜度與典型工程代價(jià)四個(gè)維度對(duì)三種多態(tài)路徑覆蓋策略進(jìn)行橫向?qū)Ρ?。策略覆蓋粒度適用場(chǎng)景實(shí)現(xiàn)復(fù)雜度典型工程代價(jià)調(diào)用點(diǎn)覆蓋以虛函數(shù)調(diào)用點(diǎn)為粒度只要求每個(gè)調(diào)用點(diǎn)至少被解析一次快速建立多態(tài)代碼的基礎(chǔ)覆蓋基線適合資源受限或大規(guī)模代碼庫(kù)的初步篩查低分析開(kāi)銷(xiāo)小但無(wú)法驗(yàn)證不同動(dòng)態(tài)類(lèi)型下的分支行為漏檢風(fēng)險(xiǎn)較高綁定目標(biāo)覆蓋以動(dòng)態(tài)綁定目標(biāo)為粒度要求每個(gè)調(diào)用點(diǎn)的所有候選目標(biāo)均被覆蓋需要驗(yàn)證不同派生類(lèi)實(shí)現(xiàn)是否都被執(zhí)行適合對(duì)多態(tài)行為正確性要求較高的模塊中需要維護(hù)候選目標(biāo)集合并構(gòu)造對(duì)應(yīng)動(dòng)態(tài)類(lèi)型測(cè)試用例數(shù)量隨候選目標(biāo)數(shù)增長(zhǎng)組合路徑覆蓋以連續(xù)虛調(diào)用形成的組合路徑為粒度覆蓋不同綁定組合的執(zhí)行序列存在多個(gè)連續(xù)虛調(diào)用且相互影響時(shí)用于發(fā)現(xiàn)組合狀態(tài)下的缺陷適合復(fù)雜狀態(tài)機(jī)或協(xié)議處理邏輯高組合數(shù)量呈指數(shù)增長(zhǎng)通常需要借助符號(hào)執(zhí)行與約束求解進(jìn)行剪枝分析時(shí)間和內(nèi)存消耗顯著選型建議在工程落地時(shí)建議以調(diào)用點(diǎn)覆蓋作為基礎(chǔ)門(mén)檻優(yōu)先保證所有虛調(diào)用點(diǎn)均被解析在關(guān)鍵模塊或缺陷高發(fā)區(qū)域進(jìn)一步采用綁定目標(biāo)覆蓋以驗(yàn)證各派生類(lèi)實(shí)現(xiàn)僅當(dāng)存在連續(xù)虛調(diào)用且組合行為直接影響正確性時(shí)才引入組合路徑覆蓋并配合符號(hào)執(zhí)行控制狀態(tài)空間規(guī)模。整體上應(yīng)遵循由低到高的覆蓋粒度遞進(jìn)策略在測(cè)試充分性與分析成本之間取得平衡。4. 靜態(tài)分析中的調(diào)用圖構(gòu)建調(diào)用圖是虛函數(shù)解析的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)。在繼承體系中調(diào)用圖需要區(qū)分聲明調(diào)用邊和實(shí)際綁定邊。構(gòu)建過(guò)程一般分為以下步驟掃描所有函數(shù)定義提取普通函數(shù)調(diào)用關(guān)系。識(shí)別虛函數(shù)調(diào)用點(diǎn)記錄其靜態(tài)類(lèi)型和候選目標(biāo)集合。結(jié)合構(gòu)造路徑和類(lèi)型傳播信息細(xì)化綁定邊。對(duì)無(wú)法確定的調(diào)用點(diǎn)標(biāo)記為待運(yùn)行時(shí)解析并保留候選集合。通過(guò)上述步驟靜態(tài)測(cè)試工具能夠生成包含多態(tài)信息的增強(qiáng)調(diào)用圖為后續(xù)覆蓋率統(tǒng)計(jì)提供支撐。5. 典型代碼示例下面給出一個(gè)簡(jiǎn)化的嵌入式 C 示例演示虛函數(shù)調(diào)用解析與多態(tài)路徑覆蓋的基本思路。class Sensor { public: virtual int read() 0; }; class TemperatureSensor : public Sensor { public: int read() override { return 25; } }; class PressureSensor : public Sensor { public: int read() override { return 101; } }; int process(Sensor* s) { return s-read(); // 虛函數(shù)調(diào)用點(diǎn) }在上述代碼中process函數(shù)的虛調(diào)用點(diǎn)存在兩個(gè)候選綁定目標(biāo)TemperatureSensor::read和PressureSensor::read。靜態(tài)測(cè)試工具需要分別構(gòu)造兩種動(dòng)態(tài)類(lèi)型下的執(zhí)行路徑以實(shí)現(xiàn)多態(tài)路徑覆蓋。下面進(jìn)一步給出一個(gè)包含多個(gè)連續(xù)虛函數(shù)調(diào)用的完整示例并展示靜態(tài)分析工具如何生成候選綁定目標(biāo)集合以及組合路徑覆蓋過(guò)程。class Device { public: virtual int status() 0; // 調(diào)用點(diǎn) 1 virtual int calibrate() 0; // 調(diào)用點(diǎn) 2 virtual int report() 0; // 調(diào)用點(diǎn) 3 }; class SensorDevice : public Device { public: int status() override { return 1; } int calibrate() override { return 10; } int report() override { return 100; } }; class ActuatorDevice : public Device { public: int status() override { return 2; } int calibrate() override { return 20; } int report() override { return 200; } }; int runSequence(Device* d) { int a d-status(); // 調(diào)用點(diǎn) 1候選 {SensorDevice::status, ActuatorDevice::status} int b d-calibrate(); // 調(diào)用點(diǎn) 2候選 {SensorDevice::calibrate, ActuatorDevice::calibrate} int c d-report(); // 調(diào)用點(diǎn) 3候選 {SensorDevice::report, ActuatorDevice::report} return a b c; }靜態(tài)分析工具對(duì)上述代碼的處理過(guò)程如下生成候選綁定目標(biāo)集合對(duì)每個(gè)虛調(diào)用點(diǎn)根據(jù)對(duì)象靜態(tài)類(lèi)型Device*和繼承體系收集所有可覆蓋的派生類(lèi)實(shí)現(xiàn)。調(diào)用點(diǎn) 1、2、3 的候選集合均為{SensorDevice, ActuatorDevice}對(duì)應(yīng)的三個(gè)虛函數(shù)實(shí)現(xiàn)。組合路徑覆蓋由于三個(gè)調(diào)用點(diǎn)連續(xù)且相互獨(dú)立工具會(huì)枚舉所有綁定組合共 2 × 2 × 2 8 條組合路徑例如SensorDevice::status → SensorDevice::calibrate → SensorDevice::report、SensorDevice::status → SensorDevice::calibrate → ActuatorDevice::report等。符號(hào)執(zhí)行剪枝當(dāng)組合數(shù)量過(guò)大時(shí)工具結(jié)合約束求解剔除不可達(dá)組合僅保留滿(mǎn)足前置條件的路徑從而控制狀態(tài)空間規(guī)模。通過(guò)上述過(guò)程靜態(tài)分析工具能夠?yàn)槊總€(gè)調(diào)用點(diǎn)標(biāo)注候選目標(biāo)并生成完整的組合路徑覆蓋報(bào)告幫助測(cè)試人員確認(rèn)多態(tài)行為是否被充分驗(yàn)證。6. 覆蓋度度量與報(bào)告多態(tài)路徑覆蓋的度量結(jié)果通常以調(diào)用點(diǎn)覆蓋率和綁定目標(biāo)覆蓋率兩種形式呈現(xiàn)。覆蓋類(lèi)型說(shuō)明典型閾值調(diào)用點(diǎn)覆蓋率已解析的虛調(diào)用點(diǎn)占全部虛調(diào)用點(diǎn)的比例100%綁定目標(biāo)覆蓋率已覆蓋的動(dòng)態(tài)綁定目標(biāo)占全部候選目標(biāo)的比例80% 以上當(dāng)綁定目標(biāo)覆蓋率不足時(shí)測(cè)試報(bào)告應(yīng)列出未覆蓋的候選目標(biāo)及其調(diào)用點(diǎn)位置便于開(kāi)發(fā)人員補(bǔ)充測(cè)試用例或增加靜態(tài)約束。7. 工程實(shí)踐中的注意事項(xiàng)在嵌入式項(xiàng)目中應(yīng)用上述技術(shù)時(shí)需要注意以下幾點(diǎn)資源受限靜態(tài)分析過(guò)程可能消耗較多內(nèi)存和 CPU 時(shí)間建議在持續(xù)集成環(huán)境中分階段執(zhí)行。第三方庫(kù)外部庫(kù)中的虛函數(shù)往往無(wú)法獲取源碼需要配置樁函數(shù)或白名單。編譯器差異不同編譯器的虛表布局和優(yōu)化策略可能影響解析精度建議結(jié)合目標(biāo)編譯器的行為進(jìn)行校準(zhǔn)。8. 總結(jié)虛函數(shù)調(diào)用解析與多態(tài)路徑覆蓋是面向?qū)ο笄度胧杰浖o態(tài)測(cè)試的關(guān)鍵技術(shù)。通過(guò)構(gòu)建增強(qiáng)調(diào)用圖、細(xì)化綁定目標(biāo)集合并采用符號(hào)執(zhí)行進(jìn)行路徑篩選可以有效提升多態(tài)代碼的測(cè)試充分性。實(shí)際落地時(shí)需要結(jié)合工程約束合理配置覆蓋閾值并持續(xù)優(yōu)化分析精度。