昨天在写一段转换函数,遇到需要将一个字符串转换为另一个。在测试时,发现一个内存泄露的问题。
函数如下:
void Str2Str(void * des, void * src)
{
{
unsigned char *pDes = (unsigned char *)des;
unsigned char *pSrc = (unsigned char *)src;
unsigned char au8Int[4] = {0};
unsigned char u8Idx = 0;
if(dis == NULL || src == NULL)
return;
while(*pSrc != '\0')
{
while((*pSrc != '.') && (*pSrc != '\0'))
unsigned char au8Int[4] = {0};
unsigned char u8Idx = 0;
if(dis == NULL || src == NULL)
return;
while(*pSrc != '\0')
{
while((*pSrc != '.') && (*pSrc != '\0'))
{
au8Int[u8Idx] = au8Int[u8Idx] * 10 + (*pSrc & 0x0f);
au8Int[u8Idx] = au8Int[u8Idx] * 10 + (*pSrc & 0x0f);
src++;
}
u8Idx++;
pSrc++;
u8Idx++;
pSrc++;
}
sprintf(pDes, "%d.%d.%d.%d", au8Int[0], au8Int[1], au8Int[2], au8Int[3]);
}
运行完函数后,发现没有返回值。感觉哪里不对,于是使用gdb调试了一下,发现当程序运行到sprintf()语句时,pDes与des的值竟然不一致。按照指针传递理解,这里也是直接赋值,他们应该是一致的才对。但是确实不一致。也就是这样,这个sprintf()把值写到了其他地址中,以至于传入的指针指向的地址没有数据写入,没有带回数据。
发现这个问题后,一直想不通,为什么会这样。当时还没有想到是内存溢出的问题。只知道,在后来的语句中,pDes的值发生了变化。
今天在和同事聊起来的时候,同事也想不明白。这种情况是不应该的。后来在提到,经过一个while后pDes的值发生了变化。同事提到会不会是在while()处内存泄露,导致里边的值发生了变化。这个提醒,点醒了我。
之后,把while()部分去掉,在测试,发现有值。虽然都是零,但是证明了问题确实出在这里。
然后检查这段代码,发现在内层while()退出后,pSrc又加了一次,这个造成了pSrc指向的地址越过了字符串的结尾,指向了未知的内存空间,而那个地方恰好有值,就造成了外层while()没有退出,一直再循环。于是pSrc访问的内存,超过了字符串的内存。同时,由于u8Idx也加1,造成了au8Int[]越界访问,指向了&pDes所在的内存,所以pDes的内容也因为此遭到修改。
(gdb) p &pDes
$2 = (unsigned char **) 0xbffff414
$2 = (unsigned char **) 0xbffff414
(gdb) p &au8Int
$4 = (unsigned char (*)[4]) 0xbffff410
$4 = (unsigned char (*)[4]) 0xbffff410
(gdb) p &au8Int[4]
$5 = (unsigned char *) 0xbffff414 "L����\206\004\b"
这里问题就在于当访问到字符串的结尾时,没有及时退出造成了最后的问题。
$5 = (unsigned char *) 0xbffff414 "L����\206\004\b"
这里问题就在于当访问到字符串的结尾时,没有及时退出造成了最后的问题。
修改后的函数如下:
void Str2Str(void * des, void * src)
{
{
unsigned char *pDes = (unsigned char *)des;
unsigned char *pSrc = (unsigned char *)src;
unsigned char au8Int[4] = {0};
unsigned char u8Idx = 0;
if(dis == NULL || src == NULL)
return;
while(*pSrc != '\0')
{
while((*pSrc != '.') && (* != '\0'))
unsigned char au8Int[4] = {0};
unsigned char u8Idx = 0;
if(dis == NULL || src == NULL)
return;
while(*pSrc != '\0')
{
while((*pSrc != '.') && (* != '\0'))
{
au8Int[u8Idx] = au8Int[u8Idx] * 10 + (*pSrc & 0x0f);
au8Int[u8Idx] = au8Int[u8Idx] * 10 + (*pSrc & 0x0f);
src++;
}
if(*pSrc == '\0')
break;
u8Idx++;
pSrc++;
}
sprintf(pDes, "%d.%d.%d.%d", au8Int[0], au8Int[1], au8Int[2], au8Int[3]);
}
避免pSrc,和au8Int的越界访问。