这是函数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);
}
使用收集的子目录调用相同的函数&#39;路径:
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 :(得分:0)
您的代码存在许多问题,例如巨大的函数,未初始化的变量,变量的时尚名称,不相关的变量重用,变量的不必要的广泛范围,分配的内存的模糊所有权,条件表达式中的赋值,小于指针与0等的比较
至于内存泄漏,这些代码很容易发生,例如:
recursqueue
字符串分配了第一个./ls
项,但如果printsubdir
未设置为1,那么它将永远不会被释放; recursqueue
数组,但如果list_directory
返回小于0的值,则永远不会释放它(并且也不会调用closedir
);