VC6调试版本C运行库内存申请的一个bug

VC调试版本C运行库内存申请的一个bug

 

 

遇到过一个通信方面的软件,需要长期运行,做压力测试时,高负荷连续运行一定天数时必定崩溃,而且都是在msvcrtd.dll中崩溃。负责维护的人百思不得其解,就去问微软的人,结果微软的人说这是VC6带的msvcrtd.dll的一个问题,VC2005已经没有这个问题了,请升级到新的版本。这个软件规模比较大,依赖于很多库,后台都是用VC6编译的调试版本,为了方便定位问题,没有Release版本。升级到VC2005后会不会出现别的问题,没有人敢冒这个风险,于是没有使用VC2005

 

闲着没事的时候分析了一下,才发现问题其实很简单。msvcrtd.dll对每次内存申请都进行计数,当计数值达到设定的某个值时,就会调用_CrtDbgBreak()MSDN_CrtDbgBreak的说明是:Sets a break point on a particular line of code,其实_CrtDbgBreakX86下只有一条指令就是int 3(0xCC)

dbgheap.c中定义了下面两个变量:

static long _lRequestCurr = 1;      /* Current request number */

extern "C" _CRTIMP long _crtBreakAlloc = -1L;  /* Break on allocation by request number */

_lRequestCurr表示当前的申请次数,_crtBreakAlloc表示当内存申请次数达到某个值时break,即调用_CrtDbgBreak。详情可参考debugheap.c中的_heap_alloc_dbg_impl函数:

lRequest = _lRequestCurr;

/* break into debugger at specific memory allocation */

if (_crtBreakAlloc != -1L && lRequest == _crtBreakAlloc)

 _CrtDbgBreak();

VC6附带的dbgheap.c中没有添加_crtBreakAlloc != -1L的判断,而是:

if (lRequest == _crtBreakAlloc)

 _CrtDbgBreak();

_lRequestCurr初始化为1,每次申请内存都加1,当_lRequestCurr-1时在VC6dbgheap.c中就会触发int 3导致程序退出,而在新的版本中添加了_crtBreakAlloc != -1L的判断,所以默认的情况下是不会触发int 3 退出的。

可以通过调用_CrtSetBreakAlloc设置_crtBreakAlloc的值,当我们设置了新的_crtBreakAlloc,而且_crtBreakAlloc等于_lRequestCurr时就会触发int 3

 

弄清楚了问题的所在,我们就可以着手解决问题了。VC6dbgheap.c中有两个地方判断了lRequest 是否与_crtBreakAlloc相等,相等后执行指令int 3。我们不用复杂的处理,把int 3替换为nop0x90)指令即可。首先得到“if (_crtBreakAlloc != -1L && lRequest == _crtBreakAlloc) 对应的二进制指令,用UE打开msvcrtd.dll,使用16进制编辑模式,查找得到的二进制指令,发现确实只有二处,把紧接着它们的0xCC替换为0x90,问题解决。

 
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值