动态申请内存与释放时的异常---Byte越界(CheckBytes函数的内部机制)

本文详细介绍了在C++中使用宽字符进行内存申请时,遇到LoadLibrary函数异常的问题,以及如何通过多申请内存空间解决该问题。通过分析内存布局和CheckBytes函数的工作原理,解释了异常产生的原因,并提供了避免此类问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://blog.youkuaiyun.com/zp373860147/article/details/6992647

今天在堆代码的时候,堆了下面一段代码,Debug时异常,Release没问题。

[html]  view plain copy
  1. const std::string &sFilename;  
  2. wchar_t  *wcstring = (wchar_t *)malloc(sizeof(wchar_t)*(sFilename.length()-1));  
  3.   m_hDLL = ::LoadLibrary(/*stringToLPCWSTR(sFilename)*/stringToLPCWSTR(sFilename,wcstring));  
  4.   if (wcstring)  
  5.   {  
  6.       delete []wcstring;  
  7.   }  
  8.   wcstring = NULL;  
其实很简单,得到一个const std::string &类型的参数sFilename,想通过它来加载dll,但是::LoadLibrary的参数是LPCWSTR类型,就自己写个函数

[html]  view plain copy
  1. LPCWSTR stringToLPCWSTR(std::string orig, wchar_t * wcstring)  

来转换一下。

然后就在转换前动态申请了内存,并在使用后释放,如下:

[html]  view plain copy
  1. wchar_t  *wcstring = (wchar_t *)malloc(sizeof(wchar_t)*(sFilename.length()-1));  
  2. .......................................  
  3.   if (wcstring)  
  4.   {  
  5.       delete []wcstring;  
  6.   }  
  7.   wcstring = NULL;  
看起来貌似没问题,但是Debug异常了,问题出在delete []wcstring;这句,果断跟进去,最后跟进n层后定位到下面这个函数

[html]  view plain copy
  1. extern "C" static int __cdecl CheckBytes(  
  2.         unsigned char * pb,  
  3.         unsigned char bCheck,  
  4.         size_t nSize  
  5.         )  
  6. {  
  7.         int bOkay = TRUE;  
  8.         while (nSize--)  
  9.         {  
  10.             if (*pb++ != bCheck)  
  11.             {  
  12. /* Internal error report is just noise; calling functions all report results - JWM */  
  13. /*                _RPT3(_CRT_WARN, "memory check error at 0x%p = 0x%02X, should be 0x%02X.\n", */  
  14. /*                    (BYTE *)(pb-1),*(pb-1), bCheck); */  
  15.                 bOkay = FALSE;  
  16.             }  
  17.         }  
  18.         return bOkay;  
  19. }  

这个函数的作用是检查指定范围内的Byte是否被更改,如果被更改,返回false,如果未更改,返回true;

第一个参数是一个指针,第二个参数是用来进行比较的值,第三个参数是从指定位置(第一个指针表示)起,检测的位数。调试发现,bCheck为253,对应16进制为fd,nSize为4,下面查看内存,如图:

可以看到第一行中连续6个ab的前面有3个连续的00 ,其中第一个00是与其左边的6e共同组成一个Unicode宽字符,对应字符n,后两个连续的00组成宽字符\0,也就是从这个位置开始,CheckByte函数开始向后检测4位,看其是否是fd,由图可知,显然不是,所以返回false,抛出异常


下面,如果我申请的内存这么写:

[html]  view plain copy
  1. wchar_t  *wcstring = (wchar_t *)malloc(sizeof(wchar_t)*(sFilename.length()-1)<span style="color:#FF0000;">+2</span>);  
即多申请两个字节,内存图如下:

可以看到连续的00后只有2个fd,调试仍然失败


下面,多申请4个字节:

[html]  view plain copy
  1. wchar_t  *wcstring = (wchar_t *)malloc(sizeof(wchar_t)*(sFilename.length()-1)<span style="color:#FF0000;">+4</span>);  

可以看到现在内存中连续的00后有了四个fd,调试不再抛异常。

最后,在以上三种情况下,通过查看CheckByte的第一个参数pb发现,pb总是我们申请的内存空间的末尾位置向前移动2个字节(如果算上编译器自动加上的用于存放\0的2个字节,那就是向前移动4个字节)。也就是说,如果我们申请的内存不足够大,那么编译器将无法在其末尾找到连续4个fd,他就会认为内存越界而异常。


经验就是,在使用宽字符的时候多申请一些空间,最小也得多申请4个。

char的时候没试验,应该也是同样的道理。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值