【问题标题】:glibc detected : double free or corruptionglibc 检测到:双重释放或损坏
【发布时间】:2013-06-27 12:57:55
【问题描述】:

我将解释我已完成的简短编码步骤以及我面临问题的区域

main.cpp

int main()
{
    int cnt_map,i=1,value;

   /* My question is about this char pointer "key" */ 
    char *key =(char*)malloc(sizeof(char) * 25);

   if(key!=NULL)
   {
     printf("Key value is not NULL,its value is:%x\n",key) ;
     cout<< "Enter the number of elements required in container map"<<endl;
     cin >> cnt_map;
     for (i=1;i<=cnt_map;i++)
     {
       cout << "Enter the key : ";
       cin >>key;
       cout << "Enter the key value:" ;
       cin >>value;
       printf("value pointed by ptr key: %s, value in ptr: %x\n", key,key);
       c -> add_map1(key,value); //Function inserts value to map container
       key+=sizeof(key);
     }
     c -> size_map1();           //Function displays size of map container
     c -> display_map1();        //Function displays contents of map container
  if(key)
  {
    printf("FINALLY:value pointed by ptr key: %s, value in ptr: %x,size:%d\n",key, key, sizeof(key));
    free(key);
  } 
 }
return 0;
}

在尝试编译和运行上述代码时,我能够成功编译代码,但在尝试运行应用程序时出现“检测到 glibc:双重释放或损坏”。

现在我的问题是我创建了一个字符指针(char *key =(char*)malloc(sizeof(char) * 25);) 并使用 malloc 成功为其分配了内存。在我尝试释放该 char 指针时完成我的过程后,我得到双重释放或损坏错误。我了解到任何使用 malloc/calloc 分配内存的变量最终都应该被释放。请告诉我为什么会出现这个错误,为什么我不应该这样做?请告诉我char* key 上的内存操作是如何进行的(如果可能的话,以图片形式)。

注意:上面显示的代码不是完整的代码,我只是解释了问题出在哪里,如果我没有释放指针变量,我的应用程序运行成功。

【问题讨论】:

  • 您可以随时使用valgrind 来调试所有这些内存错误。它丢失的很少,输出可读。

标签: c++


【解决方案1】:

通过这样做:

key+=sizeof(key);

您的key 变量不再指向您分配的内存的开头。您必须将原始指针传递给free()。您需要将原始指针存储在另一个变量中,以便在末尾正确地free()

(您可以简单地删除该行 - 我不确定它在做什么,因为 sizeof(key) 是 4 或 8。我怀疑它是多余的。)

【讨论】:

  • 一开始似乎没有任何理由增加key
  • 那么使用这个key+=sizeof(key); 分配的所有内存位置怎么样。如何释放所有位置?如果我们不释放这些位置会发生什么?为什么我的应用程序在我不使用 free() 时执行成功?
  • @ybc:每次调用malloc,您都会分配一个内存块。无论您如何使用该内存,您只需要对free 进行一次相应的调用。您的应用程序正在运行,因为没有绝对需要释放内存 - 在您的情况下,当进程终止时,内存将返回给操作系统。但是如果你循环运行这段代码,数百万次,你的进程最终会耗尽内存。
  • @RichieHindle 没错!这就是发生的事情..当我重新运行应用程序时,我发现内存开始分配在以前的相同位置。感谢您的出色分析。无论如何,我需要的迭代次数非常少在我的情况下,但是,还有一个问题我们需要在什么样的情况下释放分配的内存..我想与您提供的解释相反(如果可能的话,一个用例)。
  • @ybc:我想不出没有调用free 会导致代码失败的情况,除了内存不足。但这是非常糟糕的做法,没有人会推荐它。 (在您的示例中,您可以只使用一个普通的旧数组char key[25];,在这种情况下根本不需要调用free,就像您不为cnt_map 或@ 调用free 一样987654335@.
【解决方案2】:

那是因为这条线:key+=sizeof(key);key 不包含与 malloc 返回的地址相同的地址。

例如:

char *key =(char*)malloc(sizeof(char) * 25);

假设 malloc 返回地址20000(完全愚蠢的地址,仅用于示例)。

现在你在做key+=sizeof(key);,所以key = 20000 + 4 = 20004。问题是你试图释放key,它指向地址20004而不是20000。

为了解决这个问题,试试这个:

int main()
{
    int cnt_map,i=1,value;
    char *key_save;

   /* My question is about this char pointer "key" */ 
    char *key =(char*)malloc(sizeof(char) * 25);

    key_save = key;
   if(key!=NULL)
   {
     printf("Key value is not NULL,its value is:%x\n",key) ;
     cout<< "Enter the number of elements required in container map"<<endl;
     cin >> cnt_map;
     for (i=1;i<=cnt_map;i++)
     {
       cout << "Enter the key : ";
       cin >>key;
       cout << "Enter the key value:" ;
       cin >>value;
       printf("value pointed by ptr key: %s, value in ptr: %x\n", key,key);
       c -> add_map1(key,value); //Function inserts value to map container
       key+=sizeof(key);
     }
     c -> size_map1();           //Function displays size of map container
     c -> display_map1();        //Function displays contents of map container
  if(key)
  {
    printf("FINALLY:value pointed by ptr key: %s, value in ptr: %x,size:%d\n",key, key, sizeof(key));
    free(key_save);
  } 
 }
return 0;
}

【讨论】:

  • 如果你free(key)(用好地址),所有分配给key的内存空间都会被解放出来(包括地址“20004”so上的字节)
  • “修复”是错误的,因为递增键是错误的......请在此处查看其他答案和 cmets。
  • @JimBalter 那不是我的问题。问题是:为什么会出现内存损坏?,我只是回答这一点,我不是来查看所有代码的。
【解决方案3】:

只需删除该行:

key+=sizeof(key);

key 不是指向字符串数组的指针,而是指向单个字符串的指针。每次增加它时,都会减少字符串中的可用空间。第一次读取密钥时,有 25 个字节可用。下一次,您将 key 增加了 4 或 8 个字节,但分配空间的末尾没有改变,所以现在只有 21 或 17 个字节可用。第三次只有 17 或 9 个字节,以此类推。几次迭代后,您将在分配的内存块末尾增加key,它将开始写入未分配的内存(或分配给其他数据结构的内存)。这是未定义的行为,很可能会导致您的程序出现不可预知的故障。

由于您使用的是 C++,因此您应该使用 std::string 而不是 char[] 来表示字符串,并使用 std::vector 而不是普通数组。这些数据结构会根据需要自动扩展,因此您可以避免像这样的缓冲区溢出。

【讨论】:

    【解决方案4】:

    这没有考虑您的代码,但我在 Reader writer 问题(操作系统)http://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem 中遇到了同样的问题。

    这是由于文件指针是全局的,所以每当任何读取器尝试读取并且在 b/w 中另一个读取器读取并关闭文件指针时,当另一个尚未完成读取的读取器尝试在读取后关闭文件指针时。所以发生的事情是文件指针已经关闭它没有指向任何文件。 我使用的解决方案。 我没有将文件指针声明为全局文件,而是将它声明为读取器函数的本地文件,否则您可以检查文件指针是否为 NULL,如果为 NULL,则不要关闭文件指针。

    #include<stdio.h>
    #include<semaphore.h>
    #include<pthread.h>
    #include<string.h>
    #include<stdlib.h>
    sem_t x,wsem;
    int rc=0;
    char ch;
    char str[20];
    void *reader(void *);
    void *writer(void *);
    
    
    int main()
    {
     int nw,nr,i=0,j=0;
     pthread_t w[10],r[10];
     sem_init(&x,0,1);
     sem_init(&wsem,0,1);
     rc=0;
     printf("Enter the no of readers:");
     scanf("%d",&nr);
     printf("Enter the no of writers");
     scanf("%d",&nw);
     while(i<nw || j<nr) 
     {
    
      if(i<nw)
      {
    pthread_create(&w[i],NULL,writer,(void *)i);
    
    i++;
      }
      if(j<nr)
      {
    pthread_create(&r[j],NULL,reader,(void *)j);
    
        j++;
      }
     }
     for(i=0;i<nw;i++)
     {
    pthread_join(w[i],NULL); 
     }
     for(j=0;j<nr;j++)
     {
    pthread_join(r[j],NULL);
     }
    
     return 0;
    }
    
    void *reader(void *arg)
    {
     FILE *fptr;
     sem_wait(&x);
     rc++;
     if(rc==1)
      sem_wait(&wsem);
     sem_post(&x);
    
     printf("\nreader %d:",arg);
     fptr=fopen("temp.txt","r+");
     while(fgets(str,10,fptr)!=NULL)
     {
      printf("%s",str);
     }
     printf("\n");
     fclose(fptr);
     sem_wait(&x);
     rc--;
     if(rc==0)
        sem_post(&wsem);
     sem_post(&x);
    }
    
    
    void *writer(void *arg)
    {
     FILE *fptr1;
     sem_wait(&wsem);  
     printf("\nwriter-%d:\n",arg);
     fptr1=fopen("temp.txt","a+");
     printf("enter the string:");
     scanf("%s",str);
     fputs(str,fptr1);
     fclose(fptr1);  
     sem_post(&wsem);
    }
    

    【讨论】:

      猜你喜欢
      • 2012-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多