【问题标题】:Invalid free() after closedir()在 closedir() 之后无效的 free()
【发布时间】:2016-07-21 21:17:38
【问题描述】:

我实现了一个名为 myls 的简单版本的 ls,当我尝试释放程序中创建的链表时,我收到无效的 free() 通知,我认为它与 closedir() 有关,但我没有不知道为什么,这里是内存泄漏检查:(***表示个人信息)

******:~/***/***/myls$ valgrind --leak-check=full --show-reachable=yes myls
==742== Memcheck, a memory error detector
==742== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==742== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==742== Command: myls
==742== 
.
..
Makefile
myls
myls.c
tests
==742== Invalid free() / delete / delete[] / realloc()
==742==    at 0x4C2A82E: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==742==    by 0x4009D2: freeList (in /p2/hh/***/***/***/myls/myls)
==742==    by 0x400AE2: main (in /p2/hh/***/***/***/myls/myls)
==742==  Address 0x51f0083 is 67 bytes inside a block of size 32,816 alloc'd
==742==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==742==    by 0x4EECD5A: __alloc_dir (opendir.c:202)
==742==    by 0x400A0B: main (in /p2/hh/***/***/***/myls/myls)
==742== 
==742== 
==742== HEAP SUMMARY:
==742==     in use at exit: 0 bytes in 0 blocks
==742==   total heap usage: 7 allocs, 13 frees, 32,912 bytes allocated
==742== 
==742== All heap blocks were freed -- no leaks are possible
==742== 
==742== For counts of detected and suppressed errors, rerun with: -v
==742== ERROR SUMMARY: 6 errors from 1 contexts (suppressed: 2 from 2)

这是我的代码

#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
typedef struct n{
    char *key;
    struct n *next;
} node;
node *list = NULL;

// errorCheck(*myDir) -- check if the target directory is opened
// correctly or print out an error message if not and exit.
void errorCheck(DIR *myDir){
    if (myDir == NULL){
        perror("Error");
        exit(1);
    }
}

// buildList(*myDir) -- create a list containing
// all directories' name.
node *buildList(DIR *myDir){
    struct dirent *dirPtr;
    node *temp = NULL;

    // put into list
    while ((dirPtr = readdir(myDir)) != NULL){
        temp = malloc(sizeof(node));
        if (temp == NULL){
            fprintf(stderr, "Error: out of memory!\n");
            exit(1);
        }
        temp -> key = dirPtr -> d_name;
        temp -> next = list;
        list = temp;
    }

    return temp;
}

// printList(*list) -- print out the linked list.
void printList(node *list){
    node *temp = NULL;

    temp = list;
    while (temp != NULL){
        printf("%s\n", temp -> key);
        temp = temp -> next;
    }
}

// swap(*n1, *n2) -- swap keys of these two nodes.
void swap(node *n1, node *n2){
    char *temp;
    temp = n1 -> key;
    n1 -> key = n2 -> key;
    n2 -> key = temp;
}

// sortList(*list) -- use bubble sort to sort the
// linked list in alphabetic order.
void sortList(node *list){
    node *curr, *last = NULL;
    int changed;

    do{
        changed = 0;
        curr = list;

        while (curr -> next != last){
            if (strcmp(curr -> key, curr -> next -> key) > 0){
                swap(curr, curr -> next);
                changed = 1;
            }
            curr = curr -> next;
        }
        last = curr;
    } while (changed == 1);
}

// freeList() -- free up the linked list.
void freeList(){
    node *temp = list;

    while (list != NULL){
        temp = list;
        list = list -> next;
        free(temp -> key);
        free(temp);
    }
}

// main() -- main structure of the program
int main(int argc, char *argv[]){
    DIR *myDir;

    if (argc == 1){
        myDir = opendir(".");
        errorCheck(myDir);
        list = buildList(myDir);
        sortList(list);
        printList(list);
        closedir(myDir);
    }
    else if(argc == 2){
        myDir = opendir(argv[1]);
        errorCheck(myDir);
        list = buildList(myDir);
        sortList(list);
        printList(list);
        closedir(myDir);
    }
    else{
        fprintf(stderr, "Error: too many arguments!\n");
        return 1;
    }

    freeList();
    return 0;
}

谁能帮忙?

【问题讨论】:

  • 这个temp -&gt; key = dirPtr -&gt; d_name; 应该复制strdupmalloc 路由。甚至在你的结构中使用MAX_PATH_LEN 并使用strcpy
  • 天哪,这就是解决方案,我错过了,非常感谢!
  • 没问题 - 我只是看起来像个上帝 :-)
  • 如果评论解决了问题,你也可以删除问题
  • 您可能会发现,如果您打印列表(在释放任何内容之前),所有名称都是相同的,因为 readdir() 很有可能在每次返回时重用相同的空间文件名。使用strdup() 或亲戚的另一个原因。这也是您得到 6 个错误副本的原因;您的目录中有 6 个条目,因此您释放了 6 次相同的空间,但 closedir() 也首先释放了它。

标签: c linux memory-management memory-leaks


【解决方案1】:

我没有明确地看到 temp->key 的内存分配在哪里,所以我猜你不应该在它上面调用 free()。

// freeList() -- free up the linked list.
void freeList(){
    node *temp = list;

    while (list != NULL){
        temp = list;
        list = list -> next;
        **free(temp -> key);**
        free(temp);
    }

信息来自:http://man7.org/linux/man-pages/man3/readdir.3.html

   On success, readdir() returns a pointer to a dirent structure.  (This
   structure may be statically allocated; do not attempt to free(3) it.)

【讨论】:

  • 也许您应该阅读我 12 分钟前发表的评论并使用该信息提出解决方案
  • @ed-heal,我正在调查问题,看看问题出在哪里,这就是问题陈述(而不是解决方案本身)。在我进一步查看之前,您的 cmets 可能已经与我的路径交叉。是的,然后解决方案是查看代码中缺少的内容以使其工作 - standup()、strip()、malloc() + strlcpy()/strcpy() 等。所以,不要试图讽刺您的 cmets 或响应。
  • @ed-heal,也许你可以写,“我刚刚发布了关于我认为问题所在的 cmets,你可能想参考它”。听起来如何改变?
  • 发帖人已经同意这是问题所在
  • 好,现在让@crysishy 决定他接下来想做什么。然后他可以做出相应的评论。
猜你喜欢
  • 2012-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-21
  • 1970-01-01
  • 2014-07-01
  • 1970-01-01
  • 2013-06-27
相关资源
最近更新 更多