代码之家  ›  专栏  ›  技术社区  ›  danielschnoll

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

  •  0
  • danielschnoll  · 技术社区  · 6 年前

    下面的代码用于在 c . 如您所见,我动态地分配 path 变量,然后检查是否存在路径(通过) lstat 在辅助函数中 cmd_exists ). 然后返回path变量。我的问题是,这会导致内存泄漏 路径 从未被释放。在返回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;
    }
    
    1 回复  |  直到 6 年前
        1
  •  4
  •   Patrick    6 年前

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

    我看到了3种解决方法:

    • 3中最糟糕的解决方案是有一个全局静态缓冲区,让find_path函数填充这个缓冲区并将指向它的指针返回给调用者。这个技巧被其他一些标准的C函数使用,但是也有很多问题(通常不是线程安全的,如果是线程安全的,那么下一个调用可能会覆盖上一个返回值)。见 https://en.cppreference.com/w/cpp/utility/program/getenv 对于具有此行为的函数(请查看顶部的警告)。
    • 稍微好一点的解决方案是记录函数的返回值,并清楚地告诉调用者释放返回的指针是他的责任。如果他不告诉你,你的记忆就会泄露。见 https://en.cppreference.com/w/c/experimental/dynamic/strdup 对于使用此行为的函数。
    • 另一个解决方案是让调用方将缓冲区传递到具有最大大小的函数。所以不是返回 char * ,您添加 字符* size_t 论据( 尺寸 指示 字符* 字符缓冲区)。然后,find_path函数可以填充这个缓冲区。见 https://en.cppreference.com/w/cpp/string/byte/strncpy 对于具有此行为的函数。这种方法的问题是,如果缓冲区不够大,则函数需要返回一个错误,调用方必须传递一个较大的缓冲区。一些Windows函数通过让函数返回“预期”的缓冲区大小来解决这个问题,因此如果调用失败(因为缓冲区不够大),调用方可以使用返回值来查看缓冲区应该有多大,并分配一个更大的缓冲区。

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

        2
  •  2
  •   kiran Biradar    6 年前

    你需要有 free 在两个可能的地方。

    1. 如果你想 cmd_exists 返回false。
    2. 如果 CMDY-存在 返回true。

     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;
    

     char *temp = find_path(...);
      .....//do your stuff
      if (temp) free(temp);
    
        3
  •  0
  •   Ziming Song    6 年前

    您可以要求来电者释放内存:

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