查找嵌入式C語(yǔ)言程序/軟件中的缺陷的多種技術(shù)
基于模式的靜態(tài)代碼分析、運行時(shí)內存監測、單元測試以及數據流分析等軟件驗證技術(shù)是查找嵌入式C語(yǔ)言程序/軟件缺陷行之有效的方法。上述技術(shù)中的每一種都能查找出某一類(lèi)特定的錯誤。即便如此,如果用戶(hù)僅采用上述技術(shù)中的一種或者幾種來(lái)進(jìn)行驗證,這樣的驗證方法很有可能會(huì )漏過(guò)對程序中的一些缺陷的檢查。解決此類(lèi)問(wèn)題的一種安全和有效的策略就是同時(shí)使用上述軟件驗證中的所有互補技術(shù)。這樣就能建立起一個(gè)牢固的框架來(lái)幫助用戶(hù)檢查出可能會(huì )避開(kāi)某種特定技術(shù)的缺陷。與此同時(shí),用戶(hù)也自然地建立起一個(gè)能檢測出關(guān)鍵并且難以查找的功能性錯誤的環(huán)境。
本文將詳盡闡述基于模式的靜態(tài)代碼分析、運行時(shí)內存錯誤檢測、單元測試以及數據流分析等自動(dòng)化技術(shù)共同使用時(shí)是如何查找出嵌入式C語(yǔ)言程序/軟件中的缺陷的。本文中將以Parasoft C++test為例來(lái)演示上述各項技術(shù)。C++teST是一個(gè)經(jīng)廣泛的最佳實(shí)踐證明能提升軟件開(kāi)發(fā)團隊開(kāi)發(fā)效率以及軟件質(zhì)量的自動(dòng)化集成解決方案。
當讀者在閱讀本文以及任何時(shí)候思考查找到的缺陷時(shí),關(guān)注文中的截圖是很重要的。自動(dòng)化檢測例如內存崩潰和死鎖的缺陷,毫無(wú)疑問(wèn)對任何開(kāi)發(fā)團隊都是一項必不可少的任務(wù)。盡管如此,最致命的缺陷卻是功能性錯誤,這往往是難以自動(dòng)發(fā)現的。在本文的結論部分我們將簡(jiǎn)要地討論一下查找這些缺陷的技術(shù)。
情景簡(jiǎn)介
為了給出一個(gè)具體的示例,我們將就一個(gè)我們最近遇到的案例來(lái)介紹以及演示我們所推薦的缺陷查找策略:一個(gè)運行在A(yíng)RM 板上的簡(jiǎn)單傳感器應用程序。
假設我們已經(jīng)創(chuàng )建了該應用系統,但是當我們將程序上載到系統目標板上并試圖運行該程序時(shí),我們沒(méi)有在LCD屏上看到所預期的輸出。
我們尚不明確系統不能正常工作的原因,因此我們設法對系統進(jìn)行調試,但是在目標板上進(jìn)行調試是一件耗時(shí)而且煩人的事。因為我們不得不手動(dòng)分析調試器的結果并試圖人工判斷出問(wèn)題的真正原因?;蛘呶覀兪褂靡恍┍蛔C實(shí)能自動(dòng)定位出錯誤的工具或技術(shù)來(lái)幫助我們減輕負擔。
從這一點(diǎn)而言,我們要么期待使用調試器來(lái)調試程序能夠帶來(lái)好運,要么我們嘗試使用一種自動(dòng)化的測試策略來(lái)查找代碼中所存在的錯誤。如果自動(dòng)化技術(shù)仍然沒(méi)有幫助我們查找到錯誤,那么我們不得不回到使用調試器作為最后的辦法。
基于模式的靜態(tài)代碼分析
這里,我們假設僅在絕對必要的情況下才使用調試器進(jìn)行調試,因此我們從運行基于模式的靜態(tài)代碼分析開(kāi)始。它將查找到如下圖所示的問(wèn)題:
這是違反了 MISRA 的一個(gè)規則,此違規說(shuō)明該處的賦值運算符存在一些可疑情況。的確,編程者此處的本意是使用比較運算符而不是賦值運算符。因此我們將此處檢測到的沖突修改掉,并重新運行程序。
我們發(fā)現有了一些改善:一些輸出被顯示在了LCD屏上了。但是,由于一次訪(fǎng)問(wèn)違規,程序崩潰掉了。因此我們需要再次地做出選擇。我們是應該使用調試器還是繼續使用自動(dòng)化的錯誤檢測技術(shù)。由于經(jīng)驗告訴我們自動(dòng)化錯誤檢測技術(shù)能非常高效地檢查出我們當前程序所遇到的內存崩潰這類(lèi)問(wèn)題,因此我們決定使用運行時(shí)內存監測來(lái)查找問(wèn)題。
整個(gè)程序的運行時(shí)內存監測
為了進(jìn)行運行時(shí)內存監測,我們使用 C++test 來(lái)插裝應用程序。這樣的插裝是輕量級的,所以經(jīng)過(guò)插裝后的程序適合在目標板上運行。當我們把程序上載到目標板上并運行經(jīng)過(guò)插裝的程序后,我們將結果下載到PC上,如下的錯誤將被報告出來(lái):
該結果指出在第48行代碼處產(chǎn)生了一次讀取數組越界的錯誤。顯然,msgIndex變量的值肯定超過(guò)了數組的范圍。如果我們隨著(zhù)堆棧追蹤上一級的原因,我們將發(fā)現此處的打印信息所指示的值的確超出了數組的范圍(因為在調用printMessage()函數前我們給出了一個(gè)錯誤的條件)。我們可以刪除掉這個(gè)不必要的條件(value = 20)以修改這個(gè)錯誤。
void handleSensorValue(int value)
{
initialize();
int index = -1;
if (value >= 0 value = 10) {
index = VALUE_LOW;
} else if ((value > 10) (value = 20)) {
index = VALUE_HIGH;
}
printMessage(index, value);
}
評論