Chinaunix首页 | 论坛 | 博客
  • 博客访问: 329495
  • 博文数量: 57
  • 博客积分: 146
  • 博客等级: 入伍新兵
  • 技术积分: 769
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-29 14:57
文章分类
文章存档

2014年(39)

2013年(13)

2012年(5)

我的朋友

分类: C/C++

2014-07-11 14:18:14

从写代码上看,内存管理包括内存分配、内存读写、内存释放。内存管理设计不当,会导致堆缓冲溢出、悬空指针(指向一块已经删除了的内存的指针)、double free等问题。

1.MALLOC和RECALLOC内存分配不会初始化内存数据
调用malloc函数成功后,其分配的内存的数据没有初始化,未知数据。calloc函数调用后,新分配的内存空间也是没有初始化,其行为和malloc一样。因此调用上述函数后,最好初始化内存数据。
上述问题不会影响calloc函数,它调用后就会把内存数据初始化为0x00.

问题代码:

点击(此处)折叠或打开

  1. char *buf = malloc(MAX_BUF_SIZE);
  2. if (buf == NULL) {
  3. /* Handle Allocation Error */
  4. }
  5. strcpy(buf, str);
  6. /* process buf */
  7. free(buf)
若str的长度小于MAX_BUF_SIZE,buf里的数据就是str+未初始化的位置数据。

正确代码:进行初始化操作

点击(此处)折叠或打开

  1. char *buf = malloc(MAX_BUF_SIZE);
  2. if (buf == NULL) {
  3. /* Handle Allocation Error */
  4. }
  5. memset(buf,'\0', MAX_BUF_SIZE); /* Initialize memory to default value */
  6. strcpy(buf, str);
  7. /* process buf */
  8. free(buf)

2.内存资源的分配操作和释放操作最好在同一代码块或同一抽象层内
分配和释放在不同的模块或抽象层内,会加大程序员追踪内存块生命周期的负担。若某个内存块已经分配或已经释放的话,会导致double-free、访问已释放内存资源、写未分配的内存资源等问题。

错误代码:

点击(此处)折叠或打开

  1. int verify_size(char *list, size_t list_size) {
  2.     if (size < MIN_SIZE_ALLOWED) {
  3.         /* Handle Error Condition */
  4.         free(list);
  5.         return -1;
  6.     }
  7.     return 0;
  8. }
  9. void process_list(size_t number) {
  10.     char *list = malloc(number);
  11.     if (list == NULL) {
  12.         /* Handle Allocation Error */
  13.     }
  14.     if (verify_size(list, number) == -1) {
  15.         /* Handle Error */
  16.     }
  17.     /* Continue Processing list */
  18.     free(list);
  19. }
上面代码可能会产生double-free问题。

正确代码:

点击(此处)折叠或打开

  1. int verify_size(char *list, size_t list_size) {
  2.     if (size < MIN_SIZE_ALLOWED) {
  3.         /* Handle Error Condition */
  4.         return -1;
  5.     }
  6.     return 0;
  7. }
  8. void process_list(size_t number) {
  9.     char *list = malloc(number);
  10.     if (list == NULL) {
  11.         /* Handle Allocation Error */
  12.     }
  13.     if (verify_size(list, number) == -1) {
  14.         /* Handle Error */
  15.     }
  16.     /* Continue Processing list */
  17.     free(list);
  18. }

3.free(P)后,记得设置P=NULL。因为free(p)后p的值还是等于该内存块地址,这样会导致double-freee等一系列问题。


错误代码:指针message可能存在double-free的问题

点击(此处)折叠或打开

  1. if (message_type == value_1) {
  2.     /* Process message type 1 */
  3.     free(message);
  4. }
  5. /* ...*/
  6. if (message_type == value_2) {
  7.     /* Process message type 2 */
  8.     free(message);
  9. }
正确代码:free(NULL)是允许的。

点击(此处)折叠或打开

  1. if (message_type == value_1) {
  2.     /* Process message type 1 */
  3.     free(message);
  4.     message = NULL;
  5. }
  6. /* ...*/
  7. if (message_type == value_2) {
  8.     /* Process message type 2 */
  9.     free(message);
  10.     message = NULL;
  11. }


四.申请分配0字节的内存空间其结果依赖于实现。
C99规定若申请的大小为0,其行为依赖于实现;可能是返回值为NULL,也有可能返回值为非零值,其值不能用来访问对象。

1.MALLOC函数
错误代码:

点击(此处)折叠或打开

  1. list = malloc(size);
  2. if (list == NULL) {
  3. /* Handle Allocation Error */
  4. }
  5. /* Continue Processing list */
若size等于0,list的值不等于NULL,会导致堆溢出错误。

正确代码:

点击(此处)折叠或打开

  1. if (size <= 0) {
  2. /* Handle Error */
  3. }
  4. list = malloc(size);
  5. if (list == NULL) {
  6. /* Handle Allocation Error */
  7. }
  8. /* Continue Processing list */

2.Realloc函数
若申请新内存区域成功后,会释放原始内存区域。若释放原始内存失败,realloc返回值为NULL。若realloc的size参数为0,realloc会返回一个NULL指针。


错误代码:

点击(此处)折叠或打开

  1. char *p2;
  2. char *p = malloc(100);
  3. /* ... */
  4. if ((p2 = realloc(p, nsize)) == NULL) {
  5. free(p);
  6. p = NULL;
  7. return NULL;
  8. }
  9. p = p2
若nsize等于0,realloc申请成功会释放p的资源,然后返回一个NULL指针,然后再free(p)会导致double-free的错误。

正确代码:

点击(此处)折叠或打开

  1. char *p2;
  2. char *p = malloc(100);
  3. /* ... */
  4. if ( (nsize == 0) || (p2 = realloc(p, nsize)) == NULL) {
  5. free(p);
  6. p = NULL;
  7. return NULL;
  8. }
  9. p = p2

五.别使用自定义函数来作为内分分配函数的参数
若自定义函数返回的值过大或为0,将导致程序行为无法预测或堆溢出等。

错误代码:

点击(此处)折叠或打开

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #define MAXLINE 1000
  4. size_t calc() {
  5. char line[MAXLINE], c;
  6. size_t size = 0;
  7. while ( (c = getchar()) != EOF && c != '\n') {
  8. line[size] = c;
  9. size++;
  10. if (size >= MAXLINE)
  11. break;
  12. }
  13. return size;
  14. }
  15. int main(void) {
  16. char * line = malloc(calc());
  17. if (NULL != line){
  18.     memcpy(line, xxxx, ....);
  19. }
  20. }
若calc()函数返回0,line不会NULL,会导致堆溢出错误。

正确代码:

点击(此处)折叠或打开

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #define MAXLINE 1000
  4. size_t calc() {
  5. char line[MAXLINE], c;
  6. size_t size = 0;
  7. while ( (c = getchar()) != EOF && c != '\n') {
  8. line[size] = c;
  9. size++;
  10. if (size >= MAXLINE)
  11. break;
  12. }
  13. return size;
  14. }
  15. int main(void) {
  16. size_t size = calc();
  17. if (size > 0) {
  18. char * line = malloc(size)
  19. if (NULL != line){
  20.     memcpy(line, xxxx, ....);
  21. }
  22. }
  23. }

六.确保calloc函数的size参数不会发生整型溢出

点击(此处)折叠或打开

  1. void calloc(size_t nmemb, size_t size)
确保nmemb*size其大小范围在size_t内,否则会导致溢出。









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