2017-05-27 4 views
-1

これは、list_directory関数であり、割り当てられたポインタを失い、後で解放することはできません。 これはls-aのような実装でなければなりません。ディレクトリを見つけたら、名前を保存し、ディレクトリをリストした後、現在のディレクトリにあるディレクトリのlist_directoryを再帰的に呼び出す必要があります。しかし何らかの理由で途中でいくつかの要素が失われます。割り当てられた配列を再帰関数経由で渡すときのメモリリーク

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の出力:

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; 
} 

私はここにあるdir_indent_infoargvを渡す

==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を割り当てる:現在のファイルは、我々が同じ関数を呼び出す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

正確な機能(または割り当てや再帰が行われる関連部分のみ)を投稿してください。それは本当にこの大きな質問の難しいです。 –

+0

@AjayBrahmakshatriyaそれは今大丈夫ですか? –

+0

mallocからの返り値のチェックは0と比較するべきです。私はポインタがunsignedまたはunsigned long(size_tのような)と同等であると期待していますので、負の値を返すことはできません。通常NULL/0を返すのはエラー条件です。 –

答えて

0

あなたのコードは、このような巨大な機能、初期化されていない変数、変数の流行名の再利用など、多数の問題を、持っています変数の不必要な広範な範囲、割り当てられたメモリの不明な所有権、条件式の代入、0とポインタの比較より小さい。

メモリリークに関しては、例えば:

  • あなたは./ls文字列の最初のrecursqueue項目を割り当てるが、printsubdirが1に設定されていない場合、それは解放されることはありません。
  • recursqueueの配列を割り当てますが、list_directoryが0より小さい値を返す場合は、決して解放されません(closedirも呼び出されません)。
+0

私はすでに間違いを見つけましたが、答えとこの混乱の中で何が改善されなければならないかを指摘してくれてありがとう。 –

関連する問題