亚洲免费av电影一区二区三区,日韩爱爱视频,51精品视频一区二区三区,91视频爱爱,日韩欧美在线播放视频,中文字幕少妇AV,亚洲电影中文字幕,久久久久亚洲av成人网址,久久综合视频网站,国产在线不卡免费播放

        ?

        C/C++程序內(nèi)存泄漏檢測算法的研究

        2021-05-16 17:25:00仵俊
        現(xiàn)代信息科技 2021年22期
        關(guān)鍵詞:程序

        摘? 要:為了獲得最佳性能,C/C++語言把操縱內(nèi)存的權(quán)限以指針的方式暴露給開發(fā)人員。但是C/C++語言編譯器GCC和Clang都不提供內(nèi)存安全檢測,導(dǎo)致開發(fā)人員使用C/C++語言編寫的項目可能存在內(nèi)存泄漏的風(fēng)險。文章介紹了改進(jìn)指針?biāo)惴ê蛃hared_ptr源碼,分析了它們檢測內(nèi)存泄漏的方式,最后指出該類算法的缺陷,提出改進(jìn)思路,并建議用戶避免寫出該類算法無法檢測的代碼結(jié)構(gòu)。

        關(guān)鍵詞:C/C++程序;內(nèi)存泄漏;改進(jìn)指針?biāo)惴?shared_ptr

        中圖分類號:TP311 ? ? 文獻(xiàn)標(biāo)識碼:A文章編號:2096-4706(2021)22-0098-03

        Abstract: In order to obtain the best performance, C/C++ language exposes the permission to manipulate memory to developers in the form of pointers. However, the C/C++ language compiler GCC and Clang do not provide memory security detection, which leads to the risk of memory leakage for projects written by developers in C/C++ language. This paper introduces the improved pointer algorithm and shared_ptr source code, analyzes their ways to detect memory leakage, finally points out the defects of this kind of algorithm and puts forward improvement ideas, and advises users to avoid writing code structures that cannot be detected by such algorithms.

        Keywords: C/C++ program; memory leak; improved pointer algorithm; shared_ ptr

        0? 引? 言

        隨著使用C/C++語言所構(gòu)建項目規(guī)模的不斷增大,內(nèi)存安全也越來越受重視。內(nèi)存泄漏往往在程序運(yùn)行中就發(fā)生,不易被發(fā)現(xiàn)和修改。相較于其他運(yùn)行于虛擬機(jī)上的語言(如Python和Java),C/C++為了實現(xiàn)對內(nèi)存的細(xì)粒度的操作,沒有設(shè)計垃圾收集器。因此,使用C/C++編寫項目時,開發(fā)人員需要格外注意內(nèi)存的申請和釋放。本文介紹了改進(jìn)指針?biāo)惴╗1-3]和shared_ptr[4,5]源碼,分析了它們對內(nèi)存泄漏的檢測方式,并指出它們所存在的不足。希望讀者可以通過改進(jìn)指針?biāo)惴ɑ騭hare_ptr來規(guī)避內(nèi)存泄漏,盡量不要寫出連檢測算法也無法處理的代碼結(jié)構(gòu)。

        1? 內(nèi)存泄漏檢測原理分析

        1.1? 改進(jìn)指針?biāo)惴?/p>

        改進(jìn)指針?biāo)惴ㄊ且环N新的內(nèi)存安全性動態(tài)分析方法,采用源碼插樁技術(shù)實現(xiàn),支持復(fù)雜的動態(tài)內(nèi)存檢查。改進(jìn)指針方法的最大創(chuàng)新點是分別為每一個內(nèi)存對象和指針創(chuàng)建和維護(hù)一個狀態(tài)節(jié)點數(shù)據(jù)(status node data, snd)和指針元數(shù)據(jù)(pointer matedata, pmd)。該方法不僅可以在程序運(yùn)行時記錄每個指針指向內(nèi)存對象的邊界信息,還可以記錄內(nèi)存對象所對應(yīng)snd的狀態(tài)和計數(shù)信息。snd的狀態(tài)(stat)是指對應(yīng)內(nèi)存對象的內(nèi)存類型,如無效(invalid)、棧(heap)、全局(global)、靜態(tài)(static)和函數(shù)(function)等,snd的定義為

        1: typedef enum{

        2:? ?invalid, heap,global,...

        3: } status;

        4: typedef struct{

        5:? ?status stat;size_t count; 7: } SND;

        由于多個指針引用同一塊內(nèi)存,這些指針?biāo)鶎?yīng)的指針元數(shù)據(jù)將共享同一個snd。通過snd的count變量判斷出該內(nèi)存對象無用后,其所對應(yīng)的狀態(tài)節(jié)點也會足夠“智能”地自我銷毀,不會常駐內(nèi)存。

        指針pmd是改進(jìn)指針?biāo)惴ǖ闹匾獢?shù)據(jù)結(jié)構(gòu),用來存儲運(yùn)行時指針相關(guān)信息。改進(jìn)指針?biāo)惴ㄔ诔绦蜻\(yùn)行時為每個指針變量維護(hù)一個pmd。pmd結(jié)構(gòu)存儲對應(yīng)指針?biāo)脙?nèi)存對象的基地址(base)、邊界地址(bound)以及內(nèi)存對象的snd地址,pmd結(jié)構(gòu)定義為:

        1: typedef struct{

        2:? ? ?void *base;

        3:? ? ?void *bound;

        4:? ? ?SND *snda;

        5: }PMD;

        改進(jìn)指針?biāo)惴ㄔ跈z查內(nèi)存泄漏上可以做到非常細(xì)粒度,這是其他工具所不具備的優(yōu)勢。第2行執(zhí)行賦值語句后,指針p2和p1同時指向同一塊8個字節(jié)的堆內(nèi)存,它們的pmd共享同一個snd:

        1:p1 = (int*)malloc(8);2:p2 = p1;3:int i; p1 = &i;4:p2 = &i; /*mem leak*/

        第3行賦值語句執(zhí)行后,狀態(tài)如圖1(a)所示,p1指針指向變量i的首地址,pmd引用了變量i的snd,因此指向堆內(nèi)存的指針減1,相應(yīng)snd的count也減1。第4行賦值語句執(zhí)行后,狀態(tài)如圖1(b)所示。p2指針不再指向堆內(nèi)存,p2指針pmd引用變量i的snd,此時8個字節(jié)的堆內(nèi)存沒有指針指向它,因此其snd的count值為0。在檢查到堆內(nèi)存的count值為0后,內(nèi)存泄漏的錯誤將被報出,因為沒有指針指向這塊內(nèi)存。

        1.2? shared-_ptr原理分析

        閱讀C++STL源碼可知,shared_ptr的_M_use_count變量值為0是判斷內(nèi)存泄漏的必要條件,shared_ptr部分重要源碼:

        1:? __shared_count<_Lp>? _M_refcount;? ? ?// Reference counter

        2: _Sp_counted_base<_Lp>*? _M_pi; //__shared_count類私有變量

        3: typedef int _Atomic_word; ? ? ?//C++標(biāo)準(zhǔn)庫的GNU擴(kuò)展文件atomic_word.h

        4:? _Atomic_word? _M_use_count;? ? ? ? // _Sp_counted_base類私有變量

        5: inline void _Sp_counted_base<_S_single>::_M_add_ref_copy()

        6: { ++_M_use_count; } ? ? ?//_Sp_counted_base類的內(nèi)聯(lián)函數(shù)

        7: _Sp_counted_base<_S_single>::_M_release() noexcept

        8: if (--_M_use_count == 0){

        9: _M_dispose();? ? ? //當(dāng)_M_use_count自減到0,釋放資源? ? ?...}

        代碼均來自C++11標(biāo)準(zhǔn)模板庫源文件。

        _M_refcount是shared_ptr模板類的成員變量,它是用于處理引用計數(shù)最核心的變量。_M_refcount的類型__shared_count也是一個模板類,這個類有一個私有指針變量_M_pi,所有指向同一動態(tài)對象的shared_ptr都共享同一個_M_pi變量,如第2行所示。_M_pi變量指向的_Sp_counted_base類型有一個int類型的_M_use_count變量,如第3、第4行所示。_M_use_count變量表示引用數(shù),每當(dāng)有新的shared_ptr通過函數(shù)調(diào)用或拷貝等操作指向同一個動態(tài)對象時,_M_pi變量都會調(diào)用如第5、第6行所示的內(nèi)聯(lián)函數(shù)_M_add_ref_copy,將_M_use_count值加1。當(dāng)指向某動態(tài)對象的shared_ptr不再指向該動態(tài)對象時,其析構(gòu)函數(shù)會使_M_pi變量調(diào)用_M_release(),將_M_use_count值減1,_M_release()也會在此時判斷無用動態(tài)對象。如第7~9行所示,_M_release()函數(shù)調(diào)用將M_use_count值減1后示,若_M_use_count值為0,則表示最后一個指向該動態(tài)對象的shared_ptr被銷毀或最后一個指向該動態(tài)對象的shared_ptr通過操作符“=”或reset函數(shù)調(diào)用被賦值為其他值,檢測產(chǎn)生內(nèi)存泄漏,因此調(diào)用_M_dispose()來釋放無用動態(tài)對象。

        2? 無法檢測的內(nèi)存泄漏介紹

        通過改進(jìn)指針?biāo)惴ê蛃hared_ptr判斷的堆內(nèi)存對象泄漏都是依據(jù)引用計數(shù)值“PREFIXcount”為0來判斷的。然而,我們在調(diào)試專業(yè)測試集時發(fā)現(xiàn)當(dāng)“PREFIXcount”值大于0時,也存在內(nèi)存泄漏和無用動態(tài)對象。在程序中的表現(xiàn)為:存在數(shù)量大于等于1的指針指向該內(nèi)存對象,但是這些指針無法獲取,從而導(dǎo)致內(nèi)存泄漏?!爸羔樧灾浮本褪瞧渲幸环N:

        /*point-self*/

        1:#include <malloc.h>

        2:int main()

        3:{

        4: int **m, i = 5;

        5: m = malloc(sizeof(int*)*6);

        6: m[i] = (int*)m;

        7: m = 0;? /* mem leak*/

        8: return 0;}

        第5行賦值語句執(zhí)行后,指針m指向一塊容納6個“int*”類型變量的內(nèi)存對象首地址。第6行賦值語句執(zhí)行后,m[i]相當(dāng)于*(m+5)向該內(nèi)存尾部空間寫進(jìn)了m變量的值(即該內(nèi)存首地址)。當(dāng)?shù)?行中的m變量通過賦值語句指向它時,會發(fā)生內(nèi)存泄漏,狀態(tài)如圖2所示。雖然仍然有指針指向該堆內(nèi)存對象,但是指向它的指針來自于自身空間的內(nèi)部指針,由于任何方式都無法獲取內(nèi)部指針,因此導(dǎo)致內(nèi)存泄漏。

        另一種“循環(huán)引用”也會導(dǎo)致這種內(nèi)存泄漏:

        /*Memory leaks on memory circles.*/

        1:#include <malloc.h>

        2:typedef struct st {

        3:? ? int i;

        4:? ?struct st *next;

        5:} st;

        6:int main(){

        7: st *m, *n;

        8: m = malloc(sizeof(st));

        9: n = malloc(sizeof(st));

        10: n->next = m;

        11: m->next = n; //構(gòu)成循環(huán)狀態(tài)

        12: m=0;

        13: n=0;? ? ? ? /*mem leak*/ return 0;}

        循環(huán)引用代碼

        第8、第9行賦值語句執(zhí)行后,指針m和指針n分別指向一個容納st類型變量的內(nèi)存對象首地址。第10、第11行使這兩個內(nèi)存對象的內(nèi)部指針“struct st *next”形成互指彼此內(nèi)存對象的狀態(tài),因此在第12、第13行執(zhí)行后,引用這兩個內(nèi)存對象的指針只來自彼此內(nèi)部,形成了一個沒有起點的環(huán),此時的狀態(tài)如圖3所示。因此在程序運(yùn)行到圖2和圖3這兩種狀態(tài)時,改進(jìn)指針?biāo)惴ê蛃hared_ptr的“計數(shù)值”都大于0,根據(jù)它們“計數(shù)值”大于0的描述,這個內(nèi)存對象是有用的,但是事實上已經(jīng)存在內(nèi)存泄漏。

        3? 改進(jìn)方案

        雖然C++1x提供了一個解決方案,但是該方案過于依賴用戶,需要開發(fā)人員在使程序構(gòu)成循環(huán)時,利用weak_ptr的弱引用替換部分shared_ptr的強(qiáng)引用,程序編寫者通過手動破壞循環(huán)結(jié)構(gòu)來解決shared_ptr的設(shè)計缺陷。我們需要實現(xiàn)自動化和智能化的工具,目的是解決人為原因帶來的易錯性、低效性和不可靠性問題,靠開發(fā)人員自己發(fā)現(xiàn)程序特定缺陷并做出相應(yīng)修改是非常低效的。

        shared_ptr的設(shè)計丟失了動態(tài)對象信息,所有指向同一個動態(tài)對象的指針都共享同一個_Sp_counted_base類型_M_pi,但是_Sp_counted_base類私有變量只有“計數(shù)值”和一系列用來更新“計數(shù)值”的接口。判斷程序是否存在“指針自指”,需要獲取內(nèi)存對象的信息,由于shared_ptr的功能單一和對高性能的追求,并沒有記錄動態(tài)對象的具體信息。相較于shared_ptr的設(shè)計,改進(jìn)指針?biāo)惴ㄓ涗浀膬?nèi)存對象信息更加具體和完善。用pmd和snd的聯(lián)接,模擬了指針指向內(nèi)存對象的狀態(tài),指針pmd包含了所指內(nèi)存對象的基地址和邊界。因此改進(jìn)指針?biāo)惴ㄓ涗浀臓顟B(tài)信息更用于實現(xiàn)對該類型錯誤的檢測。

        根據(jù)改進(jìn)指針?biāo)惴ǖ脑创a,我們提出完善改進(jìn)指針?biāo)惴ǖ臋z測接口,在指針pmd與snd將要解綁時,執(zhí)行“指針自指”算法:掃描存儲pmd的hash表,查找當(dāng)前“解綁”pmd記錄的邊界內(nèi)自指指針數(shù)和對應(yīng)snd的count是否相同,若相同snd則可判斷出發(fā)生“指針自指”,導(dǎo)致內(nèi)存泄漏。然后采用深度遍歷的方式,逐個解綁該內(nèi)存泄漏范圍內(nèi)的指針pmd。

        4? 結(jié)? 論

        利用C/C++語言編寫項目后,可以使用改進(jìn)指針?biāo)惴ê蛃hared_ptr來檢測普通的內(nèi)存泄漏。完善后的改進(jìn)指針?biāo)惴ㄒ部梢詸z測“指針自指”發(fā)生的內(nèi)存泄漏,但是盡量避免編寫“循環(huán)引用”代碼結(jié)構(gòu),因為本文論證了該結(jié)構(gòu)導(dǎo)致的內(nèi)存泄漏,目前C/C++尚未找到一個較為完備的檢測算法來對內(nèi)存泄漏進(jìn)行檢測和預(yù)防。甚至是Google公司開發(fā)的內(nèi)存安全性動態(tài)分析工具AddressSanitizer和國內(nèi)基于改進(jìn)指針?biāo)惴▽崿F(xiàn)的Movec都無法完全檢測出C/C++程序中“循環(huán)引用”導(dǎo)致的內(nèi)存泄漏。

        參考文獻(xiàn):

        [1] 朱云龍.C程序運(yùn)行時監(jiān)控和驗證的插樁方法研究與應(yīng)用 [D].南京:南京航空航天大學(xué),2016.

        [2] CHEN Z,TAO C Q,ZHANG Z Y,et al. Poster: Beyond Spatial and Temporal Memory Safety [C]//2018 IEEE/ACM 40th International Conference on Software Engineering: Companion (ICSE-Companion). Gothenburg:IEEE,2018:189-190.

        [3] 嚴(yán)峻琦.C程序內(nèi)存安全錯誤的運(yùn)行時檢測技術(shù)研究與實現(xiàn) [D].南京:南京航空航天大學(xué),2017.

        [4] 葉蓉,陳榕.運(yùn)用CAR智能指針實現(xiàn)Callback機(jī)制 [J].計算機(jī)技術(shù)與發(fā)展,2008(2):9-12+16.

        [5] 張彤,何源.一種自適應(yīng)的引用計數(shù)智能指針的實現(xiàn) [J].成都大學(xué)學(xué)報(自然科學(xué)版),2007(1):55-57.

        作者簡介:仵?。?997—),男,漢族,江蘇南京人,碩士研究生在讀,研究方向:軟件驗證。

        猜你喜歡
        程序
        給Windows添加程序快速切換欄
        電腦愛好者(2020年6期)2020-05-26 09:27:33
        試論我國未決羈押程序的立法完善
        失能的信仰——走向衰亡的民事訴訟程序
        “程序猿”的生活什么樣
        英國與歐盟正式啟動“離婚”程序程序
        基于VMM的程序行為異常檢測
        偵查實驗批準(zhǔn)程序初探
        我國刑事速裁程序的構(gòu)建
        創(chuàng)衛(wèi)暗訪程序有待改進(jìn)
        恐怖犯罪刑事訴訟程序的完善
        91精品国产一区国产二区久久| 久久精品国产亚洲vr| 国内精品久久久久久久久蜜桃| 中文字幕视频一区二区| 日本xxxx色视频在线观看免费| 日本牲交大片免费观看| 亚洲AV永久青草无码性色av| 国产人妖一区二区av| 亚洲天堂精品成人影院| 成人网站免费看黄a站视频| 午夜性刺激免费视频| 国产内射视频在线观看| 亚洲精品第一页在线观看| 大肉大捧一进一出好爽视频| 草莓视频一区二区精品| 亚洲中文字幕日本日韩| 丝袜美腿一区二区国产| 中国熟妇人妻xxxxx| 国产高清国内精品福利99久久| 国产一区二区在线中文字幕| 久久久久九九精品影院| 亚洲国产高清在线一区二区三区| 亚洲中出视频| 国产精品一二三区亚洲| 私人vps一夜爽毛片免费| 色先锋资源久久综合5566| 女同另类激情在线三区| 国产一区二区长腿丝袜高跟鞋 | 免费人妖一区二区三区| 九九久久自然熟的香蕉图片| av网站免费线看| 亚洲一区二区三区品视频| 日本一区二区视频免费在线看| 国产精品丝袜久久久久久不卡| 巨臀中文字幕一区二区| 国产精品亚洲一二三区| 国产啪亚洲国产精品无码| 国产中文制服丝袜另类| 国产91在线精品观看| 国模精品一区二区三区| 99这里只有精品|