Valgrind内存泄漏问题的检测

4
我正在编写一个程序,用于搜索请求的文件所在的目录。命令行输出将是每个找到的同名文件的目录路径。但是当我使用valgrind运行它时,出现了内存泄漏问题。我在Windows虚拟机上运行Linux系统。
我更新了valgrind输出。没有任何泄漏,但仍然存在错误。
以下是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <string.h>

struct tree_t {

  char *name;
  int  nchildren;
  struct tree_t **children;
};

char *make_path(const char *dirname, const char *filename) {
  char *fullpath = (char *) malloc((strlen(dirname) + strlen(filename) + 1 + 1) * sizeof(char));
  strcat(fullpath, dirname);
  strcat(fullpath, "/");
  strcat(fullpath, filename);
  return fullpath;
}

struct tree_t *get_tree(const char *name) {
  struct tree_t *tree = (struct tree_t *) malloc(sizeof(struct tree_t)); 
  char *namecp = (char *) malloc((strlen(name) + 1) * sizeof(char));
  strcpy(namecp, name);
  tree->name = namecp;

  DIR *dir = opendir(name);
  if (dir == NULL) {
    tree->nchildren = 0;
  } else {
    tree->nchildren = 0;
    int numsubdirs = 0;

    struct dirent *entry;

    while((entry = readdir(dir))) {
      if (strcmp(entry->d_name,".") != 0 && strcmp(entry->d_name,"..") != 0) {
        tree->nchildren++;  
        DIR *subdir = opendir(entry->d_name);
        if (subdir != NULL) {
          numsubdirs++;
        }
        closedir(subdir);
      }
    }

    tree->children = (struct tree_t **) malloc(numsubdirs * sizeof(struct tree_t **));
  }
  closedir(dir);
  return tree;
}

void find_in_tree(const struct tree_t *root, const char *filename) {
  int i = 0;

  DIR *dir = opendir(root->name);

  if (dir != NULL) {

    struct dirent *entry;

    while((entry = readdir(dir))) {
      if (strcmp(entry->d_name,".") != 0 && strcmp(entry->d_name,"..") != 0) {
        char *fullpath = make_path(root->name, entry->d_name);
        DIR *subdir = opendir(fullpath);
        if (subdir != NULL) {
          root->children[i] = get_tree(fullpath);
          find_in_tree(root->children[i], filename);
          free(root->children[i]);
          i++;
        } else if (strcmp(entry->d_name, filename) == 0) {
          printf("%s\n", fullpath);
        } 
        free(fullpath);
      }
    }
  }

  free(root->name);
  free(root->children);

}

int main(int argc, char **args) {
  printf("What root directory do you want to start from?\n");
  char rootdir[256];
  scanf("%s",rootdir);

  char searchfile[256];
  printf("What file do you want to search for?\n");
  int result = scanf("%s",searchfile);

  if (result == EOF) {
    printf("\n");
    exit(1);
  }

  struct tree_t *root = get_tree(rootdir);
  find_in_tree(root, searchfile);
  free(root);

  return 0;
}

这是我的内存检查运行后的样子。
[vosterjl@clark ~]$ valgrind --tool=memcheck --leak-check=yes -v --track-origins=yes ./dirch
==1464== Memcheck, a memory error detector
==1464== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==1464== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==1464== Command: ./dirch
==1464==
--1464-- Valgrind options:
--1464--    --tool=memcheck
--1464--    --leak-check=yes
--1464--    -v
--1464--    --track-origins=yes
--1464-- Contents of /proc/version:
--1464--   Linux version 2.6.18-274.17.1.el5 (mockbuild@hs20-bc2-5.build.redhat.com) (gcc version 4.1.2 20080704 (Red Hat 4.1.2-51)) #1 SMP Wed Jan 4 22:45:44 EST 2012
--1464-- Arch and hwcaps: AMD64, amd64-sse3-cx16
--1464-- Page sizes: currently 4096, max supported 4096
--1464-- Valgrind library directory: /usr/lib64/valgrind
--1464-- Reading syms from /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch (0x400000)
--1464-- Reading syms from /usr/lib64/valgrind/memcheck-amd64-linux (0x38000000)
--1464--    object doesn't have a dynamic symbol table
--1464-- Reading syms from /lib64/ld-2.5.so (0x3ca2e00000)
--1464-- Reading suppressions file: /usr/lib64/valgrind/default.supp
--1464-- REDIR: 0x3ca2e14730 (strlen) redirected to 0x3803e767 (vgPlain_amd64_linux_REDIR_FOR_strlen)
--1464-- Reading syms from /usr/lib64/valgrind/vgpreload_core-amd64-linux.so (0x4802000)
--1464-- Reading syms from /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so (0x4a03000)
==1464== WARNING: new redirection conflicts with existing -- ignoring it
--1464--     new: 0x3ca2e14730 (strlen              ) R-> 0x04a070b0 strlen
--1464-- REDIR: 0x3ca2e14550 (index) redirected to 0x4a06f20 (index)
--1464-- REDIR: 0x3ca2e14700 (strcmp) redirected to 0x4a07180 (strcmp)
--1464-- Reading syms from /lib64/libc-2.5.so (0x3ca3200000)
--1464-- REDIR: 0x3ca3279f60 (rindex) redirected to 0x4a06dd0 (rindex)
--1464-- REDIR: 0x3ca3279b70 (strlen) redirected to 0x4a07070 (strlen)
Directory?
dir1
Search file?
test.txt
--1464-- REDIR: 0x3ca3274de0 (malloc) redirected to 0x4a0608a (malloc)
--1464-- REDIR: 0x3ca3279630 (strcpy) redirected to 0x4a08a70 (strcpy)
--1464-- REDIR: 0x3ca327ac80 (memmove) redirected to 0x4a07370 (memmove)
--1464-- REDIR: 0x3ca3272890 (free) redirected to 0x4a05c9a (free)
--1464-- REDIR: 0x3ca3279280 (strcat) redirected to 0x4a07d40 (strcat)
==1464== Invalid write of size 8
==1464==    at 0x400AF3: find_in_tree (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==    by 0x400C1F: main (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==  Address 0x4c2c170 is 0 bytes after a block of size 0 alloc'd
==1464==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==1464==    by 0x4009D2: get_tree (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==    by 0x400C0B: main (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==
==1464== Invalid read of size 8
==1464==    at 0x400B0B: find_in_tree (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==    by 0x400C1F: main (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==  Address 0x4c2c170 is 0 bytes after a block of size 0 alloc'd
==1464==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==1464==    by 0x4009D2: get_tree (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==    by 0x400C0B: main (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==
--1464-- REDIR: 0x3ca32795f0 (strcmp) redirected to 0x4a07140 (strcmp)
dir1/dir2/test.txt
==1464== Invalid read of size 8
==1464==    at 0x400B2C: find_in_tree (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==    by 0x400C1F: main (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==  Address 0x4c2c170 is 0 bytes after a block of size 0 alloc'd
==1464==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==1464==    by 0x4009D2: get_tree (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==    by 0x400C0B: main (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==
dir1/test.txt
Search file?

--1464-- REDIR: 0x3ca327ae20 (memset) redirected to 0x4a07320 (memset)
==1464==
==1464== HEAP SUMMARY:
==1464==     in use at exit: 0 bytes in 0 blocks
==1464==   total heap usage: 22 allocs, 22 frees, 262,763 bytes allocated
==1464==
==1464== All heap blocks were freed -- no leaks are possible
==1464==
==1464== ERROR SUMMARY: 6 errors from 3 contexts (suppressed: 4 from 4)
==1464==
==1464== 2 errors in context 1 of 3:
==1464== Invalid read of size 8
==1464==    at 0x400B2C: find_in_tree (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==    by 0x400C1F: main (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==  Address 0x4c2c170 is 0 bytes after a block of size 0 alloc'd
==1464==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==1464==    by 0x4009D2: get_tree (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==    by 0x400C0B: main (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==
==1464==
==1464== 2 errors in context 2 of 3:
==1464== Invalid read of size 8
==1464==    at 0x400B0B: find_in_tree (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==    by 0x400C1F: main (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==  Address 0x4c2c170 is 0 bytes after a block of size 0 alloc'd
==1464==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==1464==    by 0x4009D2: get_tree (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==    by 0x400C0B: main (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==
==1464==
==1464== 2 errors in context 3 of 3:
==1464== Invalid write of size 8
==1464==    at 0x400AF3: find_in_tree (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==    by 0x400C1F: main (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==  Address 0x4c2c170 is 0 bytes after a block of size 0 alloc'd
==1464==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==1464==    by 0x4009D2: get_tree (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==    by 0x400C0B: main (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch)
==1464==
--1464--
--1464-- used_suppression:      4 dl-hack3
==1464==
==1464== ERROR SUMMARY: 6 errors from 3 contexts (suppressed: 4 from 4)

任何帮助都可以,谢谢!

什么平台?这很重要,在Mac上,它总是报告至少一些泄漏。 - Prashant Kumar
如果您使用 --leak-check-full--track-origins-yes 重新运行 valgrind,那么您将看到泄漏的内存和未初始化值来自哪里。 - Timothy Jones
3
fullpath 是通过 malloc 分配的,但这并不保证其被初始化为 0,因此会出现未初始化值的警告。也许应该将 strcat(fullpath, dirname); 改为 strcpy(fullpath, dirname);?另外,请确保字符串以 NUL 结尾。在 C 中,不要强制转换 malloc 的返回值。 - another.anon.coward
@Prashant - 他说问题中的平台是在Windows上的Linux虚拟机。 - Hogan
是的,我忘记了 *fullpath = '\0'; 这一行代码,以消除 valgrind 结果中的警告。 - Jake Vosters
2个回答

4

相信 valgrind,不要相信你的代码。

例如:

char *make_path(const char *dirname, const char *filename) {
    char *fullpath = (char *) malloc((strlen(dirname) + strlen(filename) + 1 + 1) * sizeof(char));
    strcat(fullpath, dirname);

malloc() 返回的内存未被初始化,因此您不能立即使用 strcat()

毫无疑问,还会出现其他类似的问题。


4
对于每个 opendir 操作,您都应该使用 closedir 进行关闭。请检查一下。这可能是您泄漏的源头。
Valgrind 也向您指出了这一点。
==468== 65,648 bytes in 2 blocks are definitely lost in loss record 3 of 3 
==468==    at 0x4A0610C: malloc (vg_replace_malloc.c:195) 
==468==    by 0x3CA3296822: __alloc_dir (in /lib64/libc-2.5.so) 
==468==    by 0x400A09: find_in_tree (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch) 
==468==    by 0x400B0F: find_in_tree (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch) 
==468==    by 0x400C06: main (in /USERS/STUDENTS/S-Z/V/VOSTERJL/dirch) 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接