linux下常见内存异常查证工具和方法介绍

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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即可定位出错代码行

[email protected]:/home/zte/test# gcc null.cc -g
[email protected]:/home/zte/test# ./a.out 
Segmentation fault (core dumped)
[email protected]:/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后,再运行就会抛异常。下面是具体命令执行结果。

[email protected]:/home/zte/test# gcc t.c
[email protected]:/home/zte/test# ./a.out 
[email protected]:/home/zte/test# gcc t.c -fstack-protector -fstack-protector-all -g
[email protected]:/home/zte/test# ./a.out 
*** stack smashing detected ***: ./a.out terminated
Aborted (core dumped)

可以进一步用gdb的bt命令定位出问题的函数。

[email protected]:/home/zte/test# gdb a.out core
。。。。。。。。
Core was generated by `./a.out‘.
Program terminated with signal SIGABRT, Aborted.
#0  0x00007f6bcfab5c37 in __GI_raise ([email protected]=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 ([email protected]=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0x00007f6bcfab9028 in __GI_abort () at abort.c:89
#2  0x00007f6bcfaf22a4 in __libc_message ([email protected]=1, [email protected]=0x7f6bcfc01d70 "*** %s ***: %s terminated\n")
    at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007f6bcfb8d83c in __GI___fortify_fail (msg=<optimized out>, [email protected]=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打印即可定位到问题代码行。

[email protected]:/home/zte/test# gcc malloc_read_free.cc -lefence -g
[email protected]:/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下常见内存异常查证工具和方法介绍的主要内容,如果未能解决你的问题,请参考以下文章

Linux下检测内存泄露的工具 valgrind

排查软件异常的常见思路与方法

linux c程序内存泄漏检测工具-mtrace工具介绍

Linux下找出吃内存的方法总结

Java内存溢出异常(下)

Linux系统常见异常分析