内存泄漏检测和内存越界检测

本程序为内存泄漏和内存越界检测。本文及程序为原创,转发请标注littlezls原创。
欢迎大家相互交流学习。

1. 说明

作为一个编程人员,或许你会需要下面三个问题:

1.由于代码量大,项目复杂, 用系统函数malloc,realloc,calloc开的空间,最后结束有些没有释放,导致内存泄漏。

2.指针操作错误。导致内存越界。使得结果无法预测。

3.内存泄漏和内存越界后很难定位到那个文件和那行代码开的空间变量导致的。

如果你遇到上面三个问题之一,那么恭喜你i,本程序能帮助到你。

2. 程序说明

1.本程序支持在程序结束时打印那个文件那行代码用malloc,realloc,calloc开的空间变量没有释放。

2.本程序支持那个文件那行代码内存越界,包括上溢出,下溢出检测。

3.本程序支持字节对齐,例如开的空间1024字节对齐。

4.本程序测试用例和输出内容范例见tmemory.h。


以下为源程序

3. 源代码

tmemory.h

/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: tmalloc.h,v 1.0 2019/4/1 19:51:49 $
*
* Portions Copyright (c) 2019-20295 lszhang. All Rights Reserved.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Version: V1.1
* Contributor(s):lszhang
* 1.增加宏UNDEROVERFLOWCHECK支持内存溢出检测。vc已经支持内存溢出检测,
*   故WIN32不再检测。只做8字节内检测。
* 2.增加支持字节对齐开空间函数TALIGNED_MALLOC和释放函数TALIGNED_FREE,
*   例如1024字节对齐。
* 3.如果打印有"TERR: ",证明memory管理出错,需要查找原因。
* Version: V1.0
* Contributor(s):lszhang
* 1.支持内存空间泄漏检测。
* ***** END LICENSE BLOCK ***** */
/*
说明如下:
1、MAXMLLOCNUM:开空间次数最大值,可以自行修改,如果开空间次数超过MAXMLLOCNUM,
则不再进行保存,会每次开空间打印信息,提示是否频繁开空间。
尽量不要在每帧或者循环体里面开空间释放空间。
2、下面的例子是调用例子。需要在代码开始处调用初始化函数TINIT();代码结束处调用退出函数TDEINIT();
3、把自己代码里面的开空间函数进行如下替换即可:
malloc 替换为TMALLOC
free   替换为TFREE
realloc替换为TREALLOC
calloc 替换为TCALLOC
4、如果平台的开空间和释放空间函数不是malloc free realloc calloc。
只需要MALLOC,FREE REALLOC CALLOC重新转定义到平台的空间管理函数即可
*/

/* demo dunction */
/* out printf
TERR: TMALLOC must call TFREE:func:testbuffer,line:112
TERR: TALIGNED_MALLOC must call TALIGNED_FREE:func:testbuffer,line:114
TERR: calloc err:func:testbuffer,line:117,size:1024,must call TALIGNED_FREE:func
:testbuffer,line:116
TSUCCESS: no flow all success!!!!
TERR: no free num:2,malloc total num:7
TERR: func:testbuffer, line:117, p:0X00660530, size:1024, num:5, aligned:0
TERR: func:testbuffer, line:118, p:0X006611C0, size:2048, num:6, aligned:0
TERR: no free total size:3072
请按任意键继续. . .
*/
/*
void test(void)
{
	int num;
	int *ptr0 = NULL;
	int *ptr1 = NULL;
	int *ptr2 = NULL;

	//init
	TINIT();

	//////////////////////////// you code start
	//测试代码开始
	ptr0 = TMALLOC(1024);
	ptr1 = TCALLOC(2, 1024);
	ptr0 = TREALLOC(ptr0, 2048);
	TALIGNED_FREE(ptr0);
	ptr0 = TALIGNED_MALLOC(1024, 2048);
	TFREE(ptr0);
	ptr0 = TALIGNED_MALLOC(1024, 512);
	ptr0 = TREALLOC(ptr0, 1024);
	ptr2 = TREALLOC(NULL, 2048);
	TFREE(ptr1);

	// 测试代码结束
	//////////////////////////// you code end

    // deinit
	TDEINIT();
}
*/
#ifndef TMEMORY_H
#define TMEMORY_H

#ifdef __cplusplus
extern "C" {
#endif

#include
#include
#include

#define TDEBUG

#ifdef TDEBUG

//#ifndef WIN32
#define UNDEROVERFLOWCHECK
//#endif

#define MAXMLLOCNUM 100000

#define CALLOC calloc
#define REALLOC realloc
#define MALLOC malloc
#define FREE free
void tinit(void);
void tdeinit(void);
void *tcalloc(char *func, int line, size_t Count, size_t Size);
void *trealloc(char *func, int line, void *Memory, size_t NewSize);
void *tmalloc(char *func, int line, int size);
void tfree(void *ptr);
void *taligned_malloc(char *func, int line, int size, int alignment);
void taligned_free(void *palignedmem);

/*
 * call below functions
 */
#define TINIT tinit
#define TDEINIT tdeinit
#define TALIGNED_MALLOC(size,alignment) taligned_malloc(__FUNCTION__, __LINE__, size,alignment)
#define TALIGNED_FREE(ptr) taligned_free(ptr)
#define TCALLOC(Count,Size) tcalloc(__FUNCTION__, __LINE__, Count,Size)
#define TREALLOC(Memory,NewSize) trealloc(__FUNCTION__, __LINE__, Memory, NewSize)
#define TMALLOC(len) tmalloc(__FUNCTION__, __LINE__, len)
#define TFREE(ptr) tfree(ptr)
#else
#define TINIT
#define TDEINIT
#define TCALLOC calloc
#define TREALLOC realloc
#define TMALLOC malloc
#define TFREE free
#endif

#ifdef __cplusplus
}
#endif

#endif /* TMEMORY_H */

tmemory.c

/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: tmalloc.c,v 1.0 2019/4/1 19:51:49 $
*
* Portions Copyright (c) 2019-2029 lszhang. All Rights Reserved.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Version: V1.0
* Contributor(s):lszhang
*
* ***** END LICENSE BLOCK ***** */

#include 
#include 
#include 
#include "tmemory.h"

#ifdef TDEBUG

#define STRINGLEN 127
#define OVERFLOW 1
#define UNDERFLOW 2
#define CHECKDATALEN 8

#ifdef UNDEROVERFLOWCHECK

#define EXTRADATALEN (2 * CHECKDATALEN)
#define FLOWSIZE CHECKDATALEN
#else
#define EXTRADATALEN 0
#define FLOWSIZE 0
#endif

typedef struct vars {
	char func[STRINGLEN + 1];
	int line;
	void *ptr;
	int size;
	int num;
	int flow;
	int aligned;
} vars;

typedef struct mem_st {
	vars var[MAXMLLOCNUM];
	int lost;
	int underflow;
	int overflow;
	int total;
} mem_st;

static mem_st tmemory;
static const unsigned char tmemory_data[CHECKDATALEN] = {
	0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef
};
void tinit(void)
{
	memset(&tmemory, 0, sizeof(mem_st));
}

void *tmemorydata(void *ptr, size_t Size)
{
	unsigned char *pchar = ptr;
	if (!ptr)
		return ptr;
	if (FLOWSIZE != 0) {
		memcpy(pchar, tmemory_data, FLOWSIZE);
		memcpy(pchar + Size + FLOWSIZE, tmemory_data, FLOWSIZE);
	}
	return (void *)(pchar + FLOWSIZE);
}
void *tmemoryflow(void *ptr, int *pnum)
{
	int i = 0;
	int j = 0;
	unsigned char *pchar = ptr;
	int num = 0;
	int flow = 0;
	int Size = 0;
	if (!ptr)
		return NULL;

	pchar -= FLOWSIZE;
	for (i = 0; i < FLOWSIZE; i++) {
		if (pchar[i] != tmemory_data[i]) {
			flow = UNDERFLOW;
			printf("TERR: CRT detected that the application wrote to memory before start of heap buffer.\n");
			tmemory.underflow++;
			break;
		}
	}

	num = tmemory.total > MAXMLLOCNUM ? MAXMLLOCNUM : tmemory.total;
	for (i = 0; i < num; i++) {
		if (tmemory.var[i].ptr == ptr) {
			Size = tmemory.var[i].size;
			for (j = 0; j < FLOWSIZE; j++) {
				if (pchar[Size + FLOWSIZE + j] != tmemory_data[j]) {
					flow = OVERFLOW;
					printf("TERR: CRT detected that the application wrote to memory after end of heap buffer.\n");
					tmemory.overflow++;
					break;
				}
			}
			if (flow) {
				printf("TERR: err-flow func:%s, line:%d, p:%#p, size:%d, num:%d,flow:%d\n",
					tmemory.var[i].func,
					tmemory.var[i].line,
					tmemory.var[i].ptr,
					tmemory.var[i].size,
					tmemory.var[i].num,
					flow);
			}
			*pnum = i;
			tmemory.var[i].ptr = 0;
			tmemory.var[i].flow = flow;
			tmemory.lost--;
			if (tmemory.var[i].aligned)
				return NULL;
			break;
		}
	}
	if (flow && (i == num)) {
		printf("TERR: err-flow  p:%#p, size:%d\n", ptr, Size);
	}

	return (void *)pchar;
}

void tdeinit(void)
{
	int i = 0;
	int total = 0;

	if (tmemory.total){
		if (FLOWSIZE != 0) {
			if (tmemory.overflow || tmemory.underflow) {
				printf("TERR: err-flow:overflow num:%d. underflow num:%d\n", tmemory.overflow,
					tmemory.underflow);
			} else {
				printf("TSUCCESS: no flow all success!!!!\n");
			}
		}

		if (tmemory.lost == 0) {
			printf("TSUCCESS:free all success!!!!,malloc total num:%d\n", tmemory.total);
		} else {
			int lostnum = 0;
			int num = tmemory.total > MAXMLLOCNUM ? MAXMLLOCNUM : tmemory.total;
			printf("TERR: no free num:%d,malloc total num:%d\n", tmemory.lost, tmemory.total);
			for (i = 0; i < num; i++) {
				if (tmemory.var[i].ptr) {
					printf("TERR: func:%s, line:%d, p:%#p, size:%d, num:%d, aligned:%d\n",
						tmemory.var[i].func,
						tmemory.var[i].line,
						tmemory.var[i].ptr,
						tmemory.var[i].size,
						tmemory.var[i].num,
						tmemory.var[i].aligned);
					lostnum++;
					total += tmemory.var[i].size;
				}
			}
			if (lostnum != tmemory.lost) {
				printf("TERR: printf num :%d,no printf num:%d\n", lostnum, tmemory.lost - lostnum);
			}
			printf("TERR: no free total size:%d\n", total);
		}
	}	
}

void *tcalloc(char *func, int line, size_t Count, size_t Size)
{
	void *ptr = CALLOC(Count, Size + EXTRADATALEN);
	if (!ptr) {
		printf("TERR: calloc err:func:%s,line:%d,size:%d\n", func, line, Count * Size);
	} else {
		ptr = tmemorydata(ptr, Count * Size);
		if (tmemory.total < MAXMLLOCNUM) {
			strncpy(tmemory.var[tmemory.total].func, func, STRINGLEN);
			tmemory.var[tmemory.total].line = line;
			tmemory.var[tmemory.total].size = Count * Size;
			tmemory.var[tmemory.total].ptr = ptr;
			tmemory.var[tmemory.total].num = tmemory.total;
		} else {
			printf("TERR: warning calloc num :%d,func:%s,line:%d\n", tmemory.total, func, line);
		}
		tmemory.total++;
		tmemory.lost++;
	}
	return ptr;
}

void   *trealloc(char *func, int line, void *Memory, size_t NewSize)
{
	void *ptr = NULL;
	if (Memory) {
		int num = -1;
		void *ptr = tmemoryflow(Memory, &num);
		if (!ptr) {
			printf("TERR: calloc err:func:%s,line:%d,size:%d,must call TALIGNED_FREE:func:%s,line:%d\n",
				func, line, NewSize,
				tmemory.var[num].func,
				tmemory.var[num].line);
			FREE((void *)(((int *)Memory)[-1 - FLOWSIZE / 4]));
		}

		Memory = ptr;
	}

	ptr = REALLOC(Memory, NewSize + EXTRADATALEN);
	if (!ptr) {
		printf("TERR: calloc err:func:%s,line:%d,size:%d\n", func, line, NewSize);
	} else {
		ptr = tmemorydata(ptr, NewSize);
		if (tmemory.total < MAXMLLOCNUM) {
			strncpy(tmemory.var[tmemory.total].func, func, STRINGLEN);
			tmemory.var[tmemory.total].line = line;
			tmemory.var[tmemory.total].size = NewSize;
			tmemory.var[tmemory.total].ptr = ptr;
			tmemory.var[tmemory.total].num = tmemory.total;
		} else {
			printf("TERR: warning realloc num :%d,func:%s,line:%d\n", tmemory.total, func, line);
		}
		tmemory.total++;
		tmemory.lost++;
	}
	return ptr;
}

void *tmalloc(char *func, int line, int size)
{
	void *ptr = MALLOC(size + EXTRADATALEN);
	if (!ptr) {
		printf("TERR: malloc err:func:%s,line:%d,size:%d\n", func, line, size);
	} else {
		ptr = tmemorydata(ptr, size);
		if (tmemory.total < MAXMLLOCNUM) {
			strncpy(tmemory.var[tmemory.total].func, func, STRINGLEN);
			tmemory.var[tmemory.total].line = line;
			tmemory.var[tmemory.total].size = size;
			tmemory.var[tmemory.total].ptr = ptr;
			tmemory.var[tmemory.total].num = tmemory.total;
		} else {
			printf("TERR: warning malloc num :%d,func:%s,line:%d\n", tmemory.total, func, line);
		}
		tmemory.total++;
		tmemory.lost++;
	}
	return ptr;
}

void tfree(void *palignedmem)
{
	if (palignedmem) {
		int num = -1;
		void *ptr = tmemoryflow(palignedmem, &num);
		if (ptr == NULL) {
			printf("TERR: TALIGNED_MALLOC must call TALIGNED_FREE:func:%s,line:%d\n",
				tmemory.var[num].func,
				tmemory.var[num].line);
			FREE((void *)(((int *)palignedmem)[-1 - FLOWSIZE / 4]));
			return;
		}
		FREE(ptr);
	}
}

void *taligned_malloc(char *func, int line, int size, int alignment)
{
	if (alignment & (alignment - 1)) {
		return NULL;
	} else {
		void *praw = malloc(sizeof(void *) + EXTRADATALEN + size + alignment);
		if (praw) {
			unsigned char *pchar = praw;
			void *pbuf = (void *)(pchar + sizeof(void *) + EXTRADATALEN);
			void *palignedbuf = (void *)((((unsigned int)pbuf) | (alignment - 1)) + 1);
			tmemorydata((void *)((unsigned int)palignedbuf - FLOWSIZE), size);
			((int *)palignedbuf)[-1 - FLOWSIZE / 4] = praw;
			if (tmemory.total < MAXMLLOCNUM) {
				strncpy(tmemory.var[tmemory.total].func, func, STRINGLEN);
				tmemory.var[tmemory.total].line = line;
				tmemory.var[tmemory.total].size = size;
				tmemory.var[tmemory.total].ptr = palignedbuf;
				tmemory.var[tmemory.total].num = tmemory.total;
				tmemory.var[tmemory.total].aligned = 1;
			} else {
				printf("TERR: warning taligned_malloc num : %d,func:%s,line:%d\n", tmemory.total, func,
					line);
			}
			tmemory.total++;
			tmemory.lost++;
			return palignedbuf;
		} else {
			return NULL;
		}
	}
}

void taligned_free(void *palignedmem)
{
	if (palignedmem) {
		int num = -1;
		void *ptr = tmemoryflow(palignedmem, &num);
		if (tmemory.total > MAXMLLOCNUM) {
			printf("TERR: warning total:%d >num:%d\n", tmemory.total, MAXMLLOCNUM);
		} else {
			if (ptr) {
				printf("TERR: TMALLOC must call TFREE:func:%s,line:%d\n",
					tmemory.var[num].func,
					tmemory.var[num].line);
				FREE(ptr);
				return;
			}

		}
		FREE((void *)(((int *)palignedmem)[-1 - FLOWSIZE / 4]));
	}
}
#endif

你可能感兴趣的:(开发类)