注:官方地址下載不了,可能不再維護了,此是一個老項目
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 也有如下的缺點:
- 每一次分配都是利用一個 semaphore 同步,沒有 thread local 的分配
- malloc 和 free 在 slot 都是線性查找,這也造成了整體性能的落后
- 內存消耗大,這個是顯然的,特別對於頻繁的小內存分配
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機制實現的,具體需要進一步研究