本程序为内存泄漏和内存越界检测。本文及程序为原创,转发请标注littlezls原创。
欢迎大家相互交流学习。
作为一个编程人员,或许你会需要下面三个问题:
如果你遇到上面三个问题之一,那么恭喜你i,本程序能帮助到你。
以下为源程序
/* ***** 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 */
/* ***** 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