c++ - 立即检测 Windows 上的堆损坏错误。如何?

标签 c++ c heap-memory heap-corruption virtualalloc

我睡不着! :)

我在 Windows 上有一个相当大的项目,但遇到了一些堆损坏问题。我已经阅读了所有 SO,包括这个不错的主题:How to debug heap corruption errors? ,但是没有什么可以开箱即用地帮助我。 Debug CRTBoundsChecker 检测到堆损坏,但地址始终不同,检测点始终远离实际的内存覆盖。我一直到半夜都没睡,并制作了以下 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);
}

一些堆损坏错误变得很明显,我能够修复它们。退出时不再有 Debug CRT 警告。但是,我对这个 hack 有一些疑问:

1.它会产生任何误报吗?

2. 它会漏掉一些堆损坏吗? (即使我们替换 malloc/realloc/free?)

3. 使用 OUT_OF_MEMORY 无法在 32 位上运行,只能在 64 位上运行。我说得对吗,我们只是用完了 32 位的虚拟地址空间?

最佳答案

Can it produce any false positives?

因此,这只会捕获“在 free() 之后使用”类的错误。为此,我认为,这是相当不错的。

如果您尝试 delete 一些不是 new 的内容,这是一种不同类型的错误。在 delete 中,您应该首先检查内存是否确实已分配。您不应该盲目地释放内存并将其标记为不可访问。当尝试 delete 一些不应该被删除的东西时,我会尽量避免这种情况并报告(例如,通过调试中断),因为它从来都不是 new'ed.

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

显然,这不会捕获 new 和相应的 delete 之间的所有堆数据损坏。它只会捕获那些在 delete 之后尝试的。

例如:

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?

在 32 位 Windows 上,您通常可以使用大约 2GB 的虚拟地址空间。在提供的代码中,这对于最多 ~524288 个 new 是有好处的。但是对于大于 4KB 的对象,您将能够成功分配比这更少的实例。然后地址空间碎片将进一步减少这个数字。

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

关于c++ - 立即检测 Windows 上的堆损坏错误。如何?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12724057/

相关文章:

c++ - C++中的临时对象在哪里分配?

c++ - Pthreads 在互斥锁中间死亡

c++ - 头文件包含/转发声明

c++ - CUDA编译错误: class template has already been defined

c - sysctl 迁移到 2.6.35

c - 如何在 C 中解决此输出?

c - 绑定(bind)到特定地址但随机端口 Linux

c++ - 查找仅在性能测试下发生的堆损坏的最佳方法是什么?

arrays - 堆上的动态多维数组

c++ - 意外的 std::io_base::failure 异常