其中functionName记录了函数名称,line记录文件行数, pAddress记录了指针地址, size指向了pAddress指向的内存大小,next指向下一个结构节点。

  c)记录内存节点属性

  在MEMORY_SET_PROCESS处理过程中,不仅需要调用memset函数,还需要对当前内存节点进行记录和保存。可以通过使用单链表节点的方法进行记录。但是如果发现pAddress指向的内存是malloc时候分配过的,此时不需要记录了,因为堆内存指针溢出的问题lib库已经帮我们解决了。

 d)改造原有内存指针操作函数

  比如对memmove等函数进行改造,不失去一般性,我们以memmove作为范例。

  添加宏语句 #define memmove(dst, src, size)        MEMMOVE_PROCESS(dst, src, size)

void MEMMOVE_PROCESS(void* dst, const void* src, int size)  
{  
    MEMORY_NODE* pMemNode = check_node_exist(dst);  
    if(NULL == pMemNode) return;  
  
    assert(dst >= (pMemNode->pAddress));  
    assert(((char*)dst + size) <= ((char*)pMemNode->pAddress + pMemNode->size));  
        memmove(dst, src, size);  
    return;  
}
   e)下面是内存节点的删除工作。

  我们知道函数是需要反复使用堆栈的。不同时间相同的堆栈地址对应的是完全不同的指针内容,这要求我们在函数返回的时候对内存地址进行清理,把内存节点从对应的链表删除。

  我们知道在函数运行后,ebp和esp之间的内存是通常意义上临时变量的生存空间,所以下面的一段宏可以记录函数的内存空间。

#ifdef MEMORY_LEAK_TEST   
#define FUNCTION_LOCAL_SPACE_RECORD()   
{  
    int* functionBpRecord = 0;  
    int*  functionSpRecord = 0;  
}  
#else   
#define FUNCTION_LOCAL_SPACE_RECORD()   
#endif   
  
#ifdef MEMORY_LEAK_TEST   
#define FUNCTION_LEAVE_PROCESS()   
{  
__asm { mov functionBpRecord, bp  
    mov functionSpRecord, sp}  
    FREE_MEMORY_NODE(functionBpRecord, functionSpRecord)  
}  
#else   
#define FUNCTION_LEAVE_PROCESS()   
#endif
 
  这两段宏代码,需要插在函数的起始位置和结束的位置,这样在函数结束的时候可以根据ebp和esp删除堆栈空间中的所有内存,方便了堆栈的重复使用。如果是全局内存,因为函数的变化不会导致地址的变化,所以没有必要进行全局内存节点的处理。

  内存溢出检查流程总结:

  (1)对memset进行重新设计,记录除了malloc指针外的一切内存;

  (2)对memmove, strcpy, strncpy,strcat,sprintf等全部函数进行重新设计,因为我们需要对他们的指针运行范围进行判断;

  (3)在函数的开头和结尾位置添加宏处理。函数运行返回前进行节点清除。