即时检测在Windows堆损坏的错误。怎么样? [英] Immediate detection of heap corruption errors on Windows. How?

查看:107
本文介绍了即时检测在Windows堆损坏的错误。怎么样?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法入睡! :)

我在Windows上一个相当大的项目,并遇到了一些堆损坏问题。我已阅读全部SO,包括这个漂亮的话题:如何调试堆损坏错误,但没有什么是合适的,帮我盒子外面。 调试CRT 的BoundsChecker 检测堆损坏,但地址总是不同的检测点总是远离实际内存覆盖。我还没有睡,直到深夜,并制作了下面的技巧:

  DWORD每页= 0;内嵌无效SetPageSize()
{
    如果(!每页)
    {
        SYSTEM_INFO SYSINFO;
        的GetSystemInfo(安培; SYSINFO);
        每页= sysInfo.dwPageSize;
    }
}void *的new操作符(为size_t n大小)
{
    SetPageSize();
    为size_t额外= n大小%每页;
    n大小= n大小+(每页 - 额外的);
    返回PTR = VirtualAlloc的(0,n大小,MEM_COMMIT,PAGE_READWRITE);
}无效的operator delete(void *的PPTR)
{
    MEMORY_BASIC_INFORMATION MBI;
    VirtualQuery来(PPTR,&安培; MBI,siz​​eof的(MBI));
    //休假页,保留状态,但免费物理内存
    VirtualFree(PPTR,0,MEM_DECOMMIT);
    DWORD OldProtect;
    //保护的地址空间,因此没有人可以访问这些页面
    VirtualProtect的(PPTR,mbi.RegionSize,PAGE_NOACCESS,&安培; OldProtect);
}

有些堆损坏错误变得明显,我能够解决这些问题。有退出没有更多的调试CRT警告。但是,我有一个关于这个技巧的一些问题:

1 它可以产生任何误报?

2 它会错过一些堆损坏的? (即使我们更换的malloc / realloc的/免费的吗?)

3。它未能与 OUT_OF_MEMORY 在32位模式运行,仅在64位。我是不是正确的,我们只是在32位用完虚拟地址空间?


解决方案

  

它可以产生任何误报?


那么,这只会赶上类的虫子免费使用后()。为此,我认为,这是相当不错的。

如果您尝试删除的东西,这不是版,这是一个不同类型的bug。在删除你应该首先检查内存被分配确实。你不应该盲目释放内存并将其标记为不可访问。我会尽量避免和报表(按,说,做一个调试中断)时,有企图删除的东西,因为它是永远不应该被删除编辑。


  

这会错过一些堆损坏的? (即使我们更换的malloc / realloc的/免费的吗?)


显然,这不会赶上堆数据全部损坏之间的新键,以及相应删除。它只会对付那些试图在删除

例如:

  MyObj中* =新MyObj中(1,2,3);
// * MyObj中的腐败发生在这里,可能会被忽视
删除MyObj中;


  

它无法在32位的目标与OUT_OF_MEMORY错误仅在64位运行。我是不是正确的,我们只是在32位用完虚拟地址空间?


通常情况下,你可以有大约在32位Windows的虚拟地址空间2GB〜。这是很好的最多〜524288 就像在所提供的code。但比4KB大对象,你就可以较顺利分配较少的实例。然后地址空间碎片化将降低这一数字更进一步。

这是一个完美的预期结果,如果你在程序的生命周期中创建多个实例。

I can't sleep! :)

I have a reasonably large project on Windows and encountered some heap corruption issues. I have read all SO, including this nice topic: How to debug heap corruption errors?, however nothing was suitable to help me out-of-the-box. Debug CRT and BoundsChecker detected heap corruptions, but addresses were always different and detections point were always far away from the actual memory overwrites. I have not slept till the middle of the night and crafted the following hack:

DWORD PageSize = 0;

inline void SetPageSize()
{
    if ( !PageSize )
    {
        SYSTEM_INFO sysInfo;
        GetSystemInfo(&sysInfo);
        PageSize = sysInfo.dwPageSize;
    }
}

void* operator new (size_t nSize)
{
    SetPageSize();
    size_t Extra = nSize % PageSize;
    nSize = nSize + ( PageSize - Extra );
    return Ptr = VirtualAlloc( 0, nSize, MEM_COMMIT, PAGE_READWRITE);
}

void operator delete (void* pPtr)
{
    MEMORY_BASIC_INFORMATION mbi;
    VirtualQuery(pPtr, &mbi, sizeof(mbi));
    // leave pages in reserved state, but free the physical memory
    VirtualFree(pPtr, 0, MEM_DECOMMIT);
    DWORD OldProtect;
    // protect the address space, so noone can access those pages
    VirtualProtect(pPtr, mbi.RegionSize, PAGE_NOACCESS, &OldProtect);
}

Some heap corruption errors became obvious and i was able to fix them. There were no more Debug CRT warnings on exit. However, i have some questions regarding this hack:

1. Can it produce any false positives?

2. Can it miss some of the heap corruptions? (even if we replace malloc/realloc/free?)

3. It fails to run on 32-bits with OUT_OF_MEMORY, only on 64-bits. Am I right we simply run out of the virtual address space on 32-bits?

解决方案

Can it produce any false positives?

So, this will only catch bugs of the class "use after free()". For that purpose, I think, it's reasonably good.

If you try to delete something that wasn't new'ed, that's a different type of bug. In delete you should first check if the memory has been indeed allocated. You shouldn't be blindly freeing the memory and marking it as inaccessible. I'd try to avoid that and report (by, say, doing a debug break) when there's an attempt to delete something that shouldn't be deleted because it was never new'ed.

Can it miss some of the heap corruptions? (even if we replace malloc/realloc/free?)

Obviously, this won't catch all corruptions of heap data between new and and the respective delete. It will only catch those attempted after delete.

E.g.:

myObj* = new MyObj(1,2,3);
// corruption of *myObj happens here and may go unnoticed
delete myObj;

It fails to run on 32-bit target with OUT_OF_MEMORY error, only on 64-bit. Am I right that we simply run out of the virtual address space on 32-bits?

Typically you have available about ~2GB of the virtual address space on a 32-bit Windows. That's good for at most ~524288 new's like in the provided code. But with objects bigger than 4KB, you'll be able to successfully allocate fewer instances than that. And then address space fragmentation will reduce that number further.

It's a perfectly expected outcome if you create many object instances during the life cycle of your program.

这篇关于即时检测在Windows堆损坏的错误。怎么样?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆