C 如何检测内存出错

来源:互联网 发布:宁波每日新房成交数据 编辑:程序博客网 时间:2024/05/29 09:00

#include "stdio.h"

/**********************************************/
// 关于动态内存检测原理
//    (1)检测内存越界方法,在动态申请内存的末端加上特定的标识,当释放的时候,看特定的标识有没有被改变,如果变了,就越界了
//    (2)检测内存没有释放方法,  1)重复申请,导致前面申请的内存没有释放,2)遗忘式的内存未释放, 都看日志
//
//
//
//
//
/**********************************************/


#define  MAX_NODE_COUNT 1024

#define LOG printf
#define malloc_ext malloc
#define free_ext free
#define zkp_malloc(pptr, size) zkp_malloc_ext(pptr, size, __FILE__, __LINE__)
#define zkp_free(pptr) zkp_free_ext(pptr, __FILE__, __LINE__)
// 关于每次动态申请内存的数据
typedef struct CDown
{
    char *m_point;        // 记录动态申请的指针
    int m_size;            // 记录动态申请的内存大小
    char m_file[256];    // 记录动态申请的文件
    int m_line;        // 记录动态申请的行数
}CDown;

typedef struct Cnode
{
    CDown m_param[MAX_NODE_COUNT];
    int m_count;
}Cnode;

Cnode gDownList;
const int END_FLAG = 0x1234ABCD;

// 检测是否重复申请 ,1表示是多次
int check_multi_alloc(char *p, char *file, int line)
{
    int i = 0;

    for (; i < gDownList.m_count; i++)
    {
        if (gDownList.m_param[i].m_point == p)
        {
            LOG("同一指针出现多次申请内存 %s/t/tLine:%d/r/n", file, line);
            return 1;
        }
    }
    return 0;
}

// 把新节点加入到列表, 正常返回值,非负数,添加到第几个节点。负数表示添加到列表失败
int AddNode(CDown *node)
{
    int i = 0;

    for (;i < MAX_NODE_COUNT; i++)
    {
        if (NULL == gDownList.m_param[i].m_point)
        {
            memcpy((void *)(&gDownList.m_param[i]), (void *)node, sizeof(CDown));
            ++gDownList.m_count;
            return i;
        }
    }
    return -1;   
}

// 删除节点, 正常返回值,非负数,添加到第几个节点。负数表示添加到列表失败
int DelNode(char *point)
{   
    int i = 0;
   
    for (;i < MAX_NODE_COUNT; i++)
    {
        if (point == gDownList.m_param[i].m_point)
        {
            free_ext(point);
            //point = NULL;
            memset((void *)&gDownList.m_param[i], 0, sizeof(CDown));
            --gDownList.m_count;
            return i;
        }
    }
    return -1;
}

//打印出现存的内存信息
int PrintMemoryInfo(void)
{
    int i = 0;

    LOG("目前还有%d块内存没有释放/r/n", gDownList.m_count);
    for (;i < MAX_NODE_COUNT; i++)
    {
        if (NULL != gDownList.m_param[i].m_point)
        {
            LOG("未释放内存%s/t/tLINE:%d/t/tsize:%d/r/n", gDownList.m_param[i].m_file, gDownList.m_param[i].m_line, gDownList.m_param[i].m_size);
            if (*((int*)gDownList.m_param[i].m_point) != END_FLAG)
            {
                LOG("越界内存%s/t/tLINE:%d/t/tsize:%d/r/n", gDownList.m_param[i].m_file, gDownList.m_param[i].m_line, gDownList.m_param[i].m_size);
            }
        }
    }
    return 1;
}

//打印出出错内存块信息
int PrintErrorMemory(void)
{
    int i = 0;
    int count = 0;
    for (; i < MAX_NODE_COUNT; i++)
    {
        if ((NULL != gDownList.m_param[i].m_point) && *((int*)(gDownList.m_param[i].m_point + gDownList.m_param[i].m_size)) != END_FLAG)
        {
            LOG("越界内存%s/t/tLINE:%d/t/tsize:%d/r/n", gDownList.m_param[i].m_file, gDownList.m_param[i].m_line, gDownList.m_param[i].m_size);
            count++;
        }
    }
    return 1;
}



//

short zkp_malloc_ext(char **pptr, unsigned int size, char *file, int line)
{
   
    if (NULL != *pptr)
    {
        LOG("Warning 指针未初始化%s/t/tLine:%d/r/n", file, line);
        check_multi_alloc(*pptr, file, line);
    }
    if (NULL != (*pptr = (char*)malloc_ext(size + sizeof(END_FLAG))))
    {
        CDown newnode = {0};
        newnode.m_point = *pptr;
        newnode.m_size = size;
        strcpy(newnode.m_file, file);
        newnode.m_line = line;
        memset((void*)*pptr, 0 , size);
        //在内存的末尾加一个标志
        memcpy((void *)(*pptr + size), &END_FLAG, sizeof(END_FLAG));
        //把新的节点加入到列表中去
        AddNode(&newnode);
        return 1;
    }
    return 0;
}

/*
*pptr, 这里传的二级指针
*/
void zkp_free_ext(char **pptr, char *file, int line)
{
    if (NULL != *pptr)
    {
        if (DelNode(*pptr) < 0)
        {
            LOG("DelNode  Error, %s/t/t%d/r/n", file, line);
        }
        *pptr = NULL;
    }
    else
    {
        LOG("Warning -> Error 指针可能被多次释放%s   Line:%d/r/n", file, line);
    }
    PrintErrorMemory();
}


void main(void)
{
    char *p = NULL;
    zkp_malloc(&p, 40);
    zkp_malloc(&p, 40);
    memset((void *)p, 0, 50);
    PrintMemoryInfo();
}

原创粉丝点击