国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
C++編碼中減少內(nèi)存缺陷的方法和工具

C++編碼中減少內(nèi)存缺陷的方法和工具

程振林,方金云,唐志敏
(中國(guó)科學(xué)院計(jì)算技術(shù)研究所,北京 100080)


摘 要:基于C++的軟件的缺陷和錯(cuò)誤大部分都和內(nèi)存相關(guān),預(yù)防、發(fā)現(xiàn)、消除代碼中和內(nèi)存相關(guān)的缺陷,成為程序員編寫(xiě)、調(diào)試、維護(hù)代碼時(shí)的重要任務(wù)。該文基于“面向網(wǎng)絡(luò)海量空間信息的大型GIS”課題的工程實(shí)踐,提出和總結(jié)了如何使用C++語(yǔ)言機(jī)制、開(kāi)發(fā)環(huán)境和相關(guān)質(zhì)量保證工具來(lái)預(yù)防、發(fā)現(xiàn)各種編譯期、運(yùn)行期內(nèi)存缺陷的方法和工具。

關(guān)鍵詞:C++;內(nèi)存錯(cuò)誤;內(nèi)存泄漏;質(zhì)量保證

Techniques and Tools of Defending Memory-related Defects in Software Coded in C++
CHENG Zhenlin, FANG Jinyun, TANG Zhimin
(Institute of Computing Technology, Chinese Academy of Sciences, Beijing 100080)
【Abstract】Most of the defects and errors in the software coded in C++ are memory-related. Based on the practice in the "network, large volumespatial information oriented GIS" project, this paper presentsthe techniques and tools to find and fix the memory problems during the coding,debugging and production release phase with the support of the C++ language mechanism, development environment and related quality-assurancetools.
【Key words】C++; Memory errors; Memory leak; Quality assurance

C++語(yǔ)言是桌面系統(tǒng),尤其是系統(tǒng)軟件、大型應(yīng)用軟件的主流開(kāi)發(fā)語(yǔ)言。C++語(yǔ)言以其靈活性著稱,同時(shí)也更復(fù)雜。利用C++編寫(xiě)健壯的代碼,更具有挑戰(zhàn)性。C++允許動(dòng)態(tài)內(nèi)存管理, 同時(shí)也容易導(dǎo)致更多和內(nèi)存相關(guān)的問(wèn)題。一般而言, 除了系統(tǒng)設(shè)計(jì)上的缺陷, 基于C++的軟件的缺陷和錯(cuò)誤大部分都和內(nèi)存缺陷(主要包括內(nèi)存訪問(wèn)錯(cuò)誤和內(nèi)存泄漏兩類)相關(guān)。 所以,消除代碼中的內(nèi)存相關(guān)缺陷,成為程序員編寫(xiě)、調(diào)試、維護(hù)代碼中的任務(wù),也是保證軟件質(zhì)量的關(guān)鍵。
本文的工作基于“863”計(jì)劃項(xiàng)目“面向網(wǎng)絡(luò)海量空間信息的大型GIS”課題。該系統(tǒng)是基于C++/MFC編寫(xiě),開(kāi)發(fā)環(huán)境是Visual Studio .net 2003。本文基于此項(xiàng)目的工程實(shí)踐,總結(jié)了如何使用C++語(yǔ)言機(jī)制、開(kāi)發(fā)環(huán)境和相關(guān)質(zhì)量保證工具來(lái)預(yù)防、發(fā)現(xiàn)各種編譯期、運(yùn)行期和內(nèi)存相關(guān)的缺陷的方法和工具。
1 遵循C++相關(guān)的編碼規(guī)范和慣用法,預(yù)防缺陷
編碼規(guī)范是語(yǔ)言相關(guān)的規(guī)則,是經(jīng)過(guò)實(shí)踐總結(jié)出來(lái)的經(jīng)驗(yàn)。良好的編程標(biāo)準(zhǔn)將有效地幫助開(kāi)發(fā)人員避免開(kāi)發(fā)有潛在危險(xiǎn)的代碼。一般來(lái)說(shuō),為了減少內(nèi)存缺陷,應(yīng)該遵循下列編碼規(guī)則[1]:
(1)基類或者帶有虛函數(shù)的類應(yīng)該將其析構(gòu)函數(shù)聲明為虛函數(shù)。
(2)在構(gòu)造函數(shù)中防止內(nèi)存泄漏,在析構(gòu)函數(shù)中不要拋出異常。
(3)使用對(duì)應(yīng)形式的new和delete。即:用delete來(lái)釋放new申請(qǐng)的內(nèi)存,delete[]釋放new[]申請(qǐng)的內(nèi)存。
(4)指針在使用前必須初始化,指向動(dòng)態(tài)內(nèi)存的指針在釋放后應(yīng)立即置為空。
(5)如果類構(gòu)造函數(shù)中分配了資源,那么需要顯式提供拷貝構(gòu)造函數(shù)和賦值操作符,并且在析構(gòu)函數(shù)中釋放資源。
值得重視的是C++中的慣用法RAII。RAII核心思想是利用對(duì)象來(lái)管理資源,在對(duì)象的構(gòu)造函數(shù)中獲取資源,在其析構(gòu)函數(shù)中釋放資源[2]。為了保證動(dòng)態(tài)申請(qǐng)的內(nèi)存能在即使出現(xiàn)異常的情況下仍能釋放,比較理想的方法是使用局部變量來(lái)管理動(dòng)態(tài)內(nèi)存的所有權(quán)(ownership),就是所謂的智能指針。STL中的auto_ptr就是為解決資源所有權(quán)問(wèn)題設(shè)計(jì)的,但是缺少對(duì)引用數(shù)和數(shù)組的支持并且不能用在STL容器中。Boost庫(kù)[3]提供的智能指針相對(duì)成熟,實(shí)用價(jià)值高。其中,shared_ptr線程安全并且可以用在STL容器中。具體示例參考文獻(xiàn)[3]。
1.1 編碼規(guī)范檢查工具 CodeWizard
CodeWizard能夠?qū)υ闯绦蛑苯舆M(jìn)行自動(dòng)掃描、分析和檢查。一旦發(fā)現(xiàn)違例,產(chǎn)生信息告知與哪條規(guī)則不符并作出解釋。以CodeWizard 4.3 為例,其中內(nèi)置了超過(guò)500條編碼標(biāo)準(zhǔn)。CodeWizard可以選擇對(duì)于當(dāng)前的工程執(zhí)行哪些編碼標(biāo)準(zhǔn)。CodeWizard可以和VC++緊密集成,安裝完畢以后,VC++中有CodeWizard工具條。
1.2 代碼檢查工具 PC-Lint
PC-Lint可檢查編譯器不易發(fā)現(xiàn)的錯(cuò)誤。PC-Lint可對(duì)100多個(gè)C庫(kù)函數(shù)進(jìn)行檢查,可以發(fā)現(xiàn)標(biāo)準(zhǔn)C/C++代碼中的1 000多個(gè)常見(jiàn)錯(cuò)誤。要把PC-lint和Visual Studio集成在一起,需要自己配置。Jon Zyzyck提供了一個(gè)報(bào)告生成器,可以幫助完成這個(gè)工作??稍趆ttp://www.ddj.com下載。文獻(xiàn)[4]說(shuō)明了如何在VC++環(huán)境中集成PC-Lint。
2 利用語(yǔ)言機(jī)制、開(kāi)發(fā)環(huán)境和相關(guān)工具以預(yù)防和發(fā)現(xiàn)內(nèi)存缺陷
發(fā)現(xiàn)問(wèn)題是解決問(wèn)題的前提。相對(duì)于修復(fù)內(nèi)存缺陷,發(fā)現(xiàn)內(nèi)存缺陷并準(zhǔn)確定位導(dǎo)致缺陷的代碼更為費(fèi)時(shí)費(fèi)力。及早準(zhǔn)確地發(fā)現(xiàn)內(nèi)存缺陷,對(duì)于提高開(kāi)發(fā)效率非常重要。
2.1 利用斷言及早暴露內(nèi)存缺陷
斷言是布爾調(diào)試語(yǔ)句,用來(lái)檢測(cè)在程序運(yùn)行的時(shí)候某一條件的值是否總為真。斷言經(jīng)常用來(lái)確認(rèn)函數(shù)的輸入、輸出,檢查對(duì)象的當(dāng)前狀態(tài)是否合法等。 在以下的場(chǎng)景使用斷言可以幫助發(fā)現(xiàn)和內(nèi)存非法訪問(wèn)相關(guān)的錯(cuò)誤:
(1)驗(yàn)證指針是否可讀/寫(xiě)。在函數(shù)的入口處,經(jīng)常需要驗(yàn)證指針?biāo)赶虻膬?nèi)容區(qū)域是否可讀/寫(xiě)。 通常采用assert(p!= NULL)的檢測(cè)形式。 但是,指針的值不為空并不代表指針指向了合法可讀/寫(xiě)內(nèi)存。Win32 API提供了函數(shù)IsBadReadPtr、IsBadWritePtr、IsBadStringPtr、IsBadCodePtr用來(lái)檢測(cè)指針指向的內(nèi)存區(qū)域是否可讀/寫(xiě)。C運(yùn)行時(shí)庫(kù)提供了_CrtIs ValidPointer、_CrtIsValidHeapPointer等函數(shù),MFC庫(kù)提供了AfxIsValidAddress、AfxIsValidString函數(shù)來(lái)完成類似功能。
(2)對(duì)基于MFC的程序,ASSERT_VALID宏通過(guò)調(diào)用重載的AssertValid函數(shù)來(lái)確定指向CObject派生類對(duì)象的指針是否有效。ASSERT_VALID宏主要調(diào)用了AfxIsValidAddress函數(shù)和CObject派生類對(duì)象的AssertValid函數(shù)(參考MFC源代碼afx.h、objcore.cpp)。
2.2 利用C運(yùn)行時(shí)刻庫(kù)檢查內(nèi)存泄漏
VC++的C運(yùn)行庫(kù)(CRT)提供了廣泛的功能,幫助用戶檢測(cè)內(nèi)存泄漏。CRT提供了_CrtMemCheckPoint、_CrtDump MemoryLeaks、_CrtSetDbgFlag等函數(shù)來(lái)幫助調(diào)試內(nèi)存泄漏。
對(duì)于非MFC的工程, 要開(kāi)啟有效的內(nèi)存泄漏報(bào)告功能, 需要進(jìn)行如下設(shè)置:

(1)在StdAfx.h的頭部添加如下代碼并開(kāi)啟編譯器/Yu 選項(xiàng):

        #define _CRTDBG_MAP_ALLOC        #include <stdlib.h>        #include <crtdbg.h>        #define DEBUG_NEW new(_NORMAL_BLOCK, THIS_FILE, __LINE__)

(2)確保在每個(gè).cpp文件的頭部包含以下內(nèi)容:
        #include "stdafx.h"        #ifdef _DEBUG        #define new DEBUG_NEW        #undef THIS_FILE        static char THIS_FILE[] = __FILE__;        #endif

(3)在程序的開(kāi)始處開(kāi)啟報(bào)告內(nèi)存泄漏的開(kāi)關(guān):
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
對(duì)于MFC工程, MFC已經(jīng)做了相關(guān)的工作, 只需要確認(rèn)在每個(gè).cpp文件的頭部包含上述第(2)點(diǎn)的內(nèi)容。
在某些情況下,需要知道發(fā)生內(nèi)存泄漏的內(nèi)存塊中的內(nèi)容,但是標(biāo)準(zhǔn)的內(nèi)存轉(zhuǎn)儲(chǔ)只是內(nèi)存塊頭部的十六進(jìn)制形式。為了得到更多的有用信息,需要以用戶塊類型(_CLIENT_ BLOCK)申請(qǐng)內(nèi)存,并利用_CrtSetDumpClient建立用戶塊型內(nèi)存的轉(zhuǎn)儲(chǔ)函數(shù)。具體的說(shuō),對(duì)于不是從CObject繼承的類,需要:

(1)為每個(gè)類/結(jié)構(gòu)指定一個(gè)用戶塊子類型(參考crtdbg.h)。

(2)在申請(qǐng)內(nèi)存時(shí),采用重載的new形式:void* __cdecl operator new(size_t nSize, int nType, LPCSTR lpszFileName, int nLine)(參考MFC源代碼 afxmem.cpp),其中nType就是用戶塊的子類型。

(3)創(chuàng)建一個(gè)用戶塊內(nèi)存轉(zhuǎn)儲(chǔ)函數(shù),專門對(duì)每種需要轉(zhuǎn)儲(chǔ)的子類型進(jìn)行處理(需要包含dbgint.h)。

(4)利用_CrtSetDumpClient對(duì)用戶塊內(nèi)存轉(zhuǎn)儲(chǔ)函數(shù)進(jìn)行注冊(cè)(參考MFC源代碼dumpinit.cpp)。

對(duì)于從CObject繼承來(lái)的類,MFC 已經(jīng)按照上述方法做了基礎(chǔ)工作(參考MFC源代碼 afxmem.cpp、dumpinit.cpp)。要有效轉(zhuǎn)儲(chǔ)從CObject繼承的對(duì)象,需要:(1)對(duì)每個(gè)從CObject繼承的類重載虛函數(shù)Dump。(2)在程序的初始化部分 加入代碼 afxDump.SetDepth(1)來(lái)開(kāi)啟深度轉(zhuǎn)儲(chǔ)。

2.3 利用Purify和Insure++查找運(yùn)行時(shí)內(nèi)存缺陷
Rational Purify和Parasoft Insure++ 是用于運(yùn)行時(shí)錯(cuò)誤檢查的工具。Purify主要檢測(cè):數(shù)組內(nèi)存越界讀/寫(xiě),使用未初始化的內(nèi)存,對(duì)已釋放的內(nèi)存進(jìn)行讀/寫(xiě),內(nèi)存泄漏等。Insure++利用其專利技術(shù)(源碼插裝和運(yùn)行時(shí)指針跟蹤)能夠發(fā)現(xiàn)大量的內(nèi)存操作錯(cuò)誤,報(bào)告錯(cuò)誤的源代碼行和執(zhí)行軌跡。根據(jù)筆者的測(cè)試(基于98個(gè)有各種內(nèi)存錯(cuò)誤的C++程序,涵蓋了典型情形),Insure++ 6.1都能準(zhǔn)確檢測(cè)。
3 利用VC++環(huán)境的調(diào)試和診斷功能,檢查和發(fā)現(xiàn)常見(jiàn)內(nèi)存缺陷
理解常見(jiàn)的內(nèi)存缺陷問(wèn)題以及在VC++環(huán)境下的癥狀,能輔助我們減少問(wèn)題的發(fā)生和及時(shí)修改問(wèn)題。
從錯(cuò)誤的表現(xiàn)形式上看, 和堆棧有關(guān)的錯(cuò)誤主要分為兩大類:堆棧溢出和函數(shù)返回信息被破壞。

(1)堆棧溢出(overflow)

此類錯(cuò)誤主要有兩種情形:

1)過(guò)大的局部變量。缺省情況下Windows為每個(gè)線程保留1M堆??臻g。在菜單Project->Properties->Configuration Properties -> Linker->System中可以看到Stack Reserve Size選項(xiàng)可以調(diào)整保留的堆??臻g大小。

2)遞歸調(diào)用層數(shù)過(guò)深。在調(diào)試過(guò)程中,調(diào)用堆棧(call stack)窗口中可以發(fā)現(xiàn)函數(shù)遞歸調(diào)用的模式。

(2)函數(shù)返回信息被破壞

此類錯(cuò)誤主要有兩種情形:
1)對(duì)局部變量的寫(xiě)操作超出了范圍(上溢)。在調(diào)試過(guò)程中,函數(shù)堆棧被破壞掉的明顯標(biāo)志是無(wú)法顯示調(diào)用堆棧,并且錯(cuò)誤發(fā)生在被調(diào)用函數(shù)即將返回的位置。
2)在調(diào)用函數(shù)和被調(diào)用函數(shù)之間如果出現(xiàn)了函數(shù)參數(shù)的不匹配或者調(diào)用規(guī)范的不一致。
為了檢查此類錯(cuò)誤,應(yīng)該在代碼編譯時(shí)打開(kāi)/GS、/RTCs開(kāi)關(guān)(在菜單Project->Properties->Configuration Properties-> C/C++->Code Generation下設(shè)置)。
另外一類錯(cuò)誤是動(dòng)態(tài)內(nèi)存錯(cuò)誤。典型的情況如下:
(1)內(nèi)存寫(xiě)越界。在調(diào)試版本中,如果是寫(xiě)上溢,就會(huì)收到“Damage:after block...”的跟蹤消息,如果是寫(xiě)下溢出就會(huì)收到“Damage: before block...”的跟蹤消息。
(2)刪除不合法指針。在調(diào)試版本中,刪除未初始化的指針或者非堆指針時(shí),會(huì)收到_CrtIsValidHeapPointer斷言錯(cuò)誤。
(3)多次釋放。在調(diào)試版本中,如果多次刪除同一指針, 會(huì)收到_BLOCK_TYPE_IS_VALID斷言錯(cuò)誤。要防止此類錯(cuò)誤,應(yīng)在delete某個(gè)指向動(dòng)態(tài)內(nèi)存的指針后立即將其置為空。

4 利用Windows結(jié)構(gòu)化異常處理機(jī)制處理發(fā)布版本軟件的內(nèi)存崩潰
在程序的發(fā)布階段,應(yīng)盡量減少程序錯(cuò)誤尤其是內(nèi)存崩潰。如果崩潰了,應(yīng)該“優(yōu)雅”地退出,盡量收集程序崩潰時(shí)的運(yùn)行信息以幫助程序供應(yīng)商后續(xù)的調(diào)試。要捕捉內(nèi)存非法訪問(wèn)并獲知非法訪問(wèn)的指令地址、寄存器內(nèi)容等信息,需要用到Windows的結(jié)構(gòu)化異常處理(Structured Exception Handling,SEH)機(jī)制[6]。MiniDumpWriteDump是dbghelp.dll提供的一個(gè) API函數(shù)(參考MSDN),用于轉(zhuǎn)儲(chǔ)用戶模式程序的一些信息(比如堆棧情況等)并存為一個(gè)文件(比如.dmp文件),此文件可以被微軟的調(diào)試器(VC++或者WinDBG)利用進(jìn)行事后調(diào)試。使用此函數(shù)需要dbghelp.h、dbghelp.lib和dbghelp.dll(這些文件可以在Windows Platform SDK中找到)。
要事后根據(jù).dmp文件調(diào)試代碼,需要為發(fā)布版本軟件產(chǎn)生debug symbols (pdb)文件(打開(kāi)編譯器/DEBUG選項(xiàng))。在拿到.dmp文件以后,用VC++打開(kāi).dmp文件,然后調(diào)試執(zhí)行(按F5鍵)。這樣,崩潰現(xiàn)場(chǎng)就會(huì)重現(xiàn)。文獻(xiàn)[5]基于上述的方法實(shí)現(xiàn)了崩潰報(bào)告系統(tǒng)。

5 結(jié)論
實(shí)踐證明,在上述方法和工具支持下的減少軟件內(nèi)存缺陷的方法和工具,可以有效防止和查找代碼中的內(nèi)存錯(cuò)誤和內(nèi)存泄漏,并且能和開(kāi)發(fā)人員日常編碼無(wú)縫結(jié)合,執(zhí)行起來(lái)非常高效。上述方法配合單元測(cè)試、代碼評(píng)審、每日構(gòu)建、Bug追蹤等措施,形成了一個(gè)高效的質(zhì)量保證流程,在我們的大型平臺(tái)軟件開(kāi)發(fā)過(guò)程中起到了重要作用。

參考文獻(xiàn)
1 Sutter H, Alexandrescu A. C++ Coding Standards: 101 Rules, Guidelines, and Best Practices[M]. Addison-Wesley Professional, 2004-10.
2 Stroustrup B. The Design and Evolution of C++[M]. Addison-Wesley Professional, 1994-03.
3 Karlsson B. Beyond the C++ Standard Library: An Introduction to Boost[M]. Addison-Wesley Professional, 2005-08.
4 Zyzyck J. A Report Generator for PC-Lint[J]. Dr. Dobb's Journal, 2003, 28(2): 52.
5 Dietrich H. XCrash Report: Exception Handling and Crash Reporting[Z]. 2003-10. http://www.codeproject.com/debug/ XCrash ReportPt4.asp.
6 Richter J M. Programming Applications for Microsoft Windows[M]. Microsoft Press, 1999-09.
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Windows程序調(diào)試
析構(gòu)函數(shù)為什么總是虛函數(shù)
Debug與Release版本的區(qū)別
vc調(diào)試適合入門
VC/MFC調(diào)試技術(shù)(轉(zhuǎn)) - carekee - 博客園
編碼中常見(jiàn)的4類內(nèi)存管理錯(cuò)誤
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服