linux下常見內存異常查證工具和方法介紹
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下常見內存異常查證工具和方法介紹