该函数缺少free()导致内存泄漏

时间:2019-02-28 07:14:54

标签: c free dynamic-memory-allocation

以下代码用于在c中查找基本shell的可执行文件的路径。如您所见,我动态分配了path变量,然后检查路径是否存在(通过辅助函数lstat中的cmd_exists)。然后,我返回path变量。我的问题是,这将导致内存泄漏,因为path从未释放。在返回值之前,我无法释放路径,截至目前,我还没有想到释放已分配内存的任何方法。如果有人可以帮助我,我将不胜感激。谢谢

char * find_path(char * mypath, char * command){
     char * token = strtok(mypath, "#");
     while(token != NULL){
                         /*token size + 1 (for /) + command size*/
          char * path = calloc(strlen(token)+1+strlen(command)+1, sizeof(char));
          strcat(path, token);
          strcat(path, "/");
          strcat(path, command);
          if(cmd_exists(path) == 1){
             return path;
          }
          token = strtok(NULL, "#");
     }
     return NULL;
}

3 个答案:

答案 0 :(得分:4)

这确实是C的问题之一。内存所有权可能非常困难,因为C ++中没有RAII概念(本质上没有自动析构函数)。

我看到3种解决方案:

  • 3中最糟糕的解决方案是拥有一个全局静态缓冲区,并让您的find_path函数填充此缓冲区,然后将指向它的指针返回给调用方。此技巧已由其他许多标准C函数使用,但与此同时还有很多问题(通常不是线程安全的,并且如果是线程安全的,则下一次调用可能会覆盖先前的返回值)。有关具有此行为的函数,请参见https://en.cppreference.com/w/cpp/utility/program/getenv(请参阅顶部的警告)。
  • 一个更好的解决方案是记录函数的返回值,并明确告知调用者释放返回的指针是HIS的责任。如果他不这样做,您会遇到内存泄漏。有关使用此行为的函数,请参见https://en.cppreference.com/w/c/experimental/dynamic/strdup
  • 另一种解决方案是让调用者将缓冲区传递给最大大小的函数。因此,您无需添加char *,而是添加char *size_t自变量(size_t指示char *缓冲区的大小(以字符为单位)。然后,您的find_path函数可以填充此缓冲区。有关此行为的功能,请参见https://en.cppreference.com/w/cpp/string/byte/strncpy。这种方法的问题在于,如果缓冲区不够大,则您的函数需要返回失败,并且调用方必须传递更大的缓冲区。某些Windows函数通过使函数返回“预期的”缓冲区大小来解决此问题,因此,如果调用失败(因为缓冲区不够大),则调用者可以使用返回值查看缓冲区应该有多大,并分配更大的缓冲区。

我的首选解决方案取决于实际情况。如果存在有意义的最大缓冲区大小(例如最大文件路径),我将采用第三种选择。我会采取的第二种选择是最大的缓冲区大小很难预测。无论如何,我永远不会使用第一种选择。

答案 1 :(得分:2)

您需要在两个可能的位置放置free

  1. 如果cmd_exists返回false,则需要释放路径。
  2. 如果cmd_exists返回true,则您需要在调用者方法中具有空位。

1。

 while(token != NULL){
                     /*token size + 1 (for /) + command size*/
      char * path = calloc(strlen(token)+1+strlen(command)+1, sizeof(char));
      strcat(path, token);
      strcat(path, "/");
      strcat(path, command);
      if(cmd_exists(path) == 1){
         return path;
      }

      free(path);   // 1. Here

      token = strtok(NULL, "#");
 }
 return NULL;

2。

 char *temp = find_path(...);
  .....//do your stuff
  if (temp) free(temp);

答案 2 :(得分:0)

您可以要求呼叫者释放内存:

// in caller
char * s = find_path("/mypath", "command");
// do something about `s`
free(s);