c++ - _CrtSetAllocHook - 未处理的异常

标签 c++ c visual-studio visual-c++

我使用 Windows 10 x64 和 Visual Studio 2019。这是一个简单的程序 (x86-Debug),它应该打印内存分配大小:

#include <iostream>

int MyAllocHook(int allocType, void* userData, std::size_t size, int blockType, long requestNumber,
const unsigned char* filename, int lineNumber)
{
    std::cout << "Alloc: " << size << std::endl;
    return 1;
}

int main()
{
    _CrtSetAllocHook(MyAllocHook);
    void* ptr = malloc(128);
    if (ptr)
    {
        free(ptr);
    }

    system("pause");
    return 0;
}

当我运行程序时,我得到 Exception Unhandled 错误:
Unhandled exception at 0x7A6A2B19 (ucrtbased.dll) in testcpp.exe: 0xC00000FD: Stack overflow (parameters: 0x00000000, 0x00EB2000). occurred

怎么了 ?如何解决?

最佳答案

“堆栈溢出”(哈哈)是我的赠品。

钩子(Hook)中的 I/O 和字符串操作导致它自己的内存分配,因此钩子(Hook)被一次又一次地调用,直到它溢出堆栈。

你得看看blockType并明确排除运行时本身的调用,如下所述:https://docs.microsoft.com/en-us/visualstudio/debugger/allocation-hooks-and-c-run-time-memory-allocations?view=vs-2019

int MyAllocHook(int allocType, void* userData, std::size_t size,
                int blockType, long requestNumber,
                const unsigned char* filename, int lineNumber)
{
    // Do not hook calls from the C Runtime itself
    if (blockType == _CRT_BLOCK) return TRUE;

    std::cout << "Alloc: " << size << std::endl;
    return 1;
}

这样,来自 I/O 库本身的内存分配调用不会导致递归调用。

编辑 啊哈,您不仅被 C 运行时调用挂断,还被您自己的“正常”字符串和 I/O 调用挂断,这些调用不是来自运行时。基本上你是在间接调用 malloc()和/或 new从处理程序内部,这是不允许的。

这个测试程序可以让你看到被分配的大量内存:
#include <iostream>

struct allocinfo {
    int size;
    const char *filename;
    int lineno;
    int alloctype;
    int blocktype;
};

struct allocinfo allocs[256], *allocp = allocs;
volatile bool capturing = true;

static const char *printableAllocType(int t)
{
    switch (t)
    {
    case _HOOK_ALLOC: return "_HOOK_ALLOC";
    case _HOOK_REALLOC: return "_HOOK_REALLOC";
    case _HOOK_FREE: return "_HOOK_FREE";
    default: return "?";
    }
}

static const char *printableBlockType(int t)
{
    switch (t)
    {
    case _FREE_BLOCK: return "_FREE_BLOCK";
    case _NORMAL_BLOCK: return "_NORMAL_BLOCK";
    case _CRT_BLOCK: return "_CRT_BLOCK";
    case _IGNORE_BLOCK: return "_IGNORE_BLOCK";
    case _CLIENT_BLOCK: return "_CLIENT_BLOCK";
    default: return "?";
    }
}

int MyAllocHook( int allocType, void* userData, std::size_t size,
                 int blockType, long requestNumber,
                 const unsigned char* filename, int lineNumber)
{
    if (blockType == _CRT_BLOCK) return 1;

    if (capturing)
    {
        allocp->size = (int)size;
        allocp->lineno = lineNumber;
        allocp->blocktype = blockType;
        allocp->alloctype = allocType;
        allocp->filename = (const char *)filename;
        allocp++;
    }

    static bool firstTime = true;

    if (firstTime)
    {
        firstTime = false;
        std::cout << "Alloc : " << size << std::endl;
    }

    return 1;
}

int main()
{
    _CrtSetAllocHook(MyAllocHook);
    void* ptr = malloc(128);
    if (ptr)
    {
        free(ptr);
    }

    capturing = false;

    for (struct allocinfo *ap = allocs; ap < allocp; ap++)
        printf("%-15s %-15s Size %d  file %s line %d\n",
            printableAllocType(ap->alloctype),
            printableBlockType(ap->blocktype),
            ap->size, ap->filename, ap->lineno);

    return 0;
}

它以一种不分配任何内存(应该是安全的)的方式记录所有非 C 运行时调用,并在最后报告您的请求生成了您预期的明显 128 字节,加上另外两个 16 字节分配来自处理程序中的字符串代码:
Alloc : 128
_HOOK_ALLOC     _NORMAL_BLOCK   Size 128  file (null) line 0 <-- EXPECTED
_HOOK_ALLOC     _NORMAL_BLOCK   Size 16  file (null) line 0  <-- SURPRISE!
_HOOK_ALLOC     _NORMAL_BLOCK   Size 16  file (null) line 0  <-- SURPRISE!
_HOOK_FREE      _NORMAL_BLOCK   Size 0  file (null) line 0
_HOOK_FREE      _NORMAL_BLOCK   Size 0  file (null) line 0
_HOOK_FREE      _NORMAL_BLOCK   Size 0  file (null) line 0

代码本身完全被破解在一起,但它演示了正在发生的事情。

注意:此代码不能正确重入,如另一个答案中所述。

摘要:即使您正确排除了 C 运行时内存,您也无法在直接或间接分配用户内存的内存 Hook 中执行任何操作。

有趣的事实:移动 _CRT_BLOCK在捕获信息后检查,您会看到 C 运行时有多忙。

编辑 - 我刚刚修改了我的小测试程序,发现调用 malloc()new两者都被视为“普通”内存块,而不是运行时,因此这表明您根本不能在内存 Hook 处理程序中使用它们。

关于c++ - _CrtSetAllocHook - 未处理的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59236888/

相关文章:

C 编程 以十六进制打印一个长 double 的 float

c - 指针与整数比较失败

c# - 在 "ilc.exe"模式下编译时,"Release"退出代码 1104

c# - Visual Studio 2008/C# : How to find dead code in a project?

C++ w/静态模板方法

c++ - 有 Yacc 语法调试器吗?

c++ - 对临时对象成员的 const 引用

c++ - 一道面试题

c - 服务器不接收来自客户端的数据

visual-studio-2010 - 获取最新信息后解决方案资源管理器不显示文件