转自:http://www.cnblogs.com/jiayy/p/3475544.html

偶然中发现,下面的两端代码表现不一样
void main(){
  void* p1 = malloc(32);
      free(p1);
  free(p1); // 这里会报double free 错误,程序退出
}
void main(){
  void* p1 = malloc(32);
  void* p2 = malloc(32);
  free(p1);
  free(p2);
  free(p1); // 正常没有报错
  free(p2);//正常,没有报错
  ...
}
我就开始疑惑,难道glibc malloc库对doublefree错误的检测那么傻B,只有连续两次free的指针一样才能检测出来?然后又尝试了memset溢出的情况,如下
void main(){
  void* p1 = malloc(32);
  memset(p1,1,64); // 这里溢出了p1
  void* p2 = malloc(32); // 
  printf("p1=%p,p2=%p\n",p1,p2); // 打印发现,malloc没有检测 memset的溢出影响
}
经过搜索,发现了,原来glibc malloc 库有一个环境变量MALLOC_CHECK_,当其值是0的时候,对上述两种情况(不连续地free同一段虚拟内存,memset溢出)是没有检测的,当我将其值设置为1/2/3时,对上述情况都会正常报错。经过这次测试,建议各位在开发过程中,最好是将MALLOC_CHECK_设置为非0,等到发布的时候,才将其值设置为0提升速度。
下面是glibc malloc调试相关的环境变量或工具说明,是比较好的参考
 
 
 
(转)
一)MALLOC_CHECK_
 
GNU的标准库(glibc)可以通过内置的调试特性对动态内存进行调试,它就是MALLOC_CHECK_环境变量,
它在默认情况下是不设定的,在老的版本默认这个值为0,新的版本默认值为2,但有一个矛盾,如果设定为空,它将会打印出长长的跟踪信息,这比设为2更详细.
 
MALLOC_CHECK_有三种设定,即:
MALLOC_CHECK_=0 ----- 关闭所有检查.
MALLOC_CHECK_=1 ----- 当有错误被探测到时,在标准错误输出(stderr)上打印错误信息.
MALLOC_CHECK_=2 ----- 当有错误被探测到时,不显示错误信息,直接进行中断.
 
 
我们用下面的小程序做一下测试,源程序如下:
#include <stdio.h>
#include <stdlib.h>
 
int main (int argc,char *argv[])
{
        int i;
        char* p = (char *)malloc(10);
        char* pt = p;
 
        for (i = 0;i < 10;i++)
        {
                p[i] = 'z';
        }
        free (p);
        free(pt);
        return 0;
}
gcc double-free.c -o double-free
 
注:这个程序会释放两次指针.
echo $MALLOC_CHECK_
 
我们在MALLOC_CHECK_默认设定的情况下,执行test程序,输出如下的信息:
 ./test 
*** glibc detected *** ./test: double free or corruption (fasttop): 0x0890f008 ***
======= Backtrace: =========
/lib/libc.so.6[0x175f7d]
/lib/libc.so.6(cfree+0x90)[0x1795d0]
./test[0x80483dc]
/lib/libc.so.6(__libc_start_main+0xdc)[0x125dec]
./test[0x8048301]
======= Memory map: ========
00110000-00247000 r-xp 00000000 08:01 3704502    /lib/libc-2.5.so
00247000-00249000 r-xp 00137000 08:01 3704502    /lib/libc-2.5.so
00249000-0024a000 rwxp 00139000 08:01 3704502    /lib/libc-2.5.so
0024a000-0024d000 rwxp 0024a000 00:00 0 
00b51000-00b6a000 r-xp 00000000 08:01 3704501    /lib/ld-2.5.so
00b6a000-00b6b000 r-xp 00018000 08:01 3704501    /lib/ld-2.5.so
00b6b000-00b6c000 rwxp 00019000 08:01 3704501    /lib/ld-2.5.so
00bf3000-00bf4000 r-xp 00bf3000 00:00 0          [vdso]
00dab000-00db6000 r-xp 00000000 08:01 3704511    /lib/libgcc_s-4.1.1-20070105.so.1
00db6000-00db7000 rwxp 0000a000 08:01 3704511    /lib/libgcc_s-4.1.1-20070105.so.1
08048000-08049000 r-xp 00000000 08:01 327681     /root/test
08049000-0804a000 rw-p 00000000 08:01 327681     /root/test
0890f000-08930000 rw-p 0890f000 00:00 0 
b7e00000-b7e21000 rw-p b7e00000 00:00 0 
b7e21000-b7f00000 ---p b7e21000 00:00 0 
b7f26000-b7f27000 rw-p b7f26000 00:00 0 
b7f3b000-b7f3c000 rw-p b7f3b000 00:00 0 
bfdcf000-bfde4000 rw-p bfdcf000 00:00 0          [stack]
Aborted
 
这里我们调整MALLOC_CHECK_为0,再次运行程序,如下:
export MALLOC_CHECK_=0
./test 
注:我们看到程序没有任何输出.
 
我们将MALLOC_CHECK_调整为1,再次运行程序,如下:
export MALLOC_CHECK_=1
./test 
malloc: using debugging hooks
*** glibc detected *** ./test: free(): invalid pointer: 0x0811e008 ***
注:我们看到每次运行程序都会有malloc: using debugging hooks的输出,同时程序检测到free()两次释放的问题.
 
我们将MALLOC_CHECK_调整为2,再次运行程序,如下:
export MALLOC_CHECK_=2
./test 
Aborted
注:我们看到程序只输出了Aborted,并中断了程序的运行.
 
 
 
二)用mtrace查找内存泄露
 
mtrace是由glibc提供的一个工具,在Redhat中将它打包在glibc-utils包中.
 
我们安装此包,如下:
rpm -ivh /mnt/Server/glibc-utils-2.5-12.i386.rpm
 
mtrace的主要作用是查找内存泄露,为了应用mtrace程序,必须在代码中使用glibc提供的函数mtrace和muntrace.另外,必须设置一个文件的名字给环境变量MALLOC_TRACE,因为glibc利用它为mtrace程序存储数据.
当执行完代码后,数据将会存在这个确认的文件中,每执行一次程序,这个文件的内容都会被重写.
 
我们用下面的代码进行测试,如下:
 
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <mcheck.h>
 
 
int main (int argc,char *argv[])
{
        setenv("MALLOC_TRACE","output",1);
        mtrace();
        int i;
        char* p = (char *)malloc(10);
        char* pt = p;
 
        for (i = 0;i < 10;i++)
        {
                p[i] = 'z';
        }
        return 0;
}
 
编译:
gcc test.c -o test
 
注:程序用setenv函数设定环境变量MALLOC_TRACE
 
运行程序:
./test 
 
这时在当前目录下生成了一个名为output的文件,如下:
cat output 
= Start
@ ./test:[0x80483f2] + 0x82ba438 0xa
@ /lib/libc.so.6:(clearenv+0x7c)[0xb9910c] - 0x82ba008
@ /lib/libc.so.6:(tdestroy+0x47)[0xc39b77] - 0x82ba090
@ /lib/libc.so.6:(tdestroy+0x4f)[0xc39b7f] - 0x82ba0b0
 
用mtrace查找内存泄露,它告诉我们memory not freed
mtrace output 
- 0x082ba008 Free 3 was never alloc'd 0xb9910c
- 0x082ba090 Free 4 was never alloc'd 0xc39b77
- 0x082ba0b0 Free 5 was never alloc'd 0xc39b7f
 
Memory not freed:
-----------------
   Address     Size     Caller
0x082ba438      0xa  at 0x80483f2
 
 
 
 
三)使用memusage收集内存统计数据
 
memusage不需要在代码中做出任何指示.这个工具也来自由glibc-utils包.它以柱形显示程序占用了多少内存.它默认输出到标准输出中,用ASCII文本显示一个绘成图画似的柱形.如下:
memusage awk 'BEGIN{print "hello world"}'
hello world
 
Memory usage summary: heap total: 7487, heap peak: 6891, stack peak: 8624
         total calls   total memory   failed calls
 malloc|         58           7487              0
realloc|          0              0              0  (nomove:0, dec:0, free:0)
 calloc|          0              0              0
   free|         15            797
Histogram for block sizes:
    0-15             27  46% ==================================================
   16-31              7  12% ============
   32-47              2   3% ===
   48-63              6  10% ===========
   64-79              1   1% =
   80-95              1   1% =
   96-111             1   1% =
  112-127             4   6% =======
  160-175             1   1% =
  176-191             2   3% ===
  192-207             1   1% =
  208-223             2   3% ===
  384-399             1   1% =
  480-495             1   1% =
 4000-4015            1   1% =
 
 
 
 
四)使用Electric Fence检测内存泄漏
 
Electric Fence用一些巧妙的技术来检测程序在堆内存区上的溢出,不需要用Electric Fence来修改代码,相反,它提供一个动态库,这个库有多个动态分配函数.
一个名为ef的脚本被用来处理环境变量LD_PRELOAD的设置,我们可以用ef命令来调用程序.
 
下面是安装Electric Fence,如下:
rpm -ivh /mnt/Server/ElectricFence-2.2.2-20.2.2.i386.rpm
 
我们下面用一个小程序做测试,源代码如下:
#include <string.h>
 
int
main (int argc, char *argv[])
{
        int *ptr = new int;
        memset(ptr, 0, sizeof(int) + 1);
        delete ptr;
}
 
编译:
g++ new-corrupt.cpp -o new-corrupt
注:这个小程序会导致边界溢出.
 
执行程序:
./new-corrupt
注:程序没有任何指示.
 
 
我们用ef执行这个程序,如下:
ef ./new-corrupt   
 
  Electric Fence 2.2.0 Copyright (C) 1987-1999 Bruce Perens <bruce@perens.com>
/usr/bin/ef: line 20:  4148 Segmentation fault      ( export LD_PRELOAD=libefence.so.0.0; exec $* )
注:此时有输出信息,它告诉我们出现了Segmentation {敏感词}t,并且指明在哪行出现的问题.
 
我们也可以将electric fence和gdb联用,如下:
编译程序,同时指定-g选项
g++ -g new-corrupt.cpp -o new-corrupt 
 
用gdb打开程序,如下:
gdb ./new-corrupt
GNU gdb Red Hat Linux (6.5-16.el5rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
 
(gdb) set environment LD_PRELOAD libefence.so.0.0              /*设置环境变量LD_PRELOAD为libefence.so.0.0*/
(gdb) run                                                      /*运行程序*/
Starting program: /root/new-corrupt 
 
  Electric Fence 2.2.0 Copyright (C) 1987-1999 Bruce Perens <bruce@perens.com>
 
  Electric Fence 2.2.0 Copyright (C) 1987-1999 Bruce Perens <bruce@perens.com>
 
Program received signal SIGSEGV, Segmentation fault.
0x0804849d in main () at new-corrupt.cpp:7                     /*检查出在调用memset函数时导致越界*/
7               memset(ptr, 0, sizeof(int) + 1);
(gdb) quit
 
下面我们在gdb中不指定环境变量,我们看到gdb没有打印出相关的错误信息.
gdb ./new-corrupt
GNU gdb Red Hat Linux (6.5-16.el5rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
 
(gdb) run
Starting program: /root/new-corrupt 
 
Program exited normally.

linux调试工具glibc的演示分析-core dump double free【转】的更多相关文章

  1. linux调试工具glibc的演示分析

    偶然中发现,下面的两端代码表现不一样 void main(){ void* p1 = malloc(32);       free(p1); free(p1); // 这里会报double free ...

  2. Linux gdb分析core dump文件

    文章目录1. coredump1.1 coredump简介1.2 coredump的文件存储路径1.3 coredump产生的条件1.4 coredump产生原因2. 测试生成coredump1. c ...

  3. Unix 用gdb分析core dump文件

    产生core文件条件 用ulimit -c 指定core文件大小来开启core文件的生成,如:ulimit -c unlimited 用gdb分析core文件的条件 可执行程序在编译时,需加入-g参数 ...

  4. linux core dump学习

    1. core dump是什么? core dump又叫核心转储,当操作系统收到特定的signal时, 会生成某个进程的core dump文件.这样程序员可以根据 已经生成的core dump文件来d ...

  5. 在Linux上利用core dump和GDB调试

    段错误(segfault) "段错误"是程序试图操作不允许访问或试图访问的不允许内存的情况.可能导致段错误的原因主要有: 1.试图解引用空指针(你不允许访问内存地址0) 2.试图解 ...

  6. 在Linux上利用core dump和GDB调试segfault

    时常会遇到段错误(segfault),调试非常费劲,除了单元测试和基本测试外,有些时候是在在线环境下,没有基本开发和测试工具,这就需要调试的技能.以前介绍过使用strace进行系统调试和追踪<l ...

  7. Core Dump 程序故障分析

    1.编写一个应用程序,使用gdb+core dump进行故障分析, core dump的概念: core dump又叫核心转存:当程序在运行过程中发生异常,这时Linux系统可以把程序在运行时的内存内 ...

  8. linux core dump 文件 gdb分析

    core dump又叫核心转储, 当程序运行过程中发生异常, 程序异常退出时, 由操作系统把程序当前的内存状况存储在一个core文件中, 叫core dump. (linux中如果内存越界会收到SIG ...

  9. Linux上Core Dump文件的形成和分析

    原文: http://baidutech.blog.51cto.com/4114344/904419 Core,又称之为Core Dump文件,是Unix/Linux操作系统的一种机制,对于线上服务而 ...

随机推荐

  1. VMware 虚拟机CentOS 7 网路连接配置 无eth0简单解决办法

    个人博客:http://www.cnblogs.com/miaojinmin799/ 在前面几步基本和网上linux配置差不多,最后一步要配置eth0时出现如图所示结果使用ifconfig -a命令 ...

  2. 作业三(下)安装VS2013

    VS2013 今天常识安装Microsoft Visual Studio 2013,虽然 直接在软件管家上下载,一键安装,但是还是遇到许多问题,安装过程相当的艰难,花了好多时间.但是在尝试多次后成功的 ...

  3. Spring之redisyi一主一从复制(非哨兵模式)

    看了好几天redis了,公司从刚开始的redisluster变成了redis主从,原因是rediscluster不可控,其实是我水平没到,万一出点啥事,我这个负责人都解决不了,那就完了!大数据平台下, ...

  4. 利用mask-image蒙层编写异形头像

    需求:后台给了一个规规矩矩的头像,或圆或方,UI要求展示成水滴的形状.正在想到底如何实现的时候,不由自主去翻了鑫神的博客,正好找到了答案,窃喜(·_·) UI给的形状: 后台给的头像(忽略橙色背景色, ...

  5. Kivy 中文教程 实例入门 简易画板 (Simple Paint App):2. 实现绘图功能

    1. 理解 kivy 坐标系统 上一节中,咪博士带大家实现了画板程序的基础框架,以及一个基本的自定义窗口部件(widget).在上一节的末尾,咪博士留了一道关于 kivy 坐标系统的思考题给大家.通过 ...

  6. [国家集训队]middle

    [国家集训队]middle 题目 解法 开\(n\)颗线段树,将第\(i\)颗线段树中大于等于第\(i\)小的数权值赋为1,其他的则为-1,对于每个区间维护一个区间和,最大前缀和,最大后缀和. 然后二 ...

  7. ST算法详解

    ST算法详解 Coded by Jelly_Goat. All rights reserved. 这个主要是说ST表的. 首先了解一下ST表是什么. 先来一个老套的情景带入. (假设所有的题目都是1s ...

  8. Enum 枚举值 (一) 获取描述信息

    封装了方法: public static class EnumOperate { public class BaseDescriptionAttribute : DescriptionAttribut ...

  9. Simple Cycles Edges CodeForces - 962F(点双连通分量)

    题意: 求出简单环的所有边,简单环即为边在一个环内 解析: 求出点双连通分量,如果一个连通分量的点数和边数相等,则为一个简单环 点双连通分量  任意两个点都至少存在两条点不重复的路径  即任意两条边都 ...

  10. 洛谷P4234 最小差值生成树(LCT,生成树)

    洛谷题目传送门 和魔法森林有点像,都是动态维护最小生成树(可参考一下Blog的LCT总结相关部分) 至于从小到大还是从大到小当然无所谓啦,我是从小到大排序,每次枚举边,还没连通就连,已连通就替换环上最 ...