我们回顾一下,前面的目标,如下:
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__成立时,出现的函数定义,和定义本身都要在另一个条件下有对应操作,由此需要调整一下头文件如下
2 | //c_malloc c_free means malloc by check,not calloc,not type cmalloc!!!!! |
3 | #define c_malloc(a) malloc(a) |
4 | #define c_free(a) free(a) |
5 | #define MALLOC_FREE_INIT(...) do {} while (0) |
7 | #define MALLOC_FREE_INIT malloc_free_init |
这里的...是利用了C标准里,可变参的知识。表示任意参数。但无论什么参数。我们都将其对等于一个空内容。在#define 扩展后,调用malloc_free_init(0);的地方会对等替换成 “空;” 此时,编译可以认为是个无效的空语句。
不过对于诸如
就无法使用上述方法。此时会扩展为 a = ; 几乎没有好的解决方案回避这个问题。因此,在设计需要能通过宏进行可屏蔽的代码时,尽可能不使用带返回的函数描述方式。上述做法更好的描述应该是
1 | #define FUNC_(a,b,c,d) do {a = func(b,c,d);}while(0) |
用全大写,是方便区分,函数调用还是宏调用。
这也是为什么在条件成立时,出现一个对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的信息进行对比。为了实现这个目的,必须增加数据。如下
1 | typedef struct { //not add other type ,only void * |
5 | static _BUF_RANGE *ptab = 0; |
需要都放在C文件里,因为其他C文件不关心的东西,我们没必要折腾到头文件嘛。为什么不用如下形式
这是为了简化比较逻辑。当在代码里,需要对指针进行检测,那么用第一个方案可以如下写
1 | (ptab->pfirst >= p) && (ptab->plast < p) |
第二个方案,得如下写
1 | (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函数
此处多了个宏定义,
1 | #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)的情况不一样。
01 | static void set_malloc_tab( void *p, size_t size){ |
02 | int bias = malloc_count; |
04 | while (ptab[bias].pfirst && bias < MAX_MALLOC_NUM){ |
07 | if (bias >= MAX_MALLOC_NUM){ |
09 | while (ptab[bias].pfirst && bias < malloc_count){ |
13 | if (ptab[bias].pfirst){ |
14 | DO_ERR_EX_NO_SET(ERR_TAB_FLAG); |
16 | ptab[bias].pfirst = p; |
17 | 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的模板一样,但是你得保留代码片,省得以后忘记。以下就是清除部分的代码
01 | static int check_clear_malloc_table( void *p){ |
03 | int bias = malloc_count; |
04 | while ((i < bias) && (ptab[i].pfirst!=p)){ |
05 | bias += (ptab[i++].pfirst == 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信息表中的那个数据。由此我们需要获取一个索引,用于判断。如下,
01 | void ** get_malloc_index( void *ptr){ |
04 | for (i = 0,bias = 0 ; bias < malloc_count && i < MAX_MALLOC_NUM; i++){ |
05 | if (ptab[i].pfirst == ptr) return &(ptab[i].pfirst); |
06 | bias += (ptab[i].pfirst !=0); |
08 | DO_ERR_EX_NO_SET(ERR_PTR_NOFOUND); |
这里, 从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还不够。因为他传递给了一个变量,而这个变量总要申明吧。由此,我们在头文件里需要添加如下信息。
1 | #define _TYPE_INDEX_MALLOC_FREE(name) void ** name; |
记得,如果你尝试在一个函数内使用, _TYPE_INDEX_MALLOC_FREE(pbufinfo);
则会导致作用域的问题在别的函数内无效。最好在这个C文件的最上方定义。同时这样的定义我没有强制为 static,是因为有很多情况,malloc一个空间,而利用该空间的指针往往不在一个模块里。所以使用了全局变量,但由此可能会导致重名问题。因此, 最好对name 的命名能准确描述该空间的含义。那么就存在一个配置的工作,如下
假设是上面的pbase则
1 | _TYPE_INDEX_MALLOC_FREE(pbufinfo); //此处申明一个索引变量 |
2 | void *pbuf = c_malloc(SIZE); //申请一个SIZE大小的空间给pbuf |
3 | 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__关闭时的剥离,所以头文件修改如下,以下增加了对指针的判断检测
03 | #define _TYPE_INDEX_MALLOC_FREE(...) |
04 | #define GET_MALLOC_INDEX(...) do{}while (0) |
05 | #define CHECK_PTR_RANGE(...) (1) |
09 | #define _TYPE_INDEX_MALLOC_FREE(name) void ** name; |
10 | #define GET_MALLOC_INDEX(p,indexP) do{indexP = get_malloc_index(p);}while (0) |
11 | #define CHECK_PTR_RANGE(p,indexP) ((indexP[0] <= (void *)(p)) && (indexP[1] > (void*)(p))) |
这里需要说明,CHECK_PTR_RANGE,既然是判断用途,因此,需要用()进行包裹,而为什么在__MMDB_FLAG__关闭是变成了(1), 是因为,我们默认这个判断更多情况下是条件成立,所以在关闭是,为了保证代码不做改动,则我们也默认为(1),放心,编译器当发现 if (1) {...} else {...}时,会把if (1)以及else后面的语句全部拿掉。永远判断均位1,何必判断,永远跑不进的代码何必保留呢?但这个是针对编译器而言,对于你,运行态和检测态是都有 可能发生的。
但通常错了,总要有对应动作。而这个动作,需要包裹在宏里面,否则,在 __MMDB_FLAG__关闭下,需要ctrl+ X掉。因此,我们再增加一个宏
1 | #define CHECK_PTR_RANGE_ER(p,indexP,n,NAME) do {\ |
2 | if (CHECK_PTR_RANGE(p,indexP)){n++;} else {\ |
3 | set_check_ptr_range_error_exit(p,indexP,n,NAME);}} while (0) |
这里说下n,n是用于计数的,目的是,检测第几次发生,由此可以通过检测这个值,在个值发生前,可以做点信息打印之类的事情,检测逻辑正确性,甚至另代码停滞,以观测判断一些变量是否被修改,而导致指针出错。因此多出这个变量,计数值。也需要宏包裹一下,如下
1 | #define _TYPE_COUNT_MALLOC_FREE(name) unsigned long name = 0; |
以下,就给出.h和.c的全部清单。记得关注一下 ERR_MAX_NUM在枚举中的作用,虽然这个并不是你需要的枚举类型。
01 | #ifndef _malloc_free_H_ |
02 | #define _malloc_free_H_ |
04 | #define ALLOC_PAGE_SIZE 4096 //mininum malloc unit sizes ,not change |
05 | #define MALLOC_NUM_UNIT_SIZE (ALLOC_PAGE_SIZE / sizeof(void*)) |
06 | #define MAX_MALLOC_UNIT_NUM 64 //not more than 4096*8 |
07 | #define MAX_MALLOC_NUM (MALLOC_NUM_UNIT_SIZE * MAX_MALLOC_UNIT_NUM) // max malloc times ,you can change |
08 | //#define __MMDB_FLAG__ |
10 | //c_malloc c_free means malloc by check,not calloc,not type cmalloc!!!!! |
11 | #define c_malloc(a) malloc(a) |
12 | #define c_free(a) free(a) |
13 | #define MALLOC_FREE_INIT(...) do{}while(0) |
14 | #define _TYPE_INDEX_MALLOC_FREE(...) |
15 | #define _TYPE_COUNT_MALLOC_FREE(...) |
16 | #define CHECK_PTR_RANGE(...) (1) |
17 | #define GET_MALLOC_INDEX(...) do{}while (0) |
18 | #define CHECK_PTR_RANGE_ER(...) do{}while(0) |
21 | #define MALLOC_FREE_INIT malloc_free_init |
22 | #define _TYPE_COUNT_MALLOC_FREE(name) unsigned long name = 0; |
23 | #define _TYPE_INDEX_MALLOC_FREE(name) void ** name; |
24 | #define CHECK_PTR_RANGE(p,indexP) ((indexP[0] <= (void *)(p)) && (indexP[1] > (void*)(p))) |
25 | #define GET_MALLOC_INDEX(p,indexP) do{indexP = get_malloc_index(p);}while (0) |
26 | #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) |
35 | void memory_free_init( void *); |
36 | void **get_malloc_index( void *ptr); //not used in code ,please used GET_MALLOC_INDEX define |
37 | 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 |
38 | void *c_malloc( size_t size); |
39 | void c_free( void *ptr); |
44 | #endif //_malloc_free_H_ |
005 | #include "malloc_free.h" |
008 | typedef struct { //not add other type ,only void * |
012 | #define BUF_RANGE_SIZE (sizeof(_BUF_RANGE)/sizeof(void *)) |
026 | const static char error_str[ERR_MAX_NUM][256] = { "malloc_free is ok!\n" , "too much free func called!\n" ,\ |
028 | "too much alloc func called!\n" , |
029 | "malloc called failed!\n" , |
030 | "malloc_count or tab flag error!\n" , |
031 | "try to free zero address error!\n" , |
032 | "no found the address is malloc error!\n" , |
033 | "want to get one ptr index ,but the ptr not malloc !\n" , |
034 | "ptr range check error !\n" }; |
035 | #define ERROR(n) do {error_type = ((n)<ERR_MAX_NUM?n:error_type);}while(0) |
036 | #define DO_ERR_EX(n,E) do {ERROR(E);n = 0;exit(1);} while (0) |
037 | #define DO_ERR_EX_NO_SET(E) do {int tmp;DO_ERR_EX(tmp,ERR_TAB_FLAG) ;}while (0) |
038 | #define CHECK_ALLOC(n) do {if ((n)>=MAX_MALLOC_NUM){DO_ERR_EX(n,ERR_ALLOC_OVERFLOW);}}while(0) |
039 | #define CHECK_FREE(n) do {if ((n) == 0){DO_ERR_EX(n,ERR_FREE_MORE);}}while(0) |
040 | #define CHECK_FREE_LACK(n) do {if ((n)){ERROR(ERR_FREE_LACK);}}while(0) |
041 | #define CHECK_MALLOC(p) do {if (p == 0){DO_ERR_EX(malloc_count,ERR_MALLOC);}}while(0) |
042 | #define SET_ZERO(p,T,s) do {T *tp = (T)(p); int i; for (i = 0 ; i < s ;i++){*tp++ = 0;} }while (0) |
043 | static int malloc_free_flag =0; |
044 | static long malloc_count = 0; |
045 | static unsigned int error_type = 0; |
046 | static _BUF_RANGE *ptab = 0; |
048 | void malloc_free_destory( void ); |
049 | void malloc_free_init( void *pv){ |
050 | if (malloc_free_flag) { |
051 | //log("module inited..",X); |
054 | malloc_free_flag = 1; |
055 | //todo:module init... |
057 | ptab = (_BUF_RANGE*) malloc ( sizeof (_BUF_RANGE)*MAX_MALLOC_NUM); |
058 | SET_ZERO(ptab, void *,MAX_MALLOC_NUM*BUF_RANGE_SIZE); |
060 | SET_ZERO(tflag,_tBIT_FLAG,BIT_FLAG_SIZE); |
062 | atexit (malloc_free_destory); |
065 | static void set_malloc_tab( void *p, size_t size){ |
066 | int bias = malloc_count; |
068 | while (ptab[bias].pfirst && bias < MAX_MALLOC_NUM){ |
071 | if (bias >= MAX_MALLOC_NUM){ |
073 | while (ptab[bias].pfirst && bias < malloc_count){ |
077 | if (ptab[bias].pfirst){ |
078 | DO_ERR_EX_NO_SET(ERR_TAB_FLAG); |
080 | ptab[bias].pfirst = p; |
081 | ptab[bias].plast = p + size; |
085 | static int check_clear_malloc_table( void *p){ |
087 | int bias = malloc_count; |
088 | while ((i < bias) && (ptab[i].pfirst!=p)){ |
089 | bias += (ptab[i++].pfirst == 0); |
100 | void *c_malloc( size_t size){ |
102 | CHECK_ALLOC(malloc_count); |
105 | set_malloc_tab(re,size); |
109 | void c_free( void *ptr){ |
111 | if (check_clear_malloc_table(ptr)){ |
112 | CHECK_FREE(malloc_count); |
118 | DO_ERR_EX_NO_SET(ERR_FREE_NOFOUND); |
121 | DO_ERR_EX_NO_SET(ERR_FREE_ZERO); |
125 | void malloc_free_destory( void ){ |
126 | if (!malloc_free_flag) { |
127 | //log("module not inited..",X); |
130 | malloc_free_flag = 0; |
131 | //todo:module destory... |
132 | if (error_type == 0){ |
133 | CHECK_FREE_LACK(malloc_count); |
135 | if (ptab) free (ptab); |
136 | fprintf (stderr, "%s" ,error_str[error_type]); |
139 | void set_check_ptr_range_error_exit( void *p, void **indexP,unsigned long n, const char *strname){ |
143 | fprintf (stderr, "ptr:%s\n" ,strname); |
145 | 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]); |
146 | DO_ERR_EX(tmp, ERR_RANGE_NOFOUND); |
149 | void ** get_malloc_index( void *ptr){ |
152 | for (i = 0,bias = 0 ; bias < malloc_count && i < MAX_MALLOC_NUM; i++){ |
153 | if (ptab[i].pfirst == ptr) return &(ptab[i].pfirst); |
154 | bias += (ptab[i].pfirst !=0); |
156 | DO_ERR_EX_NO_SET(ERR_PTR_NOFOUND); |
这里谈一下,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时,你可以如这种方案操作。而对于错误点检测,通常是需要当作严重错误来停滞的。除非你尝试工 作运行态下的检测,总得有对应操作吧,另谈。其源码如下。
001 | #include "malloc_free.h" |
004 | typedef void (* TEST_FUNC)( void ); |
006 | static void test0( void ){ |
010 | p1 =( char *)c_malloc(4); //*4); |
011 | p2 = ( char *)c_malloc(6); |
014 | return ; //normal check |
016 | static void test1( void ){ |
018 | p1 = ( char *)c_malloc(5); |
019 | p2 = ( char *)c_malloc(6); |
022 | return ; //free lack check |
024 | static void test2( void ){ |
026 | p1 = ( char *)c_malloc(5); |
027 | p3 = p2 = ( char *)c_malloc(6); |
031 | return ; //free more check |
033 | static void test3( void ){ |
034 | char **pp = ( char **)c_malloc( sizeof ( char *)*MAX_MALLOC_NUM + 1); |
036 | for (i = 0 ; i <= MAX_MALLOC_NUM ; i++){ |
037 | pp[i] = ( char *)c_malloc(2); |
039 | return ; //alloc more check |
041 | static void test4( void ){ |
043 | p1 = ( char *)c_malloc(5); |
044 | p2 = ( char *)c_malloc(6); |
045 | p3 = ( char *)c_malloc(6); |
049 | return ; //free twin check |
051 | static void test5( void ){ |
053 | p1 = ( char *)c_malloc(5); |
054 | p2 = ( char *)c_malloc(6); |
057 | return ; //free shift check |
059 | static void test6( void ){ |
061 | p1 = ( char *)c_malloc(5); |
062 | p2 = ( char *)c_malloc(6); |
065 | return ; //free zero check |
068 | static void test7( void ){ |
070 | _TYPE_COUNT_MALLOC_FREE(ptr_count); |
071 | _TYPE_INDEX_MALLOC_FREE(pindex); |
074 | p1 = ( char *)c_malloc(5); |
075 | GET_MALLOC_INDEX(p1,pindex); |
077 | for (i = 3 ; i< 10 ; i++,p2++){ |
078 | if (CHECK_PTR_RANGE(p2,pindex)){ |
079 | printf ( "p2 bias is %d , check ok\n" ,i); |
081 | printf ( "error bias is %d!\n" ,i); |
085 | for (i = 0 ; i< 10 ; i++,p2++){ |
086 | CHECK_PTR_RANGE_ER(p2,pindex,ptr_count, "test7 func p2" ); |
091 | return ; //free zero check |
094 | TEST_FUNC test_a[TEST_MASK+1]= {test0,test1,test2,test3,test4,test5,test6,test7}; |
097 | int main( int argc, char *argv[]){ |
100 | printf ( "hello test_malloc_free_main now run...\n" ); |
103 | printf ( "need parameters!\n" ); |
106 | mode = argv[1][0] - '0' ; |
107 | test_a[mode & TEST_MASK](); |
109 | printf ( "hello test_malloc_free_main now exit...\n" ); |