此函数中缺少 free() 导致内存泄漏
Memory leak from lack of free() in this function
以下代码用于在 c
中查找基本 shell 的可执行文件的路径。如您所见,我动态分配 path
变量,然后检查路径是否存在(通过辅助函数 cmd_exists
中的 lstat
)。然后我 return 路径变量。我的问题是,这会导致内存泄漏,因为 path
永远不会被释放。在我 return 它的值之前我无法释放路径,截至目前我想不出任何方法来释放已分配的内存。如果有人可以帮助我,我将不胜感激。谢谢
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;
}
您可以要求调用方释放内存:
// in caller
char * s = find_path("/mypath", "command");
// do something about `s`
free(s);
这确实是 C 的问题之一。内存所有权可能非常困难,因为 C++ 中没有 RAII 概念(本质上,没有自动析构函数)。
我看到 3 个解决方案:
- 3 中最糟糕的解决方案是拥有一个全局静态缓冲区,让您的 find_path 函数填充此缓冲区,并 return 将指向它的指针指向调用者。这个技巧被很多其他标准的 C 函数使用,但是它也有很多问题(通常不是线程安全的,如果它是线程安全的,那么下一次调用可能会覆盖之前的 return 值).请参阅 https://en.cppreference.com/w/cpp/utility/program/getenv 了解具有此行为的函数(查看顶部的警告)。
- 稍微好一点的解决方案是记录函数的 return 值,并清楚地告诉调用者释放 returned 指针是他的责任。如果他不这样做,你就会发生内存泄漏。有关使用此行为的函数,请参阅 https://en.cppreference.com/w/c/experimental/dynamic/strdup。
- 另一种解决方案是让调用者将最大大小的缓冲区传递给您的函数。因此,不是 returning
char *
,而是添加 char *
和 size_t
参数(size_t
以字符表示 char *
缓冲区的大小) .然后你的 find_path 函数可以填充这个缓冲区。有关具有此行为的函数,请参阅 https://en.cppreference.com/w/cpp/string/byte/strncpy。这种方法的问题是,如果缓冲区不够大,您的函数需要 return 失败,调用者必须传递更大的缓冲区。一些 Windows 函数通过让函数 return 设置 'expected' 缓冲区大小来解决这个问题,因此如果调用失败(因为缓冲区不够大),调用者可以使用 return 值来查看缓冲区应该有多大,并分配一个更大的缓冲区。
我的首选解决方案取决于实际情况。如果存在有意义的最大缓冲区大小(例如最大文件路径),我会采用第三种选择。我会采取第二种选择是最大缓冲区大小很难预测。无论如何,我永远不会使用第一种选择。
您需要在两个可能的地方使用 free
。
- 如果
cmd_exists
returns false,您需要释放路径。
- 如果
cmd_exists
returns 为真,您需要在调用方方法中有 free。
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);
以下代码用于在 c
中查找基本 shell 的可执行文件的路径。如您所见,我动态分配 path
变量,然后检查路径是否存在(通过辅助函数 cmd_exists
中的 lstat
)。然后我 return 路径变量。我的问题是,这会导致内存泄漏,因为 path
永远不会被释放。在我 return 它的值之前我无法释放路径,截至目前我想不出任何方法来释放已分配的内存。如果有人可以帮助我,我将不胜感激。谢谢
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;
}
您可以要求调用方释放内存:
// in caller
char * s = find_path("/mypath", "command");
// do something about `s`
free(s);
这确实是 C 的问题之一。内存所有权可能非常困难,因为 C++ 中没有 RAII 概念(本质上,没有自动析构函数)。
我看到 3 个解决方案:
- 3 中最糟糕的解决方案是拥有一个全局静态缓冲区,让您的 find_path 函数填充此缓冲区,并 return 将指向它的指针指向调用者。这个技巧被很多其他标准的 C 函数使用,但是它也有很多问题(通常不是线程安全的,如果它是线程安全的,那么下一次调用可能会覆盖之前的 return 值).请参阅 https://en.cppreference.com/w/cpp/utility/program/getenv 了解具有此行为的函数(查看顶部的警告)。
- 稍微好一点的解决方案是记录函数的 return 值,并清楚地告诉调用者释放 returned 指针是他的责任。如果他不这样做,你就会发生内存泄漏。有关使用此行为的函数,请参阅 https://en.cppreference.com/w/c/experimental/dynamic/strdup。
- 另一种解决方案是让调用者将最大大小的缓冲区传递给您的函数。因此,不是 returning
char *
,而是添加char *
和size_t
参数(size_t
以字符表示char *
缓冲区的大小) .然后你的 find_path 函数可以填充这个缓冲区。有关具有此行为的函数,请参阅 https://en.cppreference.com/w/cpp/string/byte/strncpy。这种方法的问题是,如果缓冲区不够大,您的函数需要 return 失败,调用者必须传递更大的缓冲区。一些 Windows 函数通过让函数 return 设置 'expected' 缓冲区大小来解决这个问题,因此如果调用失败(因为缓冲区不够大),调用者可以使用 return 值来查看缓冲区应该有多大,并分配一个更大的缓冲区。
我的首选解决方案取决于实际情况。如果存在有意义的最大缓冲区大小(例如最大文件路径),我会采用第三种选择。我会采取第二种选择是最大缓冲区大小很难预测。无论如何,我永远不会使用第一种选择。
您需要在两个可能的地方使用 free
。
- 如果
cmd_exists
returns false,您需要释放路径。 - 如果
cmd_exists
returns 为真,您需要在调用方方法中有 free。
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);