2016-06-09 130 views
1

下面的程序不會觸發斷言失敗:jemalloc未檢測內存損壞

int main(int argc, char **argv) 
{ 
    int * n = (int *)malloc(100); 
    //malloc_stats_print(nullptr, nullptr, "gablh"); 
    free(n); 
    *n += 1; 
    std::cerr << *n << std::endl; 
    for (int i = 0; i != 10; ++i) { 
    std::cerr << *(n+i) << std::endl; 
    } 
} 

當我運行程序 MALLOC_CONF="quarantine:32,abort:true,stats_print:true" ex_stats_pr

我得到:

1515870811 
1515870811 
1515870810 
1515870810 
1515870810 
1515870810 
1515870810 
1515870810 
1515870810 
1515870810 
1515870810 

是否有辦法用jemalloc觸發中止失敗?

+0

阿彌陀佛,jemalloc有任何檢查機會嗎?你的程序是免費的,然後試圖破壞內存,打印一些內容然後退出,而不需要額外調用jemalloc。例如,隔離選項應該與valgrind一起使用,而不僅僅是普通的運行(valgrind可以做一些檢查):http://linux.die.net/man/3/jemalloc「隔離內存在釋放之前不會被釋放來自隔離,...此功能特別與Valgrind [2]結合使用,可檢測訪問隔離對象的嘗試。「 – osgx

回答

0

這還不是很直接回答你的問題,但是...

未定義行爲是不確定的。與釋放的記憶一起玩進這個陣營。根據你的內存處理程序的實現,你可能會有一個「驗證內存」類型的函數,它沿着你的空閒內存列表來查看是否存在某種類型的損壞,但即使這樣也不會捕獲所有內容特別是我自己熟悉jemalloc)。這可能是因爲你的上面的代碼碰到沒有人關心的內存,所以不會被捕獲。哎呀,你的std::cerr聲明也在做未定義的行爲,所以你甚至不能相信它的值(想想線程和操作系統抓取和改變內存等)

這是你不直接使用指針的原因之一儘可能使用C++。管理生命週期的智能指針和容器可以自動防止幾乎所有這些類型的錯誤。

0

您期望jemalloc檢測到一個寫入釋放的內存和一些釋放內存的讀取。

但jemalloc庫不具備此功能。其調試模式僅檢測導致內存損壞的一組有限的錯誤。例如雙釋放。

這不是一個任意的限制,因爲像jemalloc這樣的庫只是無法檢測到任何類型的內存訪問錯誤。這意味着作爲一個庫,它可以輕鬆地重載malloc()/ free()等,並安裝一個退出處理程序。因此調試模式實現可以有效地實現有限的一組檢查。當然,每個調試模式實現都會選擇自己的權衡。例如,jemalloc在空閒期間也不會檢測到簡單的緩衝區溢出,儘管其他具有調試功能的庫(例如Solaris'libumem)實現了輕量級機制,其中檢查了一些特殊的尾部字節的完整性。

對於像jemalloc這樣的庫來檢測對已釋放內存的讀/寫操作,它必須將調試器樣式的手錶安裝到每個釋放區域中,這樣會變得非常複雜並且會產生大量的運行時間開銷 - 如果這樣會擴大許多和大的分配,完全可以。

問題是:jemalloc是檢測寫入釋放的內存(A)和讀取釋放的內存(B)的錯誤工具。

例如,GCC和Clang附帶的Address Sanitizer-fsanitize=address)能夠檢測到(A),但不能檢測到(B)。並且Valgrindvalgrind --tool=memcheck)能夠檢測到(A)和(B)並將這些問題報告爲無效的讀/寫入釋放的塊。這兩種工具肯定比分配程序庫的簡單調試模式具有更高的運行時間開銷。而且,由於valgrind的方法是模擬CPU,因此其開銷遠高於Address Sanitizer的開銷。