1. 程式人生 > >linux下常見內存異常查證工具和方法介紹

linux下常見內存異常查證工具和方法介紹

linux 內存異常 efence 函數棧

linux下常見內存異常查證工具和方法介紹

內存異常導致的異常往往很難查證,本文介紹在linux下的各種常見內存異常的查證工具和方法。

1、訪問空指針/未初始化指針

這個是最簡單的內存異常了,只要能夠生成coredump文件,可以快速定位問題代碼。

開啟coredump

部分環境下默認不會生成coredump,需要運行如下命令:
ulimit -c unlimited //unlimited表示不限制coredump文件大小,也可以指定一個最大文件大小。

定制core文件名

默認的coredump文件名為core,如果想自己定制core文件名,可以運行如下命令:
echo “./core-%e-%p-%t” > /proc/sys/kernel/core_pattern


可以在core_pattern模板中使用變量還很多,見下面的列表:
%% 單個%字符
%p 所dump進程的進程ID
%u 所dump進程的實際用戶ID
%g 所dump進程的實際組ID
%s 導致本次core dump的信號
%t core dump的時間 (由1970年1月1日計起的秒數)
%h 主機名
%e 程序文件名

使用gdb定位代碼行

問題代碼

int main()
{
    int *p=0;
    *p=6;
    return 0;
}

使用gcc -g編譯後運行出現異常,通過gdb即可定位出錯代碼行

root@ubuntu:/home/zte/test# gcc null.cc -g
root@ubuntu:/home/zte/test# ./a.out 
Segmentation fault (core dumped)
root@ubuntu:/home/zte/test# gdb a.out core
.......
Core was generated by `./null‘.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00000000004004fd in main () at null.cc:4
4        *p=6;

2、函數棧溢出

局部變量的寫越界可能會破壞函數棧幀導致程序coredump,由於默認不會在越界的第一現場coredump,導致問題查證非常困難。
幸運的是我們可以通過gcc的編譯選項-fstack-protector 和 -fstack-protector-all在函數棧被破壞的第一現場就coredump,從而可以方便地定位問題。

示例

int main()
{
    int a=5;
    int *p=&a;
    p[3]=6;
    return 0;
}

上面代碼會破壞函數棧,如果我們用gcc直接編譯運行,不會拋異常。但是加了編譯參數-fstack-protector 和 -fstack-protector-all後,再運行就會拋異常。下面是具體命令執行結果。

root@ubuntu:/home/zte/test# gcc t.c
root@ubuntu:/home/zte/test# ./a.out 
root@ubuntu:/home/zte/test# gcc t.c -fstack-protector -fstack-protector-all -g
root@ubuntu:/home/zte/test# ./a.out 
*** stack smashing detected ***: ./a.out terminated
Aborted (core dumped)

可以進一步用gdb的bt命令定位出問題的函數。

root@ubuntu:/home/zte/test# gdb a.out core
。。。。。。。。
Core was generated by `./a.out‘.
Program terminated with signal SIGABRT, Aborted.
#0  0x00007f6bcfab5c37 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56    ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  0x00007f6bcfab5c37 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0x00007f6bcfab9028 in __GI_abort () at abort.c:89
#2  0x00007f6bcfaf22a4 in __libc_message (do_abort=do_abort@entry=1, fmt=fmt@entry=0x7f6bcfc01d70 "*** %s ***: %s terminated\n")
    at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007f6bcfb8d83c in __GI___fortify_fail (msg=<optimized out>, msg@entry=0x7f6bcfc01d58 "stack smashing detected")
    at fortify_fail.c:38
#4  0x00007f6bcfb8d7e0 in __stack_chk_fail () at stack_chk_fail.c:28
#5  0x00000000004005aa in main () at t.c:7
(gdb) q

3、越界讀寫動態分配內存/讀寫已釋放動態分配內存

動態分配內存讀寫越界、讀寫已釋放動態分配內存系統默認可能不會拋異常,我們可以使用electric-fence來使得讀寫越界內存立刻拋異常,加速問題定位。

安裝Electric fence

sudo apt-get install electric-fence

使用Electric fence

下面是越界寫代碼

#include <stdlib.h>

int main()
{
    int *p = (int*)malloc(sizeof(int));
    p[1] = 6;
    return 0;
}

如果使用gcc直接編譯運行,不會拋異常。
我們可以加上參數 -lefence -g編譯後運行,就會拋異常。通過gdb的bt打印即可定位到問題代碼行。

root@ubuntu:/home/zte/test# gcc malloc_read_free.cc -lefence -g
root@ubuntu:/home/zte/test# ./a.out 

  Electric Fence 2.2 Copyright (C) 1987-1999 Bruce Perens <[email protected]>
Segmentation fault (core dumped)

4、動態分配內存重復釋放

默認會拋異常,通過gdb和coredump即可定位。

generated by haroopad

本文出自 “鄔領東的博客” 博客,請務必保留此出處http://13484557.blog.51cto.com/13474557/1983537

linux下常見內存異常查證工具和方法介紹