gpt4 book ai didi

c - 通过递归函数传递分配的数组时出现内存泄漏

转载 作者:行者123 更新时间:2023-11-30 19:34:12 25 4
gpt4 key购买 nike

这是函数list_directory,我在其中丢失了分配的指针,并且以后无法释放它。这应该是类似 ls-a 的实现,当它找到一个目录时,它应该保存其名称,并在列出目录后,它应该递归地在当前目录中找到的目录上调用 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)

为 char** 数组分配指针:

if (chinfo->param_R)
{
if ((recursqueue = malloc(argc * sizeof(char*))) < 0)
perror("malloc");
}

分配第一个元素并为其分配 ./ls 以模拟参数输入:

if (chinfo->param_R)
{
if ((recursqueue[subdirs] = malloc((256) * sizeof(char))) < 0)
perror("malloc");
strcpy(recursqueue[subdirs++], "./ls");
}

如果当前文件是目录,我们将其添加到recursqueue

case S_IFDIR:  printf("d");
if (chinfo->param_R)
{
printsubdir = 1;
recursqueue[subdirs] = malloc((256) * sizeof(char));
strcpy(recursqueue[subdirs++], path);
}

使用收集的子目录路径调用相同的函数:

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等的比较

至于内存泄漏,这样的代码很容易发生,例如:

  • 您为 ./ls 字符串分配第一个 recursqueue 项,但如果 printsubdir 未设置为 1,则它将永远不会被释放;
  • 你分配了recursqueue数组,但是如果list_directory返回的值小于0,那么它永远不会被释放(并且linedir也不会被调用);

关于c - 通过递归函数传递分配的数组时出现内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44217396/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com