TinyXml Print 函数 Bug
2016-03-22 13:33
246 查看
最近做一个项目,用到了TinyXml操作XML,有一个地方需要用print函数把XML文本打印出来,代码如下:
程序结束时,我打算free掉m_pDbCfg->trees[m_pDbCfg->treeCount-1].cbuffer,问题来了,有时会崩溃,有时正常,真是让人觉得莫名其妙,找同事看了看,一开始在外边自己代码找问题,感觉TinyXml这个库辣么多人用,应该不会出问题嘛。但是,外边没找到问题,后来调试到Print函数里边,突然发现,realloc 存在问题,把代码贴出来,如下(代码太多就不全部贴出来了,能说明问题就行):
问题是什么呢?那就是realloc之后,指针的地址可能会发生变化,cbuffer = (char*)realloc(cbuffer, *size);也即是说,此时返回的cbuffer(局部变量)与实参不一致,至于原因可见realloc函数介绍,如下:
原型::void *realloc(void *mem_address, unsigned int newsize);
功能:先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域(注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。
所以,如果空间不够,那么m_pDbCfg->trees[m_pDbCfg->treeCount-1].cbuffer指针所指内容就是无效的,当我使用m_pDbCfg->trees[m_pDbCfg->treeCount-1].cbuffer去free时,程序就会崩溃。
解决:可以把print函数的参数cbuffer定义为指针的指针,或者指针的引用,这样,realloc产生的地址就能赋值给实参了,由于指针还要解引用,改动代码太多,本人将cbuffer改为指针的引用,问题成功解决。
感慨:这么成熟的一个库,都会出这样的问题,一定要敢于怀疑,大胆假设,小心求证。
m_pDbCfg->trees[m_pDbCfg->treeCount-1].cbuffer = (char*)malloc( MAX_BUFFERSIZE ); int idx = 0; int isize = MAX_BUFFERSIZE;//由于无法预计最大长度,<span style="font-family: Arial, Helvetica, sans-serif;">看了一下Print函数,打印时对长度做出了判断,当长度不够时,realloc了一个新的大小,便</span>将<span style="font-family: Arial, Helvetica, sans-serif;">MAX_BUFFERSIZE定义为512,</span> treeElement->Print( m_pDbCfg->trees[m_pDbCfg->treeCount-1].cbuffer, &idx, &isize, 0 );
程序结束时,我打算free掉m_pDbCfg->trees[m_pDbCfg->treeCount-1].cbuffer,问题来了,有时会崩溃,有时正常,真是让人觉得莫名其妙,找同事看了看,一开始在外边自己代码找问题,感觉TinyXml这个库辣么多人用,应该不会出问题嘛。但是,外边没找到问题,后来调试到Print函数里边,突然发现,realloc 存在问题,把代码贴出来,如下(代码太多就不全部贴出来了,能说明问题就行):
void TiXmlElement::Print( char* cbuffer, int *idx, int *size, int depth ) const { int i; for ( i=0; i<depth; i++ ) { sprintf( &cbuffer[*idx], " " ); *idx += strlen(" "); if(*idx > *size-128) { *size += 1024; cbuffer = (char *)realloc(cbuffer, *size); } }
<span style="font-family: Arial, Helvetica, sans-serif;">}</span>
问题是什么呢?那就是realloc之后,指针的地址可能会发生变化,cbuffer = (char*)realloc(cbuffer, *size);也即是说,此时返回的cbuffer(局部变量)与实参不一致,至于原因可见realloc函数介绍,如下:
原型::void *realloc(void *mem_address, unsigned int newsize);
功能:先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域(注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。
所以,如果空间不够,那么m_pDbCfg->trees[m_pDbCfg->treeCount-1].cbuffer指针所指内容就是无效的,当我使用m_pDbCfg->trees[m_pDbCfg->treeCount-1].cbuffer去free时,程序就会崩溃。
解决:可以把print函数的参数cbuffer定义为指针的指针,或者指针的引用,这样,realloc产生的地址就能赋值给实参了,由于指针还要解引用,改动代码太多,本人将cbuffer改为指针的引用,问题成功解决。
感慨:这么成熟的一个库,都会出这样的问题,一定要敢于怀疑,大胆假设,小心求证。
相关文章推荐
- iOS 图片左右反转 反向
- 移动web页面前端开发总结
- Qt5自带加密方法
- ftrace的使用【转】
- 检测数据库各实例session 阻塞 tree的sql
- 常用正则表达式整理
- Exchange 2013 证书配置
- LeetCode[258]——Add Digits
- 求素数
- 解引用和箭头操作符
- DM9000网卡的基本工作原理
- iOS 宏(define)与常量(const)的正确使用
- android 加载图片
- javascript知识结构
- OCX控件的简单开发实例
- C/C++—— 输入两点坐标(X1,Y1),(X2,Y2),计算并输出两点间的距离
- ES2015 - Object (6)
- 【redis】跟着redis tutorial的基本学习
- POJ 2553 The Bottom of a Graph TarJan算法题解
- PIC16F877A最小功能板 - 原理图系列