24小時(shí)聯(lián)系電話(huà):18217114652、13661815404
中文
- 您當前的位置:
- 首頁(yè)>
- 電子資訊>
- 技術(shù)專(zhuān)題>
- 基于標準的開(kāi)發(fā)實(shí)踐
技術(shù)專(zhuān)題
基于標準的開(kāi)發(fā)實(shí)踐
整個(gè)行業(yè)都圍繞著(zhù)以功能安全性,安全性和編碼標準(例如IEC 61508,ISO 26262,IEC 62304,MISRA C和CWE)為支持的驗證和確認實(shí)踐而發(fā)展。當然,并非所有人都有義務(wù)遵循這些標準所倡導的正式流程和方法,尤其是在其軟件不需要滿(mǎn)足這些標準的嚴格要求的情況下。但是標準支持最佳實(shí)踐,因為經(jīng)驗表明,它們代表了獲得高質(zhì)量,可靠和強大的軟件的最有效方法。
遵循這些標準的最佳實(shí)踐開(kāi)發(fā)技術(shù)可幫助確保一開(kāi)始就不會(huì )在代碼中引入錯誤,從而減少了對大量調試活動(dòng)的需求,這些活動(dòng)可能會(huì )縮短上市時(shí)間并增加成本。當然,并非所有開(kāi)發(fā)人員都擁有在航空航天,汽車(chē)或醫療設備行業(yè)中看到的應用程序所能承受的時(shí)間和預算。但是,無(wú)論關(guān)鍵性是否強制使用它們,他們部署的技術(shù)對于任何開(kāi)發(fā)團隊而言都具有巨大的潛在利益。
錯誤類(lèi)型和解決方法
在軟件中可以找到兩種關(guān)鍵類(lèi)型的錯誤,并使用防止錯誤引入的工具進(jìn)行了處理:
編碼錯誤。一個(gè)示例是嘗試訪(fǎng)問(wèn)數組范圍之外的代碼??梢酝ㄟ^(guò)執行靜態(tài)分析來(lái)檢測這些類(lèi)型的問(wèn)題。
應用程序錯誤。只有通過(guò)確切了解應用程序應該做什么才能檢測到這些,這意味著(zhù)需要進(jìn)行測試。
編碼錯誤和代碼檢查
靜態(tài)分析是檢測編碼錯誤的有效技術(shù),尤其是從項目開(kāi)始部署時(shí)。一旦分析了代碼,就可以查看不同類(lèi)型的結果。在代碼審查中,將根據諸如MISRA C:2012之類(lèi)的編碼標準來(lái)檢查代碼,這是我們在本文中重點(diǎn)介紹的內容。
理想情況下,所有嵌入式項目都應使用安全語(yǔ)言(例如Ada)。Ada具有許多特性,可以強制執行思考過(guò)程,從而自然地減少錯誤(例如,嚴格鍵入)。不幸的是,很難找到具有Ada知識和經(jīng)驗的程序員,因此大多數公司都使用C和/或C ++。但是,即使是經(jīng)驗豐富的開(kāi)發(fā)人員,這些語(yǔ)言也會(huì )帶來(lái)陷阱。幸運的是,通過(guò)執行代碼審查,可以避免大多數這些潛在的陷阱。
避免代碼缺陷的最佳方法是避免將其放置在此處。這聽(tīng)起來(lái)很明顯,但這正是編碼標準所做的。在C和C ++世界中,大約80%的軟件缺陷是由錯誤使用大約20%的語(yǔ)言引起的。如果限制使用該語(yǔ)言以避免該語(yǔ)言的已知部分出現問(wèn)題,則可以避免出現缺陷,從而大大提高軟件質(zhì)量。
C / C ++編程語(yǔ)言與語(yǔ)言相關(guān)的故障的根本原因是未定義的行為,實(shí)現定義的行為和未指定的行為。這些行為導致軟件錯誤和安全問(wèn)題。
作為實(shí)現定義的行為的示例,請考慮當有符號整數右移時(shí)的高階位的傳播。結果是0x40000000還是0xC0000000?
某些C和C ++構造的行為取決于所使用的編譯器
答案取決于您使用的是哪個(gè)編譯器(圖1)。可能是。函數參數的求值順序未在C語(yǔ)言中指定。在圖2所示的代碼中(其中rollDice()函數僅從持有值“ 1、2、3和4”的循環(huán)緩沖區中讀取下一個(gè)值),期望的返回值為1234。但是,沒(méi)有為此,至少一個(gè)編譯器將生成返回值3412的代碼。
圖2:某些C和C ++構造的行為未由語(yǔ)言指定
C / C ++語(yǔ)言存在許多類(lèi)似的陷阱,但是通過(guò)使用編碼標準,可以避免這些未定義,未指定和實(shí)現定義的行為。同樣,使用諸如goto或malloc之類(lèi)的構造會(huì )導致缺陷,因此可以使用編碼標準來(lái)防止使用這些構造?;旌嫌蟹柡蜔o(wú)符號值時(shí)會(huì )發(fā)生許多問(wèn)題,這在大多數情況下不會(huì )產(chǎn)生問(wèn)題,但是有時(shí)可能會(huì )出現極端情況,即有符號的值溢出并變?yōu)樨摂怠?/span>
編碼標準還可以檢查代碼是否以特定樣式編寫(xiě)。例如,驗證未使用制表符,縮進(jìn)是特定大小還是括號位于特定位置。這很重要,因為將需要進(jìn)行一些手動(dòng)代碼審查,并且在其他選項卡字符大小不同的編輯器中查看代碼時(shí),奇怪的布局分散了審查者的注意力,使他們無(wú)法集中精力審查代碼。
一些開(kāi)發(fā)人員對編寫(xiě)“聰明的”代碼感到內gui,這些代碼可能是高效且緊湊的,但也可能是晦澀復雜的,這使得其他人難以理解。最好保持簡(jiǎn)單,讓編譯器負責制作高效的二進(jìn)制文件。再次,使用編碼標準可以幫助防止開(kāi)發(fā)人員創(chuàng )建未記錄且過(guò)于復雜的代碼。
最著(zhù)名的編程標準可能是MISRA標準,該標準于1998年首次發(fā)布給汽車(chē)行業(yè)。這些標準的普及反映在提供某種級別的MISRA檢查的嵌入式編譯器中。MISRA的最新版本是MISRA C:2012,其頁(yè)數幾乎是其前身的兩倍。這些附加文檔中的大多數包含有關(guān)每個(gè)規則為何存在的有用解釋?zhuān)约霸撘巹t的各種例外的詳細信息。MISRA有幾個(gè)準則,并且在適用時(shí),它們包含對標準或未定義,未指定和實(shí)現定義的行為的引用。這樣的一個(gè)例子可以在圖3中看到。
圖3:MISRA C引用了未定義,未指定和實(shí)現定義的行為
MISRA的大多數指南都是“可判定的”,這意味著(zhù)工具應該能夠識別是否存在違規行為。但是,一些準則是“不確定的”,這意味著(zhù)工具并非總是可能推斷出是否存在違規行為。例如,將未初始化的變量作為輸出參數傳遞給應該對其進(jìn)行初始化的系統函數時(shí)。但是,除非靜態(tài)分析可以訪(fǎng)問(wèn)系統功能的源代碼,否則它將無(wú)法在該功能初始化之前就知道該功能是否使用了該變量。如果使用簡(jiǎn)單的MISRA檢查器,則它可能不會(huì )報告此違規,可能導致假陰性?;蛘?,如果不確定MISRA檢查器,則它可以報告違規情況,可能導致假陽(yáng)性。什么是最好的?不知道可能有問(wèn)題嗎?還是確切地知道在哪里花費時(shí)間來(lái)確保絕對沒(méi)有問(wèn)題?當然,假陽(yáng)性比假陰性更可取。
2016年4月,MISRA委員會(huì )發(fā)布了對MISRA C:2012的修訂,其中增加了14條準則,以幫助確保MISRA不僅適用于安全性至關(guān)重要的軟件,還適用于安全性至關(guān)重要的軟件。這些準則之一就是指令4.14,如圖4所示,該準則有助于防止由于未定義行為引起的陷阱。
圖4:MISRA和安全注意事項
應用程序錯誤和需求測試
應用程序錯誤只能通過(guò)測試產(chǎn)品是否達到了預期功能才能找到,這意味著(zhù)有要求。避免應用程序錯誤既需要設計正確的產(chǎn)品,又需要設計正確的產(chǎn)品。
設計正確的產(chǎn)品意味著(zhù)預先建立需求,并確保需求和源代碼之間的雙向可追溯性,以便已實(shí)現每個(gè)需求,并且每個(gè)軟件功能都可以追溯到需求。任何缺少的或不必要的功能(不符合要求)也是應用程序錯誤。設計產(chǎn)品權利是確認開(kāi)發(fā)的系統代碼滿(mǎn)足項目要求的過(guò)程,可以通過(guò)執行基于需求的測試來(lái)實(shí)現。
圖5顯示了雙向可追溯性的示例。在這個(gè)簡(jiǎn)單的示例中,選擇了一個(gè)功能,并突出了從功能到低層需求,然后是高層需求,最后是系統層需求的上游可追溯性。
圖5:雙向可追溯性,已選擇功能
在圖6中,選擇了一個(gè)高級需求,并且高亮顯示了對系統級別需求的上游可追溯性和對低級別需求以及源代碼功能的下游可追溯性。
圖6:雙向可追溯性,已選擇要求
這種可視化可追溯性的能力可以導致在生命周期的早期發(fā)現可追溯性問(wèn)題(應用程序錯誤)。
測試代碼功能需要了解它應該做什么,這意味著(zhù)具有低級要求來(lái)陳述每個(gè)功能的作用。圖7顯示了一個(gè)低級別需求的示例,在這種情況下,它完整地描述了一個(gè)功能。
圖7:低級別需求示例
測試用例源自表1中所示的低級需求。
表1:來(lái)自低級需求的測試用例
然后使用單元測試工具在主機或目標上執行這些測試用例,以確保代碼的行為符合要求。圖8顯示所有測試用例均已回歸并通過(guò)。
圖8:執行單元測試
測試用例運行后,應測量結構覆蓋范圍,以確保所有代碼都已執行。如果覆蓋率不是100%,則可能需要更多的測試用例,或者有多余的代碼應刪除。