原文出处:http://www.devdiv.net/thread-15649-1-1.html(转载时请注明)
原理是申请内存时,多申请一些,并把后面的保护起来。 这样,当程序访问越界时,就会报异常,并在当前调用栈停下来,让我们可以跟踪凶案现场。
增加以下实现与宏定义: inline void* devdiv_malloc_protected(size_t size) { int page_num = (int) (size / 0x1000 + 1); size_t offset = page_num * 0x1000 - size; void* p = ::VirtualAlloc(NULL, page_num*0x1000+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (NULL == p) { // ASSERT(FALSE); return NULL; // 内存用尽 } void* pchecker = (char*)p + page_num * 0x1000; DWORD old_value; ::VirtualProtect(pchecker, 0x1000, PAGE_NOACCESS, &old_value); return (char*)p + offset; } inline void devdiv_free_protected(void* p) { //找到VirtualAlloc时候的起始地址 p = (char*)p - (size_t)p % 0x1000; ::VirtualFree(p, 0, MEM_RELEASE); } inline void* __cdecl operator new(unsigned int s, int) { return devdiv_malloc_protected(s); } // {{ 如果把以下注释掉,则异常出现在不该出现的地方。 #ifdef _DEBUG inline void __cdecl operator delete[](void* pvMem) { devdiv_free_protected(pvMem); } #define malloc devdiv_malloc_protected #define free devdiv_free_protected #define new new(1) #endif // }} 测试代码: void main() { char* p = (char*)malloc(5); char* p2 = new char[5]; strcpy(p, "devdiv"); // 我希望这里异常。而不是把隐患留着,以后出现在不该出现的莫名其妙的地方。 strcpy(p2, "devdiv"); // 我希望这里异常 free(p); delete[] p2; } 这样用的缺点是,每次分配内存,都会比较耗。因为设置windows的内存保护属性是以页(默认是0x1000 byte)为单位的。但一般只定义为DEBUG版时用。 |