Chinaunix首页 | 论坛 | 博客
  • 博客访问: 8130837
  • 博文数量: 159
  • 博客积分: 10424
  • 博客等级: 少将
  • 技术积分: 14615
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-14 12:45
个人简介

啦啦啦~~~

文章分类
文章存档

2015年(5)

2014年(1)

2013年(5)

2012年(10)

2011年(116)

2010年(22)

分类: C/C++

2011-06-13 23:09:35

本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
    

在良好的代码风格中,其中有一项要求就是,一个函数只做一件事情。如果该函数实现了多个功能,那基本上可以说这不是一个设计良好的函数。

今天看C库中的函数realloc。其原型是void *realloc(void *ptr, size_t size);函数说明如下:
realloc() changes the size of the memory block pointed to by ptr to size bytes. The contents will be unchanged to the minimum of the old and new sizes; newly allocated memory will be uninitialized. If ptr is NULL, the call is equivalent to malloc(size); if sizeis equal to zero, the call is equivalent to free(ptr). Unless ptr is NULL, it must have been returned by an earlier call to malloc(), calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done.

总结一下,有以下几种行为:
1. 与名字相符,真正的realloc,参数ptr和size均不为NULL,重新调整内存大小,并将新的内存指针返回,并保证最小的size的内容不变;
2. 参数ptr为NULL,但size不为0,那么行为就等于malloc(size);
3. 参数size为0,则realloc的行为为free(ptr);这时原有的指针已经被free掉,不能继续使用。而此时realloc的返回值为NULL。这意味着不检查realloc的返回值,直接使用,会导致crash。

看,一个简单C库函数,却赋予了三种行为,所以这个realloc并不是设计良好的库函数。估计也是为了兼容性,才容忍这个函数一直在C库中。虽然在编码中,realloc会提供一定的方便,但是也很容易引发bug。

下面就举两个例子,来说明一下。
1. realloc第一种行为引发的bug
  1. void *ptr = realloc(ptr, new_size);
  2. if (!ptr) {
  3.     错误处理
  4. }
这里就引出了一个内存泄露的问题,当realloc分配失败的时候,会返回NULL。但是参数中的ptr的内存是没有被释放的。如果直接将realloc的返回值赋给ptr。那么当申请内存失败时,就会造成ptr原来指向的内存丢失,造成泄露。

正确的处理应该是这样
  1. void *new_ptr = realloc(ptr, new_size);
  2. if (!new_ptr) {
  3.     错误处理。
  4. }
  5. ptr = new_ptr

2. 第三种行为引发的bug
这种bug由一种不好的编程习惯引发的。即认为申请内存始终可以成功,因此并不检查malloc的返回值。这在一般情况下,不会引发问题。但是对于realloc来说,当new_size为0时,realloc返回NULL。而在后面的代码上,继续使用new_ptr,比如会导致程序crash。
  1. void *new_ptr = realloc(old_ptr, new_size);
 //其它代码
 ...... ......

从上面可以看出,在面对这个设计并非良好的API时,我们需要小心小心再小心。上面只是举了两个例子,其实还有一些其它的小问题。


阅读(17582) | 评论(14) | 转发(7) |
给主人留下些什么吧!~~

GFree_Wind2012-06-28 10:06:45

Bean_lee: 呵呵,写这种服务器长期运行的程序一定要小心。最近遇到了realloc相关的bug,首先想到了你的博文。和同事share之前,先测试了一把,才发现这个问题。.....
我这个也是以前遇到项目中的代码,有使用realloc带来的种种问题。
其中一个就是提到的size为0的情况。

估计是写文章的时候,记错了size为0,如何引起的bug的。

Bean_lee2012-06-27 23:36:49

GFree_Wind: 这个是我想当然了。没有经过程序测试。

刚才试了一下,realloc在new_size等于0时,行为等于free。不过返回值为NULL。而free一个NULL指针,并不会出错。

多谢指.....
呵呵,写这种服务器长期运行的程序一定要小心。最近遇到了realloc相关的bug,首先想到了你的博文。和同事share之前,先测试了一把,才发现这个问题。

GFree_Wind2012-06-27 22:58:44

Bean_lee: void *new_ptr = realloc(old_ptr, new_size);
//其它代码
...... ......
free(new_ptr);
今天我实验了下,没什么问题啊,就算new_size等于0,也OK啊?
没有你.....
这个是我想当然了。没有经过程序测试。

刚才试了一下,realloc在new_size等于0时,行为等于free。不过返回值为NULL。而free一个NULL指针,并不会出错。

多谢指正呵。

Bean_lee2012-06-27 12:33:27

void *new_ptr = realloc(old_ptr, new_size);
//其它代码
...... ......
free(new_ptr);
今天我实验了下,没什么问题啊,就算new_size等于0,也OK啊?
没有你说的double free的问题啊。

zyd_cu2012-01-08 18:46:17

GFree_Wind: 当我以前发现realloc这个问题时,搜索我们的工程代码,会发现很多地方都有问题。只不过问题不容易暴露而已。.....
的确,realloc的使用不会很频繁,少量的内存泄露问题不太容易暴露。