我使用 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/