⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 isemem.cpp

📁 内存泄漏管理,介绍内存泄漏的避免方法
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/********************************************************************

	isemem.cpp

	----------------------------------------------------------------
    软件许可证 - 公有域软件
	版权所有 (C) 2001 VCHelp coPathway ISee workgroup.
	----------------------------------------------------------------
	本文件用途:	内存防护系统实现文件
	本文件编写人:	
					YZ				yzfree##yeah.net

	本文件版本:	20501
	最后修改于:	2002-5-1

	注:以上E-Mail地址中的##请用@替换。
	----------------------------------------------------------------
	修正历史:

		2002-5		第一个测试版

********************************************************************/


/* 如果你的项目没有使用VC的预编译设置,可以将stdafx.h行注释掉 */
#include "StdAfx.h"

/* 如果用于 C 语言,并且不使用预编译选项,可打开下面的编译设置
#if defined(WIN32)
#include <windows.h>
#endif
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#if defined(_MSC_VER) 
#include <malloc.h>
#else
#include <mem.h>
#endif

#include "isemem.h"



/* 如果你想将本系统用于其它语言,可将其编译为DLL。
#ifdef WIN32
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		break;
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
		break;
	case DLL_PROCESS_DETACH:
		break;
    }
    return TRUE;
}
#endif
*/



#ifdef _DEBUG

static LPISE_MBINFO		ise_memblock_header = (LPISE_MBINFO)0;	/* 内存信息块链表头指针 */
static LPISE_MBINFO		ise_memblock_tail   = (LPISE_MBINFO)0;	/* 内存信息块链表尾指针 */
static unsigned long	ise_memblock_count  = 0;				/* 受防护内存块的个数 */

static CRITICAL_SECTION ise_mbheader_access;					/* 内存信息块链表访问关键段 */

static char				ise_err_buf[1024];

#ifdef WIN32
static HANDLE			ise_heap;								/* 内存信息私有堆 */
#else
#endif


/* 内部用函数 */
static LPISE_MBINFO CALLAGREEMENT _create_mb_header(void);
static void			CALLAGREEMENT _free_mb_header(LPISE_MBINFO);
static void			CALLAGREEMENT _insert_mb_header(LPISE_MBINFO);
static void			CALLAGREEMENT _moved_mb_header(LPISE_MBINFO);
static LPISE_MBINFO CALLAGREEMENT _find_mb_header(void *);




/********************************************************************
 * 内存防护系统接口函数
 ********************************************************************/


/* 打开内存管理子系统 */
ISEMEM_API void CALLAGREEMENT ise_open_mem_sys(void)
{
	/* 此函数只能在程序运行时调用一次 */
	assert(ise_memblock_count == 0);
	assert(ise_memblock_header == 0);
	assert(ise_memblock_tail == 0);

	_create_heap();

	InitializeCriticalSection(&ise_mbheader_access);
}


static char	*ise_err0_str = "@@@>>> 警告:程序申请的内存块没有全部被释放!\n";
static char	*ise_err1_str = "@@@>>> 文件 %s 中第 %d 行代码分配的内存块(长度为%d字节)没有被正确释放!\n";


/* 关闭内存管理子系统,并对管理情况做彻底检查 */
ISEMEM_API int CALLAGREEMENT ise_close_mem_sys(void)
{
	int i, mark = 0;

	EnterCriticalSection(&ise_mbheader_access);

	if (ise_memblock_count)
	{
		mark = (int)ise_memblock_count;
		ISE_PUTERR_STR(ise_err0_str);
		inform_me(INFORM_LEVEL);

		for (i=0; i<mark; i++)
		{
			assert(ise_memblock_header);
			sprintf(ise_err_buf, ise_err1_str, ise_memblock_header->filename, ise_memblock_header->linenum, ise_memblock_header->use_len);
			ISE_PUTERR_STR(ise_err_buf);

			_ise_free(ise_memblock_header->pstart);
		}
	}

	assert(ise_memblock_header == 0);
	assert(ise_memblock_tail == 0);
	assert(ise_memblock_count == 0);

	LeaveCriticalSection(&ise_mbheader_access);

	/* 销毁访问关键段 */
	DeleteCriticalSection(&ise_mbheader_access);

	/* 销毁私有堆 */
	_destroy_heap();
	
	return mark;
	/* 0   - 内存管理正常,未发现任何问题 */
	/* 非0 - 出现了未被正确释放的内存 */
}


static char	*ise_err2_str = "@@@>>> 错误:内存防护系统的内部信息已被程序销毁,程序无法继续运行!\n";
static char	*ise_err3_str = "@@@>>> 错误:操作系统异常,程序无法正常运行,建议重启计算机!\n";
static char	*ise_err4_str = "@@@>>> 文件 %s 中第 %d 行代码分配的内存块(长度为%d字节)发生了写越界!\n";
static char	*ise_err5_str = "@@@>>> 文件 %s 中第 %d 行代码分配的内存块(长度为%d字节)被覆写!\n";

static char	*ise_err10_str = "@@@>>> 警告:文件 %s 中第 %d 行代码分配的内存块(%d字节)被程序用非法字符覆盖了,请检查一下各指针变量是否工作正常,或写内存操作是否越界。\n";
static char	*ise_err11_str = "@@@>>> 警告:文件 %s 中第 %d 行代码分配的内存块(%d字节)的前端被非法数据覆盖,请检查一下前面的内存操作是否正常(有可能是无效的指针参与了运算)。\n";
static char	*ise_err12_str = "@@@>>> 警告:代码在向文件 %s 中第 %d 行代码分配的内存块(%d字节)中写入数据时超出了该块的范围,请检查对该内存块的写入操作代码。\n";


/* 检测内存防护系统中所有的内存块是否存在错误(如果存在错误,则通知程序员)*/
ISEMEM_API void CALLAGREEMENT ise_check_mem_sys(void)
{
	LPISE_MBINFO	ptmp;
	unsigned long	mark;

	EnterCriticalSection(&ise_mbheader_access);

	/* 检测所有的受防护内存块 */
	for (ptmp=ise_memblock_tail, mark = 0; ptmp != 0; ptmp = ptmp->prev, mark = 0)
	{
		/* 先检测防护系统自身是否正常 */
		if ((ptmp->tag0 != ISE_MEMBLOCK_MARK)||(ptmp->tag1 != ISE_MEMBLOCK_MARK))
		{
			ISE_PUTERR_STR(ise_err2_str); 
			inform_me(INFORM_LEVEL);
		}

		/* 检测受防护内存的前后防覆写标志 */
		if (((unsigned long *)(unsigned char *)(ptmp->pbegin+4+ptmp->use_len))[0] != ISE_MEMBLOCK_MARK)
		{
			mark |= 0x1;
		}
		if (((unsigned long *)ptmp->pbegin)[0] != ISE_MEMBLOCK_MARK)
		{
			mark |= 0x2;
		}

		/* 通知程序员有关的信息 */
		switch (mark)
		{
		case	0:	/* 未发现问题 */
			break;
		case	1:	/* 本内存块写溢出 */
			sprintf(ise_err_buf, ise_err12_str, ptmp->filename, ptmp->linenum, ptmp->use_len);
			ISE_PUTERR_STR(ise_err_buf); 
			inform_me(INFORM_LEVEL);
			break;
		case	2:	/* 前内存块写溢出 */
			sprintf(ise_err_buf, ise_err11_str, ptmp->filename, ptmp->linenum, ptmp->use_len);
			ISE_PUTERR_STR(ise_err_buf);
			inform_me(INFORM_LEVEL);
			break;
		case	3:	/* 全覆盖 */
			sprintf(ise_err_buf, ise_err10_str, ptmp->filename, ptmp->linenum, ptmp->use_len);
			ISE_PUTERR_STR(ise_err_buf);
			inform_me(INFORM_LEVEL);
			break;
		default:	/* 系统错误 */
			ISE_PUTERR_STR(ise_err3_str);
			inform_me(INFORM_LEVEL);
			break;
		}
	}

	LeaveCriticalSection(&ise_mbheader_access);
}


static char	*ise_info0_str = "对不起,你给出的地址不在防护范围之内,这块内存可能是由其他内存分配函数分配的。\n";
static char	*ise_info1_str = "这个地址所在的内存是由 %s 文件中的第 %d 行代码分配的,尺寸是 %d 字节,";
static char	*ise_info2_str = "不过这个内存块现在已被破坏了,建议检查附近的内存写操作。";
static char	*ise_info3_str = "这个内存块现在工作正常。";


/* 输出指定指针所在内存块的信息 */
ISEMEM_API void   CALLAGREEMENT ise_put_pointer_info(void *p, char *info_buf)
{
	LPISE_MBINFO	pmb = 0;

	assert(p&&info_buf);

	EnterCriticalSection(&ise_mbheader_access);

	/* 查找对应的信息块 */
	pmb = _find_mb_header(p);

	if (pmb == 0)
	{
		strcpy(info_buf, (const char *)ise_info0_str);
	}
	else
	{
		/* 输出相关内存块的信息 */
		sprintf(info_buf, (const char *)ise_info1_str, pmb->filename, pmb->linenum, pmb->use_len);

		/* 并检查改内存块是否正常 */
		if ((((unsigned long *)(unsigned char *)(pmb->pbegin+4+pmb->use_len))[0] != ISE_MEMBLOCK_MARK)||\
			(((unsigned long *)pmb->pbegin)[0] != ISE_MEMBLOCK_MARK))
		{
			strcat(info_buf, (const char *)ise_info2_str);
		}
		else
		{
			strcat(info_buf, (const char *)ise_info3_str);
		}
	}

	LeaveCriticalSection(&ise_mbheader_access);
}


static char	*ise_err20_str = "@@@>>> 警告:文件 %s 中第 %d 行代码所作的有效空间检测发现异常情况,指定的地址(%s 中第 %d 行代码分配的内存块,共 %d 字节)后面只有 %d 字节可用,而程序可能需要写入 %d 字节的数据,如果继续运行程序就有可能覆盖系统信息。请核查此处的内存操作代码。\n";
static char	*ise_err21_str = "@@@>>> 警告:文件 %s 中第 %d 行代码中指定的地址不在防护范围之内,请核查。\n";


/* 确保指定地址p后面有size字节的有效空间可用(此函数与断言的作用相同)*/
ISEMEM_API void CALLAGREEMENT _ise_help_me_sure(void *p, int size, char *fn, int line)
{
	LPISE_MBINFO	pmb = 0;
	
	assert(p&&size);
	
	EnterCriticalSection(&ise_mbheader_access);
	
	/* 查找对应的信息块 */
	pmb = _find_mb_header(p);
	
	if (pmb == 0)
	{
		sprintf(ise_err_buf, (const char *)ise_err21_str, fn, line); 
		ISE_PUTERR_STR(ise_err_buf);
		inform_me(INFORM_LEVEL);		/* 指定的地址不在防护范围内 */
	}
	else
	{
		unsigned char *pb = (unsigned char *)p;

		/* 判断是否有足够的空间 */
		if ((pb+size) > (pmb->pstart+pmb->use_len))
		{
			sprintf(ise_err_buf, (const char *)ise_err20_str, fn, line, pmb->filename, pmb->linenum, pmb->use_len, ((pmb->pstart+pmb->use_len)-pb), size);
			ISE_PUTERR_STR(ise_err_buf);
			inform_me(INFORM_LEVEL);	/* 在指定的内存块中没有足够的空间来容纳size字节的数据 */
		}
		
		/* 顺便检查一下这块内存是否正常 */
		if ((((unsigned long *)(unsigned char *)(pmb->pbegin+4+pmb->use_len))[0] != ISE_MEMBLOCK_MARK)||\
			(((unsigned long *)pmb->pbegin)[0] != ISE_MEMBLOCK_MARK))
		{
			sprintf(ise_err_buf, (const char *)ise_info1_str, pmb->filename, pmb->linenum, pmb->use_len);
			strcat(ise_err_buf, (const char *)ise_info2_str);
			ISE_PUTERR_STR(ise_err_buf);
			inform_me(INFORM_LEVEL);
		}
	}

	LeaveCriticalSection(&ise_mbheader_access);
}


static char	*ise_err30_str = "@@@>>> 注意:文件 %s 中第 %d 行代码中指定的地址不在防护范围之内,最好不要在这个地址上写入任何数据。\n";


/* 检测指定地址所在的内存块是否正常 */
ISEMEM_API void   CALLAGREEMENT _ise_check_pointer(void *p, char *fn, int line)
{
	LPISE_MBINFO	pmb = 0;
	
	assert(p);
	
	EnterCriticalSection(&ise_mbheader_access);
	
	/* 查找对应的信息块 */
	pmb = _find_mb_header(p);
	
	if (pmb == 0)
	{
		sprintf(ise_err_buf, (const char *)ise_err30_str, fn, line); 
		/* 指定的地址不在防护范围内 */
		ISE_PUTERR_STR(ise_err_buf);
	}
	else
	{
		/* 检查内存块是否正常 */
		if ((((unsigned long *)(unsigned char *)(pmb->pbegin+4+pmb->use_len))[0] != ISE_MEMBLOCK_MARK)||\
			(((unsigned long *)pmb->pbegin)[0] != ISE_MEMBLOCK_MARK))
		{
			sprintf(ise_err_buf, (const char *)ise_info1_str, pmb->filename, pmb->linenum, pmb->use_len);
			strcat(ise_err_buf, (const char *)ise_info2_str);
			ISE_PUTERR_STR(ise_err_buf);
			inform_me(INFORM_LEVEL);
		}
	}

	LeaveCriticalSection(&ise_mbheader_access);
}


/* 分配一块受防护的内存块 */
ISEMEM_API void * CALLAGREEMENT _ise_malloc(long size, const char *fn, int linenum)
{
	unsigned char	*pb = 0;
	LPISE_MBINFO	pbm = 0;

	assert(size);

	EnterCriticalSection(&ise_mbheader_access);
	
	/* 分配用户内存,+8为头、尾标志所占字节 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -