测试c++代码和IsBadWritePtr

Testing C++ code and IsBadWritePtr

本文关键字:IsBadWritePtr 代码 c++ 测试      更新时间:2023-10-16

我目前正在为我的c++代码的一些功能编写一些基本测试(这是一个游戏引擎,我主要是为了教育目的而编写的)。我想测试的特性之一是内存分配代码。测试目前由一个函数组成,如果代码处于调试模式,则该函数在每次启动时运行。这迫使我在调试时总是测试代码。

为了测试我的内存分配代码,我的直觉是这样做:

int* test = MemoryManager::AllocateMemory<int>();
assert(!IsBadWritePtr(test, sizeof(int)), "Memory allocation test failed: allocate");
MemoryManager::FreeMemory(test);
assert(IsBadWritePtr(test, sizeof(int)), "Memory free test failed: free");

这段代码工作得很好,但是我能找到的所有资源都说不要使用IsBadWritePtr函数(对于那些不熟悉的人来说,这是一个WinAPI函数)。在这种情况下使用这个函数没问题吗?我发现使用它的三个主要警告是:

这可能会导致保护页面出现问题

这不是一个问题,因为内存分配代码就在那里,我知道我没有分配一个保护页。

最好早点失败

这不是一个考虑,因为我确实使用它来尽可能早地失败。

不是线程安全的

测试代码在执行开始时执行,远远早于任何其他线程存在。它还作用于没有创建其他指针的内存,因此不可能存在于其他线程中。

所以基本上我想知道在这种情况下使用这个函数是否是一个好主意,以及我是否遗漏了关于这个函数的任何东西。我也意识到,指向错误位置的东西仍然会通过这个测试,但它至少检测到大多数内存分配错误,对吧(如果分配失败,我有什么机会得到一个指向有效内存的指针?)

我本来打算把这段写为注释的,但是太长了。

我要提出一个显而易见的问题:为什么不以传统的方式(通过返回null或抛出异常)测试失败呢?

别管IsBadWritePtr是如此不受欢迎的事实(甚至它的文档都说它已经过时了,你不应该使用它),但是你的用例甚至看起来都不合适。来自MSDN文档:

这个函数通常在处理从第三方库返回的指针时使用,在这种情况下,您无法确定第三方DLL中的内存管理行为。

但是你没有使用它来测试任何从DLL传递/返回的东西,你似乎只是用它来测试分配成功,这不仅是不必要的(因为你已经知道从HeapAlloc, GlobalAlloc等的返回值),但它不是什么IsBadWritePtr的目的。

此外,测试分配成功不是你应该只在调试模式下做的事情,或者断言,因为它显然不在你的控制范围内,你不能试图通过调试来"修复"它。

基于@user1610015的回答,IsBadReadPtr不应该在您的场景中工作的原因有一个。

基本上IsBadReadPtr工作在整个页面粒度。这意味着要使上述代码正确,您所做的每次分配都将消耗整个页面(最少4KB)。

现代分配器使用各种技巧将大量分配打包到页面中(低碎片桶堆、分配链表等)。如果你不像这样打包小的分配,那么像stl map和其他使用大量小分配的库绝对会扼杀你的游戏(无论是内存使用还是缓存一致性都会被这么多未使用的填充所破坏)。

作为一个方面,你最后关于线程安全的评论是危险的。你链接到的许多应用程序和库都可以通过全局对象构造函数(因此在调用main之前运行)和其他技巧将代码插入到进程中。所以我肯定会检查你的代码现在就是这种情况但更重要的是以后当你添加第三方库到你的代码时检查它