linux 下 C 编程和make的方法 (九、malloc 和 free的功能补充)

中山野鬼 发布于 2012/04/14 23:49
阅读 1K+
收藏 9

    我们回顾一下,前面的目标,如下:   
1、可通过宏的方式,打开或关闭检测,当关闭时检测代码全部在编译时被拿掉。
    2、检测的打开,尽可能的少的影响代码本身的运行效率。检测代码的是否工作和编译效率选项无关。
    3、可以进行以下几种检测。
    a、是否所有malloc都free了,且malloc和free的地址是一样的。
    b、是否一个指针超出了指定的寻址范围。例如一个指针希望是对刚申请的从 0x10到0x70的空间的内容进行操作。而他却正在读取或写出到0x80这个空间内。
    c、可以根据条件的检测,当条件未达到前,不做检测。
    d、可在执行态时,根据判断,程序暂停执行,打印一定的信息到屏幕上。

    关于目标1,则目前已经的设计内容,就符合了目标。当屏蔽掉__MMDB_FLAG__后,则,c_malloc,c_free,自动修正为,malloc ,free标准库函数。不过此时实际有个问题,malloc_free_init 和malloc_free_destory两个函数仍然存在。由此我们需要对C代码进行修改。在 malloc_free.c文件出现#include "malloc_free.h" 之后,立刻加上,#ifdef __MMDB_FLAG__ ,对应的#endif 需要一直放到文件尾端。这样才能真正的满足目标1的需求。

      不错此时出现问题。test_malloc_free_main.c内在连接时,会出现,无法找到malloc_free_init,malloc_free_destory的问题。这很正常,我们本身的目标就希望在关闭下不需要这些冗余代码。由此我们需要修改malloc_free.h的头文件,做到,任何 #ifdef __MMDB_FLAG__成立时,出现的函数定义,和定义本身都要在另一个条件下有对应操作,由此需要调整一下头文件如下


#ifndef __MMDB_FLAG__
//c_malloc c_free means malloc by check,not calloc,not type cmalloc!!!!!
#define c_malloc(a) malloc(a)
#define c_free(a) free(a)
#define MALLOC_FREE_INIT(...) do {} while (0)
#else
#define MALLOC_FREE_INIT malloc_free_init
。。。
     这里的...是利用了C标准里,可变参的知识。表示任意参数。但无论什么参数。我们都将其对等于一个空内容。在#define 扩展后,调用malloc_free_init(0);的地方会对等替换成 “空;” 此时,编译可以认为是个无效的空语句。
不过对于诸如
     a = func(b,c,d);

     就无法使用上述方法。此时会扩展为 a = ; 几乎没有好的解决方案回避这个问题。因此,在设计需要能通过宏进行可屏蔽的代码时,尽可能不使用带返回的函数描述方式。上述做法更好的描述应该是


  #define FUNC_(a,b,c,d) do {a = func(b,c,d);}while(0)
   FUNC_(a,b,c,d);

    用全大写,是方便区分,函数调用还是宏调用。
    这也是为什么在条件成立时,出现一个对malloc_free_init名称替换的目的。当然严格说,c_malloc c_free也需要进行全大写替换,此处暂时不形而上学。记得对应修改test_malloc_free_main中调用malloc_free_init的书写方式,修改为全大写。

    关于目标2,这个是个比较抽象的目标。判断标准应该是增加的代码,尽可能小巧和简单。减少代码的复杂度。同时将比较复杂的操作,通过函数的调用方式实现这样降低了被检测的代码片额外的代码量,而我们尽可能少的调用这些函数,这样降低了被检测代码片额外的执行量,只有在条件成立下。
    关于目标3,现在我们只补充a,b,c的。d,原先想用个弱智方式实现,但觉得利用这个介绍一下多线程设计很不错,所以我们放后面讨论。
    关于a,前面已经做的OK了。但是关于b,c我们还没有实现。下面先针对b进行实现。
    目标b,是要判断一个指针是否在一个malloc过的空间内,防止指针被改写或不正确设置值时,指向其他地址空间。由此必须要有个判断值,通过对曾经malloc的信息进行对比。为了实现这个目的,必须增加数据。如下
    typedef struct{//not add other type ,only void *
        void *pfirst;
        void *plast;
    }_BUF_RANGE;
    static _BUF_RANGE *ptab = 0;
    需要都放在C文件里,因为其他C文件不关心的东西,我们没必要折腾到头文件嘛。为什么不用如下形式
   
typedef struct{
        void *pfirst;
        size_t size;
    }_BUF_RANGE;
    这是为了简化比较逻辑。当在代码里,需要对指针进行检测,那么用第一个方案可以如下写
  
(ptab->pfirst >= p) && (ptab->plast < p)
    第二个方案,得如下写
  
(ptab->pfirst >= p) && ((ptab->pfirst + ptab->size) < p)
    无缘无故的多了一步加法,而这个加法在size确定下,有时任意时刻一致的结果。何必呢?
    而对于ptab,显然需要有个足够的空间,空间大小怎么来,由MAX_MALLOC_NUM 确定,在 malloc_free_init里,进行申请,如果失败则认为致命错误,直接退出。同时在malloc_free_destory进行释放。
    此时我们需要修改一下c_malloc,和c_free。一个是增加信息,一个是检测信息。
    c_malloc在成功申请后,需要对ptab里的内容进行设置。如下 set_malloc_tab函数
    此处多了个宏定义,   
    #define DO_ERR_EX_NO_SET(E) do {int tmp;DO_ERR_EX(tmp,ERR_TAB_FLAG)    ;}while (0)
    这里tmp没有意义,是为了利用DO_ERR_EX的宏,尽量合并过程,是C模块化过程化编写的原则,而此时malloc_count 由于可能还有其他的检测,因此我们暂时不能清除,因为当前的问题不是由malloc_count本身导致的,这和前面使用 DO_ERR_EX(malloc_count)的情况不一样。
   
   
static void set_malloc_tab(void *p,size_t size){
    int bias = malloc_count;
    int bias1 = 0;
    while (ptab[bias].pfirst && bias < MAX_MALLOC_NUM){
        bias++;
    }
    if (bias >= MAX_MALLOC_NUM){
        bias = 0;
        while (ptab[bias].pfirst && bias < malloc_count){
            bias++;
        }
    }
    if (ptab[bias].pfirst){
        DO_ERR_EX_NO_SET(ERR_TAB_FLAG);
    }
    ptab[bias].pfirst = p;
    ptab[bias].plast = p + size;
   
    }
    这里存在一个简单的全扫描检测空存储空间的工作。由于malloc的发生我们本身并不希望他频繁,所以对set_malloc_tab没有效率要求,因此简化了寻找空地址的工作,这个和普通的memory管理不一样。设计程序, 有个很重要的原则,把有限的精力放在目标问题上,绝大多数的代码都不是最优的描述,因为最优本身就是可变化的。
    if (bias >= MAX_MALLOC_NUM) 是因为,我们假设当前malloc_count之后的空间可能空的空间更多,因此直接从bias = malloc_count开始扫描,但这并不代表当malloc_count < MAX_MALLOC_NUM时,就一定在这个区间段有可利用的资源。可能前面已申请的空间被释放了。由此需要进行从头的补扫描,如果第一个while没有发现有效空间时。
    上述两个while,无论哪个,必须表示ptab[bias].pfirst == 0,才是有效,因此,判断是否有足够的空间时,既然已经全扫描了,我们就可以通过它来判断,而不是简单的 malloc_count < MAX_MALLOC_NUM来判断。
    代码设计时,需要注意, 在不增加额外代码时,最好使用直接关联的逻辑来处理,对等逻辑例如malloc_count < MAX_MALLOC_NUM确实和ptab[bias].pfirst 是否为0 ,存在对应关系,但是这只是理论上的。如果malloc_count本身就错了呢?例如其他的地方没有free却修改了malloc_count。这里的DO_ERR_EX_NO_SET本身也是对malloc_count的正确性判断的错误输出。
    上述这个观点,是非常重要,也是初学者非常容易忽视的。觉得,一个表达,这样也可以做,那样也可以做。想想一个目标可以多种方式实现是好事情,但目的是搞清楚为什么,在搞清楚之后,能够简化逻辑与逻辑之间的关联。尽量直接的表达逻辑。否则此处就是个潜在的BUG难点。当malloc_count本身被外部修改出错,但修改的地方并不会出现系统出错问题。反倒是这里会出现系统崩溃,这样的错误转移,导致debug难度加大。 其原因就是在代码设计时,用逻辑映射逻辑的方式,将错误给转移了过来。小工程无所谓,大工程,等着吃苦吧。
    有设置,一定要想到有清除,且不谈有查找。如同有init,就有destory,哪怕你什么都没做,如同我的create_module创建的C的模板一样,但是你得保留代码片,省得以后忘记。以下就是清除部分的代码
static int check_clear_malloc_table(void *p){
    int i = 0;
    int bias = malloc_count;
    while ((i < bias) && (ptab[i].pfirst!=p)){
        bias += (ptab[i++].pfirst == 0);
    }
    if (i < bias){
        ptab[i].pfirst = 0;
        return 1;
    }else{
        return 0;
    }
   
}
    为什么多增加了一个check,是因为set是假设可以set的,实际是否有空间是外部通过 malloc_count < MAX_MALLOC_NUM来判断。而 clear之所以要和check进行整合,是因为 clear的前提条件不单单是是否存在没有free对指针,还要判断指针是否合法。而这个工作,集中处理,要比分开处理更有效的防止匹配错误。例如,没有check就clear,或没有clear,以为check就clear了。
    因为clear很难有什么先验的信息,此处和set不同。因此while 是从0开始的。从malloc_count开始就画蛇添足了。当然可以修改为,从malloc_count 开始向0进行反向扫描。不过机器的cache 机制告诉我们, 循环,尽可能后向检测,不要前向检测

    这里说了set,立刻说clear,并废话一堆,这个clear下的动作,在set里是对应的什么。是希望新手注意,面向模块,的设计, 对于大多数的数据区如果存在有意义的设置动作,必然会存在对等的清理动作。哪怕他没有必要,但也要有这个概念。特别是你在练习消息,通讯等交互工作设计时。
    既然能SET了,也能CLEAR了。那么我们就应该可以做查找判断了。一种简单的做法,是我们每次针对一个指针,对整个malloc记录信息表进行查找。不过这显得很无聊。因为我们对任何一个代码片的指针,从设计的角度都知道这个指针应该指向什么。我们 不是在追问,这个指针目前指向哪个区域,而是这个指针针对某个malloc申请的空间,是否越界了。如果是前者,对于后者的问题毫无帮助。如果一个指针从A的区,指向了B的区,一样还是错啊。因此上述简单的做法,就是个错误的方式,先不谈效率。效率永远是最后的话题,而且还得当你发现他慢到,成为一个问题的时候才是问题。
    因此正确的做法是,需要一个带比较的基准区域,也就是我们得知道是malloc信息表中的那个数据。由此我们需要获取一个索引,用于判断。如下,
  
void ** get_malloc_index(void*ptr){
        int i;
        int bias;
        for (i = 0,bias = 0 ; bias < malloc_count && i < MAX_MALLOC_NUM; i++){
            if (ptab[i].pfirst == ptr) return &(ptab[i].pfirst);
            bias += (ptab[i].pfirst !=0);
        }
        DO_ERR_EX_NO_SET(ERR_PTR_NOFOUND);
        //return 0;
    }
    这里, 从0开始的目的和前面clear的情况一样。由此该函数也被定义为,不可频繁执行的函数。需要在类似malloc的地方紧随使用。为什么用void**,不用_BUF_RANGE *,是因为我们要简化头文件,头文件越简单,则对于__MMDB_FLAG__开启关闭的差异性越小,由此越能保证代码设计时的正确性。内容少,出错的概率就小嘛。只是习惯问题,你完全可以修改,将 _BUF_RANGE 放到头文件里,使用
    _BUF_RANGE *get_malloc_index(void*ptr){ 方式获取对应信息。
    使用void **,则可以
    假设pvv = get_malloc_index(ptr);
    简单利用 pvv[0] pvv[1]对等 (ptab+i)->pfirst ,(ptab+i)->plast。这也是为什么我坚持在_BUF_RANGE里都定义为void *的原因。
    获取get_malloc_index还不够。因为他传递给了一个变量,而这个变量总要申明吧。由此,我们在头文件里需要添加如下信息。
    #define _TYPE_INDEX_MALLOC_FREE(name) void ** name;
    记得,如果你尝试在一个函数内使用, _TYPE_INDEX_MALLOC_FREE(pbufinfo);
    则会导致作用域的问题在别的函数内无效。最好在这个C文件的最上方定义。同时这样的定义我没有强制为 static,是因为有很多情况,malloc一个空间,而利用该空间的指针往往不在一个模块里。所以使用了全局变量,但由此可能会导致重名问题。因此,最好对name 的命名能准确描述该空间的含义。那么就存在一个配置的工作,如下
    假设是上面的pbase则
    _TYPE_INDEX_MALLOC_FREE(pbufinfo); //此处申明一个索引变量
    void *pbuf = c_malloc(SIZE);//申请一个SIZE大小的空间给pbuf
    pbufinfo = get_malloc_index(pbuf);//将pbuf的空间信息的地址传递给pbufinfo
    当然,你可以提出,此处有个简化方式,将pbufinfo当作参数给予 c_malloc,如果我不关系某个c_malloc的信息,可以传递个0.这样确实可以做。但直接影响到当__MMDB_FLAG__关闭时, #define c_malloc malloc的宏的修正。这里就又提出一个编程思想。
    当你的一个代码片的增加,如果引入到其他代码片时,会出现其他代码片全范围的修改,则最好慎用。例如上面将get_malloc_index的动作作为c_malloc的动作,如果只是在c_malloc内部实现,并不影响参数,由此不会影响 __MMDB_FLAG__关闭时的逻辑,则完全可以。反之则不要合并。这样的合并会导致和目标无关的逻辑关联。简化逻辑关联,是分解问题,分析问题,归总设计方案的一个原则。何必额外增加复杂度呢?

    参考前面关于malloc_free_init的讨论,我们需要对get_malloc_index包装一下,用宏的全大写方式展开,这样有利于__MMDB_FLAG__关闭时的剥离,所以头文件修改如下,以下增加了对指针的判断检测
   
#ifndef __MMDB_FLAG__
...
#define _TYPE_INDEX_MALLOC_FREE(...)
#define GET_MALLOC_INDEX(...) do{}while (0)
#define CHECK_PTR_RANGE(...) (1)
...
#else
...
#define _TYPE_INDEX_MALLOC_FREE(name) void ** name;
#define GET_MALLOC_INDEX(p,indexP) do{indexP = get_malloc_index(p);}while (0)
#define CHECK_PTR_RANGE(p,indexP) ((indexP[0] <= (void *)(p)) && (indexP[1] > (void*)(p)))
...
#endif
   
    这里需要说明,CHECK_PTR_RANGE,既然是判断用途,因此,需要用()进行包裹,而为什么在__MMDB_FLAG__关闭是变成了(1),是因为,我们默认这个判断更多情况下是条件成立,所以在关闭是,为了保证代码不做改动,则我们也默认为(1),放心,编译器当发现 if (1) {...} else {...}时,会把if (1)以及else后面的语句全部拿掉。永远判断均位1,何必判断,永远跑不进的代码何必保留呢?但这个是针对编译器而言,对于你,运行态和检测态是都有可能发生的。
    但通常错了,总要有对应动作。而这个动作,需要包裹在宏里面,否则,在 __MMDB_FLAG__关闭下,需要ctrl+ X掉。因此,我们再增加一个宏
    #define CHECK_PTR_RANGE_ER(p,indexP,n,NAME) do {\
if (CHECK_PTR_RANGE(p,indexP)){n++;}else{\
set_check_ptr_range_error_exit(p,indexP,n,NAME);}} while (0)
    这里说下n,n是用于计数的,目的是,检测第几次发生,由此可以通过检测这个值,在个值发生前,可以做点信息打印之类的事情,检测逻辑正确性,甚至另代码停滞,以观测判断一些变量是否被修改,而导致指针出错。因此多出这个变量,计数值。也需要宏包裹一下,如下
   
#define _TYPE_COUNT_MALLOC_FREE(name) unsigned long name  = 0;
    以下,就给出.h和.c的全部清单。记得关注一下 ERR_MAX_NUM在枚举中的作用,虽然这个并不是你需要的枚举类型。
#ifndef _malloc_free_H_
#define _malloc_free_H_
#include <stdlib.h>
#define ALLOC_PAGE_SIZE 4096 //mininum malloc unit sizes ,not change
#define MALLOC_NUM_UNIT_SIZE (ALLOC_PAGE_SIZE / sizeof(void*))
#define MAX_MALLOC_UNIT_NUM 64 //not more than 4096*8
#define MAX_MALLOC_NUM  (MALLOC_NUM_UNIT_SIZE * MAX_MALLOC_UNIT_NUM) // max malloc times ,you can change
//#define __MMDB_FLAG__
#ifndef __MMDB_FLAG__
//c_malloc c_free means malloc by check,not calloc,not type cmalloc!!!!!
#define c_malloc(a) malloc(a)
#define c_free(a) free(a)
#define MALLOC_FREE_INIT(...) do{}while(0)
#define _TYPE_INDEX_MALLOC_FREE(...)
#define _TYPE_COUNT_MALLOC_FREE(...)
#define CHECK_PTR_RANGE(...) (1)
#define GET_MALLOC_INDEX(...) do{}while (0)
#define CHECK_PTR_RANGE_ER(...) do{}while(0)
 
#else
#define MALLOC_FREE_INIT malloc_free_init
#define _TYPE_COUNT_MALLOC_FREE(name) unsigned long name  = 0;
#define _TYPE_INDEX_MALLOC_FREE(name) void ** name;
#define CHECK_PTR_RANGE(p,indexP) ((indexP[0] <= (void *)(p)) && (indexP[1] > (void*)(p)))
#define GET_MALLOC_INDEX(p,indexP) do{indexP = get_malloc_index(p);}while (0)
#define CHECK_PTR_RANGE_ER(p,indexP,n,NAME) do {if (CHECK_PTR_RANGE(p,indexP)){n++;}else{set_check_ptr_range_error_exit(p,indexP,n,NAME);}} while (0)

//ins_inc_file

//ins_typedef_def

//ins_def

//ins_func_declare
void memory_free_init(void*);
void **get_malloc_index(void *ptr); //not used in code ,please used GET_MALLOC_INDEX define
void set_check_ptr_range_error_exit(void *p,void **index,unsigned long n,const char *str);//not used in code ,please used CHECK_PTR_RANGE_ER
void *c_malloc(size_t size);
void c_free(void *ptr);

#endif


#endif //_malloc_free_H_

 /***************
src/malloc_free.c
 by luckystar
 ***************/
#include "malloc_free.h"
#include <stdio.h>
#ifdef __MMDB_FLAG__
typedef struct{//not add other type ,only void *
    void *pfirst;
    void *plast;
}_BUF_RANGE;
#define BUF_RANGE_SIZE (sizeof(_BUF_RANGE)/sizeof(void *))
enum {
    ERR_NULL,
    ERR_FREE_MORE,
    ERR_FREE_LACK,
    ERR_ALLOC_OVERFLOW,
    ERR_MALLOC,
    ERR_TAB_FLAG,
    ERR_FREE_ZERO,
    ERR_FREE_NOFOUND,
    ERR_PTR_NOFOUND,
    ERR_RANGE_NOFOUND,
    ERR_MAX_NUM
};
const static char error_str[ERR_MAX_NUM][256] = {"malloc_free is ok!\n","too much free func called!\n",\
"free is lack!\n",
"too much alloc func called!\n",
"malloc called failed!\n",
"malloc_count or tab flag error!\n",
"try to free zero address error!\n",
"no found the address is malloc error!\n",
"want to get one ptr index ,but the ptr not malloc !\n",
"ptr range check error !\n"};
#define ERROR(n) do {error_type = ((n)<ERR_MAX_NUM?n:error_type);}while(0)
#define DO_ERR_EX(n,E) do {ERROR(E);n = 0;exit(1);} while (0)
#define DO_ERR_EX_NO_SET(E) do {int tmp;DO_ERR_EX(tmp,ERR_TAB_FLAG)    ;}while (0)
#define CHECK_ALLOC(n) do {if ((n)>=MAX_MALLOC_NUM){DO_ERR_EX(n,ERR_ALLOC_OVERFLOW);}}while(0)
#define CHECK_FREE(n) do {if ((n) == 0){DO_ERR_EX(n,ERR_FREE_MORE);}}while(0)
#define CHECK_FREE_LACK(n) do {if ((n)){ERROR(ERR_FREE_LACK);}}while(0)
#define CHECK_MALLOC(p) do {if (p == 0){DO_ERR_EX(malloc_count,ERR_MALLOC);}}while(0)
#define SET_ZERO(p,T,s) do {T *tp = (T)(p); int i; for (i = 0 ; i < s ;i++){*tp++ = 0;} }while (0)
static int malloc_free_flag =0;
static long malloc_count = 0;
static unsigned int error_type = 0;
static _BUF_RANGE *ptab = 0;

void malloc_free_destory(void);
void malloc_free_init(void*pv){
    if (malloc_free_flag) {
        //log("module inited..",X);
        return;
    }
    malloc_free_flag = 1;
    //todo:module init...
    error_type = 0;
    ptab = (_BUF_RANGE*)malloc(sizeof(_BUF_RANGE)*MAX_MALLOC_NUM);
    SET_ZERO(ptab,void *,MAX_MALLOC_NUM*BUF_RANGE_SIZE);
    #if 0
    SET_ZERO(tflag,_tBIT_FLAG,BIT_FLAG_SIZE);
    #endif
    atexit(malloc_free_destory);
}

static void set_malloc_tab(void *p,size_t size){
    int bias = malloc_count;
    int bias1 = 0;
    while (ptab[bias].pfirst && bias < MAX_MALLOC_NUM){
        bias++;
    }
    if (bias >= MAX_MALLOC_NUM){
        bias = 0;
        while (ptab[bias].pfirst && bias < malloc_count){
            bias++;
        }
    }
    if (ptab[bias].pfirst){
        DO_ERR_EX_NO_SET(ERR_TAB_FLAG);
    }
    ptab[bias].pfirst = p;
    ptab[bias].plast = p + size;
   
}

static int check_clear_malloc_table(void *p){
    int i = 0;
    int bias = malloc_count;
    while ((i < bias) && (ptab[i].pfirst!=p)){
        bias += (ptab[i++].pfirst == 0);
    }
    if (i < bias){
        ptab[i].pfirst = 0;
        return 1;
    }else{
        return 0;
    }
   
}

void *c_malloc(size_t size){
    void *re;
    CHECK_ALLOC(malloc_count);
    re = malloc(size);
    CHECK_MALLOC(re);   
    set_malloc_tab(re,size);
    malloc_count++;
    return re;
}
void c_free(void *ptr){
    if (ptr){
        if (check_clear_malloc_table(ptr)){
            CHECK_FREE(malloc_count);
            free(ptr);
           
            malloc_count--;
        }else{
           
            DO_ERR_EX_NO_SET(ERR_FREE_NOFOUND);
        }
    }else{
        DO_ERR_EX_NO_SET(ERR_FREE_ZERO);
    }
    return;
}
void malloc_free_destory(void){
    if (!malloc_free_flag) {
        //log("module not inited..",X);
        return;
    }
    malloc_free_flag = 0;
    //todo:module destory...
    if (error_type == 0){
        CHECK_FREE_LACK(malloc_count);
    }
    if (ptab) free(ptab);
    fprintf(stderr,"%s",error_str[error_type]);

}
void set_check_ptr_range_error_exit(void *p,void **indexP,unsigned long n,const char *strname){
    {
        int tmp;
        if (strname){
            fprintf(stderr,"ptr:%s\n",strname);
        }
        fprintf(stderr,"in %ld times, found 0x%llx not in buf\n buf is  [0x%llx,0x%llx]\n",n,(unsigned long long)p,(unsigned long long)indexP[0],(unsigned long long)indexP[1]);
        DO_ERR_EX(tmp,    ERR_RANGE_NOFOUND);
    }
}
void ** get_malloc_index(void*ptr){
    int i;
    int bias;
    for (i = 0,bias = 0 ; bias < malloc_count && i < MAX_MALLOC_NUM; i++){
        if (ptab[i].pfirst == ptr) return &(ptab[i].pfirst);
        bias += (ptab[i].pfirst !=0);
    }
    DO_ERR_EX_NO_SET(ERR_PTR_NOFOUND);
    //return 0;
}
#endif 
    这里谈一下,test_malloc_free_main.c的作用。之所以我在设计create_module脚本时默认自动生成一个test_MODULENAME_main.c的文件,是用于持久保留模块设计中,对于功能的检测。越重视这些东西,对你后期的大系统设计越有帮助。
    test7函数里,给出了两种检测方法,一种检测,是不调用 malloc_free的内部函数而自行添加代码。但是这种方案不好。违背了 __MMDB_FLAG__的原则。当__MMDB_FLAG__被关闭是,printf("p2 bias is %d , check ok\n",i);会持久保留。只是给出建议,当使用ptr时,你可以如这种方案操作。而对于错误点检测,通常是需要当作严重错误来停滞的。除非你尝试工作运行态下的检测,总得有对应操作吧,另谈。其源码如下。

   

#include "malloc_free.h"
#include <stdio.h>

typedef void (* TEST_FUNC)(void);

static void test0(void){
    void *p1 = 0;
    char *p2 = 0;
    printf("test0\n");
    p1 =(char*)c_malloc(4);//*4);
    p2 = (char*)c_malloc(6);
    c_free(p1);
    c_free(p2);
    return; //normal check
}
static void test1(void){
    char *p1,*p2;
    p1 = (char*)c_malloc(5);
    p2 = (char*)c_malloc(6);
    c_free(p1);
    //cfree(p2);
    return; //free lack check
}
static void test2(void){
    char *p1,*p2,*p3;
    p1 = (char*)c_malloc(5);
    p3 = p2 = (char*)c_malloc(6);
    c_free(p1);
    c_free(p2);
    c_free(p3);
    return; //free more check
}
static void test3(void){
    char **pp = (char**)c_malloc(sizeof(char*)*MAX_MALLOC_NUM + 1);
    int i;
    for (i = 0 ; i <= MAX_MALLOC_NUM ; i++){
        pp[i] = (char*)c_malloc(2);
    }
    return; //alloc more check
}
static void test4(void){
    char *p1,*p2,*p3;
    p1 = (char*)c_malloc(5);
    p2 = (char*)c_malloc(6);
    p3 = (char*)c_malloc(6);
    c_free(p1);
    c_free(p2);
    c_free(p2);
    return; //free twin check   
}
static void test5(void){
    char *p1,*p2;
    p1 = (char*)c_malloc(5);
    p2 = (char*)c_malloc(6);
    c_free(p1);
    c_free(p2+3);
    return; //free shift check   
}
static void test6(void){
    char *p1,*p2;
    p1 = (char*)c_malloc(5);
    p2 = (char*)c_malloc(6);
    c_free(p1);
    c_free(0);
    return; //free zero check   
}

static void test7(void){
    char *p1,*p2;
    _TYPE_COUNT_MALLOC_FREE(ptr_count);
    _TYPE_INDEX_MALLOC_FREE(pindex);   
    int i;

    p1 = (char*)c_malloc(5);
    GET_MALLOC_INDEX(p1,pindex);
    p2 = p1+ 3;
    for (i = 3 ; i< 10 ; i++,p2++){
        if (CHECK_PTR_RANGE(p2,pindex)){
            printf("p2 bias is %d , check ok\n",i);
        }else{
            printf("error bias is %d!\n",i);
        }
    }
    p2 = p1;
    for (i = 0 ; i< 10 ; i++,p2++){
        CHECK_PTR_RANGE_ER(p2,pindex,ptr_count,"test7 func p2");
    }   
   
    c_free(p1);
    //c_free(0);
    return; //free zero check   
}
#define TEST_MASK 7
TEST_FUNC test_a[TEST_MASK+1]= {test0,test1,test2,test3,test4,test5,test6,test7};
   

int main(int argc,char *argv[]){
    int mode;

    printf("hello test_malloc_free_main now run...\n");
    MALLOC_FREE_INIT(0);
    if (argc < 2){
        printf("need parameters!\n");
        return 1;
    }
    mode = argv[1][0] - '0';
    test_a[mode & TEST_MASK]();
   
    printf("hello test_malloc_free_main now exit...\n");
    return 0;
}






加载中
返回顶部
顶部