重载new造成的BoundsChecker误报

原文链接:http://www.titilima.cn/?action=show&id=273

BoundsChecker是一个功能很强大的内存/资源泄漏检查工具,尤其是可以嵌入Visual Studio的环境中随着调试器一同运行,使用起来尤其方便。当程序退出后,BoundsChecker则会弹出一个视图,其中记录了代码中发生的内存泄漏。
不过,如果我们在代码中对内存分配做了特殊的处理,就有可能导致BoundsChecker的误报。考虑如下代码:

  1. #include <Windows.h>
  2.    
  3. void* operator new(size_t size)
  4. {
  5.     static BYTE pool[4096];
  6.     return pool;
  7. }
  8.    
  9. int main(void)
  10. {
  11.     int *p = new int[10];
  12.     return 0;
  13. }

在这个程序结束后,BoundsChecker就会报告有40字节的内存泄漏。很显然,事实上并非如此。
BoundsChecker的内存泄漏检查原理是挂钩了所有的内存/资源分配函数和销毁函数,当内存/资源分配时,则跳转到BoundsChecker自己的函数中,记录内存块的地址或资源句柄;当销毁内存/资源的时候,BoundsChecker则会删除对应的分配记录。这样一来,在程序退出后,仍然遗留下来的分配记录就是内存/资源的泄漏了。
对于上面的源代码,当启用BoundsChecker调试时,operator new的反汇编代码如下:

  1. 3:    void* operator new(size_t size)
  2. 4:    {
  3. 00401020   jmp 01172348
  4. 00401025   inc eax
  5. 00401026   pushebx
  6. 00401027   pushesi
  7. 00401028   pushedi
  8. 00401029   lea edi,[ebp-40h]
  9. 0040102C   mov ecx,10h
  10. 00401031   mov eax,0CCCCCCCCh
  11. 00401036   rep stosdword ptr [edi]
  12. 5:        static BYTE pool[4096];
  13. 6:        return pool;
  14. 00401038   mov eax,offset pool (00432a78)
  15. 7:    }
  16. 0040103D   pop edi
  17. 0040103E   pop esi
  18. 0040103F   pop ebx
  19. 00401040   mov esp,ebp
  20. 00401042   pop ebp
  21. 00401043   ret

如你所见,01172348这个地址就是BoundsChecker的内存统计函数了。也正因为BoundsChecker只是简单收集了内存块的大小而并没有关心程序员是如何实现内存分配的,所以这里的误报就在所难免了。其实在某种意义上来说,即使是使用了自己的内存池,如果分配完后不释放也可以算作内存泄漏——因为这个行为造成了内存池的浪费。
但是上面这种重载new倒是会造成类似Rational Purify的工具进行错误的内存统计,因为所有的内存都在内存池中一次性分配好了。
话又说回来——我为什么要故意和BoundsChecker对着干呢?

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值