內存調試工具Electric Fence


源碼下載地址

注:官方地址下載不了,可能不再維護了,此是一個老項目

efence中相關環境變量控制:

302     /*
303      * See if the user wants to allow malloc(0).
304      */
305     if ( EF_ALLOW_MALLOC_0 == -1 ) {
306         if ( (string = getenv("EF_ALLOW_MALLOC_0")) != 0 )
307             EF_ALLOW_MALLOC_0 = (atoi(string) != 0);
308         else
309             EF_ALLOW_MALLOC_0 = 0;
310     }  

 

 gdb的局限性:

有的時候,gbd 給出的 crash 上下文其實並不是真正發生問題的第一現場,在多線程程序設計中,這種情景會讓 bug 的追查陷入誤區。

內存調試工具Electric Fence

使用 electric-fence 調試內存越界

Electric-fence 介紹

electric-fence 原理如下:

  • 重寫malloc、free、realloc、calloc、valloc 函數,對於C++ 應使用 extern “C”; C 使用 extern 來導出符號;以確保應用程序使用  electric-fence 的malloc等函數
  • 系 統調用malloc會多分配一個page(注意是 虛存)  然后根據是否EF_PROTECT_BELOW 設置來決定返回新分配內存區的高地址(或低地址)給user;同時,調用 mprotect((caddr_t)address, size, PROT_NONE) 來設置多分配的page頁為不可訪問;這樣一旦程序越界便會進入不可訪問區間,因此coredump。同時,EF_ALIGNMENT 也會影響到該處。
  • electric-fence  內存管理的實現基本思路為:a. 每次向操作系統申請MEMORY_CREATION_SIZE(當前為1M)字節內存,使用mmap完成; b. 存在一片內存區 用於存放 所有 slot 信息, slot 用於管理被分配的內存信息,如返回給用戶的地址以及其內部實際地址、size等; c. 分配時從當前slot 中查找是否有能滿足分配需求的內存區,這里注意的是每次實際分配的內存區大小比用戶請求的至少要大 一個page,大致公式為:  real_size = user_size + (alignment – (user_size  % alignment )) + page_size;   若存在則拆分內存區,修改相關slot信息 d. free  內存時不會將內存交給操作系統,而是設置free或者標志PROTECTED,PROTECTED意味着該片內存不會被再次分配,由 EF_PROTECT_FREE 控制。 若設置了EF_FREE_WIPES,還會用0xbd填充用戶free的區域。

electric-fence 也有如下的缺點:

  1. 每一次分配都是利用一個 semaphore 同步,沒有 thread local 的分配
  2. malloc 和 free 在 slot 都是線性查找,這也造成了整體性能的落后
  3. 內存消耗大,這個是顯然的,特別對於頻繁的小內存分配

2,3 點都是造成整個 lib 性能較低的原因。簡單說,這還是一個比較簡陋的工具,如果能借鑒 tcmalloc, jemalloc 等設計可能會更好一點。

 

注意:我在hi3520下使用時有如下錯誤:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x40ce94c0 (LWP 779)]
memalign (alignment=4, userSize=56) at efence.c:498
498                      && slot->internalSize >= internalSize ) {
(gdb) bt
#0  memalign (alignment=4, userSize=56) at efence.c:498
#1  0x0074a2d4 in malloc (size=55) at efence.c:821
#2  0x4038cc60 in operator new(unsigned int) () from /lib/libstdc++.so.6
#3  0x40369e68 in std::string::_Rep::_S_create(unsigned int, unsigned int, std::allocator<char> const&) () from /lib/libstdc++.so.6
#4  0x4036a818 in std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned int) () from /lib/libstdc++.so.6
#5  0x4036b39c in std::string::reserve(unsigned int) ()
   from /lib/libstdc++.so.6
#6  0x4036b5e8 in std::string::append(char const*, unsigned int) ()
   from /lib/libstdc++.so.6
#7  0x00135c24 in Thread::trace (this=0x403ebfd8, name=0x783070 "loop", 
    file=0x783075 "util/trace/tracer.cpp", line=505, func=0x782fa0 "run", 
    time=1478188527) at util/trace/tracer.cpp:88
#8  0x00135de0 in Tracer::trace (this=0x403b8fac, name=0x783070 "loop", 
    file=0x783075 "util/trace/tracer.cpp", line=505, func=0x782fa0 "run", 
    time=1478188527) at util/trace/tracer.cpp:725
#9  0x0013456c in traceOut (name=0x783070 "loop", 
    file=0x783075 "util/trace/tracer.cpp", line=505, func=0x782fa0 "run")
    at util/trace/if_trace.cpp:110
#10 0x0013559c in Logger::run (arg=<optimized out>)
    at util/trace/tracer.cpp:505
#11 0x401e2f9c in start_thread () from /lib/libpthread.so.0
#12 0x40245b58 in clone () from /lib/libc.so.0
#13 0x40245b58 in clone () from /lib/libc.so.0
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) q


496     for ( slot = allocationList, count = slotCount ; count > 0; count-- ) {
497         if ( slot->mode == FREE
498          && slot->internalSize >= internalSize ) {
499             if ( !fullSlot
500              ||slot->internalSize < fullSlot->internalSize){
501                 fullSlot = slot;
502                 if ( slot->internalSize == internalSize                                                                                                                                                  
503                  && emptySlots[0] )
504                     break;  /* All done, */
505             }
506         }
507         else if ( slot->mode == NOT_IN_USE ) {
508             if ( !emptySlots[0] )
509                 emptySlots[0] = slot;
510             else if ( !emptySlots[1] )
511                 emptySlots[1] = slot;
512             else if ( fullSlot
513              && fullSlot->internalSize == internalSize )
514                 break;  /* All done. */
515         }
516         slot++;
517     }


extern C_LINKAGE void *
malloc(size_t size)
{
        void  *allocation;   
 
        if ( allocationList == 0 ) {
                pthread_mutex_init(&mutex, NULL);
                initialize();   /* This sets EF_ALIGNMENT */
        }       
        lock();
        allocation=memalign(EF_ALIGNMENT, size);

        unlock();
                                                                                                                                                                                                             
▸   return allocation;
}

1、查看對應的錯誤點,發現相關變量都是正常的

2、frame 1到frame 0中的size莫名奇妙的發生了變化

3、基於這些原因,最終沒有應用起來,不知道為什么?是否程序真的有越界行為導致

問題:

若出現segment fault錯誤,對應的pc指針是否為導致該錯誤的直接原因,還是這個pc指針是隨機的?

答:pc僅能作為參考,segment fault應是通過signal機制實現的,具體需要進一步研究

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM