当通过递归函数传递分配的数组时,内存泄漏
问题描述:
这是函数list_directory
,其中我丢失了分配的指针,之后我无法释放它。 这应该是一个类似于实现的方式,当它找到一个目录时,它应该保存它的名称,并且在列出该目录后,它应该递归地在当前目录中找到的目录上调用list_directory
。但由于某种原因,它在途中失去了一些元素。当通过递归函数传递分配的数组时,内存泄漏
int list_directory(int argc, char *argv[], struct check_info *chinfo, int dirs)
{
struct group *grp;
struct passwd *pwd;
struct stat file_info;
struct tm *mtime;
struct dirent *dir_info;
int subdirs = 0;
int printsubdir = 0;
int skip_newline = 1;
char timebuffer[26];
char **recursqueue;
if (chinfo->param_R)
{
if ((recursqueue = malloc(argc * sizeof(char*))) < 0)
perror("malloc");
}
if (dirs > -1)
{
for (int i = 0; i < chinfo->files; i++)
{
list_file(chinfo->argv_files[i], chinfo);
free(chinfo->argv_files[i]);
}
free(chinfo->argv_files);
}
for (int i = 1; i < argc; i++)
{
DIR *dp = opendir(argv[i]);
if (dp)
{
if (chinfo->param_R)
{
if ((recursqueue[subdirs] = malloc((256) * sizeof(char))) < 0)
perror("malloc");
strcpy(recursqueue[subdirs++], "./ls");
}
if (dirs+chinfo->files > 1 || chinfo->param_R)
{
if (!skip_newline || dirs == -1 || chinfo->files)
printf("\n%s:\n", argv[i]);
else
printf("%s:\n", argv[i]);
}
skip_newline = 0;
if (chinfo->param_l)
{
dir_indent_info(argv[i], chinfo);
printf("total %lu\n", chinfo->blocks_total/2);
}
while ((dir_info = readdir(dp)) != NULL)
{
if (!strcmp(".", dir_info->d_name) ||
!strcmp("..", dir_info->d_name))
{
continue;
}
else if (!strncmp(".", dir_info->d_name, 1)
&& !chinfo->param_A)
{
continue;
}
else
{
char path[strlen(argv[i]) + strlen(dir_info->d_name) + 1];
sprintf(path, "%s/%s", argv[i], dir_info->d_name);
if (lstat(path, &file_info) == -1)
continue;
switch (file_info.st_mode & S_IFMT)
{
case S_IFBLK: printf("b"); break;
case S_IFCHR: printf("c"); break;
case S_IFDIR: printf("d");
if (chinfo->param_R)
{
printsubdir = 1;
recursqueue[subdirs] = malloc((256) * sizeof(char));
strcpy(recursqueue[subdirs++], path);
}
break;
case S_IFIFO: printf("p"); break;
case S_IFLNK: printf("l"); break;
case S_IFREG: printf("-"); break;
case S_IFSOCK: printf("s"); break;
default: printf("?"); break;
}
if (chinfo->param_l)
{
printf((file_info.st_mode & S_IRUSR) ? "r" : "-");
printf((file_info.st_mode & S_IWUSR) ? "w" : "-");
printf((file_info.st_mode & S_IXUSR) ? "x" : "-");
printf((file_info.st_mode & S_IRGRP) ? "r" : "-");
printf((file_info.st_mode & S_IWGRP) ? "w" : "-");
printf((file_info.st_mode & S_IXGRP) ? "x" : "-");
printf((file_info.st_mode & S_IROTH) ? "r" : "-");
printf((file_info.st_mode & S_IWOTH) ? "w" : "-");
printf((file_info.st_mode & S_IXOTH) ? "x" : "-");
printf(" %*lu", numlen(chinfo->link_len), file_info.st_nlink);
pwd = getpwuid(file_info.st_uid);
printf(" %-*s", chinfo->usr_len, pwd->pw_name);
grp = getgrgid(file_info.st_gid);
printf(" %-*s", chinfo->grp_len, grp->gr_name);
printf(" %*lu", numlen(chinfo->size_len), file_info.st_size);
mtime = localtime(&file_info.st_mtime);
strftime(timebuffer, 26, "%b %e %R", mtime);
printf(" %s", timebuffer);
}
printf(" %s\n", dir_info->d_name);
}
}
if (printsubdir)
{
if((list_directory(subdirs, recursqueue, chinfo, -1)) < 0)
printsubdir = -1;
for (int i = 0; i < subdirs; i++)
{
free(recursqueue[i]);
}
if (printsubdir < 0)
return -1;
}
closedir (dp);
subdirs = 0;
}
}
if (chinfo->param_R)
free(recursqueue);
return 0;
}
我通过argv
到dir_indent_info
所以在这里它是:
int dir_indent_info(char* dirpath, struct check_info *chinfo)
{
struct dirent *dir_info;
struct stat file_info;
struct group *grp;
struct passwd *pwd;
reset_info(chinfo);
DIR *dp = opendir(dirpath);
if (dp)
{
while ((dir_info = readdir(dp)) != NULL)
{
if (!strcmp(".", dir_info->d_name) ||
!strcmp("..", dir_info->d_name))
{
continue;
}
char path[strlen(dir_info->d_name) + strlen(dirpath) + 1];
sprintf(path, "%s/%s", dirpath, dir_info->d_name);
if (lstat(path, &file_info) == -1)
{
perror("lstat()");
continue;
}
pwd = getpwuid(file_info.st_uid);
if (strlen(pwd->pw_name) > chinfo->usr_len)
chinfo->usr_len = strlen(pwd->pw_name);
grp = getgrgid(file_info.st_gid);
if (strlen(grp->gr_name) > chinfo->grp_len)
chinfo->grp_len = strlen(grp->gr_name);
chinfo->blocks_total += file_info.st_blocks;
if (file_info.st_size > chinfo->size_len)
chinfo->size_len = file_info.st_size;
if (file_info.st_nlink > chinfo->link_len)
chinfo->link_len = file_info.st_nlink;
}
closedir(dp);
}
else
{
perror("error");
return -1;
}
return 0;
}
Valgrind的输出:用于焦炭
==6361== WARNING: new redirection conflicts with existing -- ignoring it
--6361-- old: 0x0401cdc0 (strlen ) R-> (0000.0) 0x3809e181 ???
--6361-- new: 0x0401cdc0 (strlen ) R-> (2007.0) 0x04c31020 strlen
==6361==
==6361== HEAP SUMMARY:
==6361== in use at exit: 768 bytes in 3 blocks
==6361== total heap usage: 231 allocs, 228 frees, 596,108 bytes allocated
==6361==
==6361== Searching for pointers to 3 not-freed blocks
==6361== Checked 65,288 bytes
==6361==
==6361== 256 bytes in 1 blocks are definitely lost in loss record 1 of 2
==6361== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6361== by 0x4016FD: list_directory (ls.c:293)
==6361== by 0x401DFB: list_directory (ls.c:385)
==6361== by 0x401F55: main (ls.c:415)
==6361==
==6361== 512 bytes in 2 blocks are definitely lost in loss record 2 of 2
==6361== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6361== by 0x4016FD: list_directory (ls.c:293)
==6361== by 0x401DFB: list_directory (ls.c:385)
==6361== by 0x401DFB: list_directory (ls.c:385)
==6361== by 0x401F55: main (ls.c:415)
==6361==
==6361== LEAK SUMMARY:
==6361== definitely lost: 768 bytes in 3 blocks
==6361== indirectly lost: 0 bytes in 0 blocks
==6361== possibly lost: 0 bytes in 0 blocks
==6361== still reachable: 0 bytes in 0 blocks
==6361== suppressed: 0 bytes in 0 blocks
==6361==
==6361== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 1 from 1)
分配指针**阵列:
if (chinfo->param_R)
{
if ((recursqueue = malloc(argc * sizeof(char*))) < 0)
perror("malloc");
}
分配的第一要素和分配./ls它来模拟参数输入:如果当前文件是我们在recursqueue
case S_IFDIR: printf("d");
if (chinfo->param_R)
{
printsubdir = 1;
recursqueue[subdirs] = malloc((256) * sizeof(char));
strcpy(recursqueue[subdirs++], path);
}
添加一个目录调用具有相同功能的
if (chinfo->param_R)
{
if ((recursqueue[subdirs] = malloc((256) * sizeof(char))) < 0)
perror("malloc");
strcpy(recursqueue[subdirs++], "./ls");
}
收集到的子目录路径:
if (printsubdir)
{
if((list_directory(subdirs, recursqueue, chinfo, -1)) < 0)
printsubdir = -1;
for (int i = 0; i < subdirs; i++)
{
free(recursqueue[i]);
}
if (printsubdir < 0)
return -1;
}
答
你的代码有许多问题,如庞大的功能,未初始化变量,变量名时尚,再利用无关的目的变量,变量的不必要的广泛范围,模糊的所有权分配的内存,在条件表达式中的分配,小于0的指针比较等。
至于内存泄漏,它们很容易发生这样的代码,例如:
- 你分配的第一
recursqueue
项目为./ls
字符串,但如果printsubdir
未设置为1,那么它将永远不会被释放; - 您分配
recursqueue
数组,但如果list_directory
返回的值小于0,则它永远不会被释放(并且也不会调用closedir
);
+0
我发现我的错误,但感谢您的答案,并指出在这个混乱中必须改进的东西。 –
请问您可以发布精确的函数(或者只是相关的部分,分配和递归发生的地方)。这个问题真的很难。 –
@AjayBrahmakshatriya现在好吗? –
你从malloc返回的检查应该与0比较。我期望一个指针等于一个无符号或无符号的long(就像size_t),因此我不希望有可能返回一个负值。通常返回NULL/0是错误条件。 –