【问题标题】:Why doesn't valgrind detect memory leaks?为什么 valgrind 不检测内存泄漏?
【发布时间】:2021-02-28 21:11:59
【问题描述】:

我试图弄清楚为什么当我故意避免释放内存时valgrind 没有检测到任何错误。我有这个小程序。它从键盘读取数字并打印消息You've entered <number>!。如果之前读取过该号码,则打印You've already read <number>!

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct node {
    int number;
    struct node* next;
};

struct node* add(struct node* head, int number) {
    struct node* n;
    struct node* p;
    
    n = (struct node*)malloc(sizeof(struct node));
    n->number = number;
    n->next = NULL;

    if (head == NULL) {
        return n;
    }

    p = head;
    while (p->next != NULL) {
        p = p->next;
    }
    p->next = n;
    return head;
}

void clear(struct node* head) {
    if (head == NULL) {
        return;
    }
    clear(head->next);
    free(head);
}

int already_read(struct node* head, int number) {
    struct node* p;
    if (head == NULL) {
        return 0;
    }

    p = head;
    while (p!=NULL && p->number!=number) {
        p = p->next;
    }
    
    if (p == NULL) {
        return 0;
    }
    return 1;
}

int main(int argc, char** argv) {
    int number;
    struct node* head = NULL;
    while (scanf("%d", &number) == 1) {
        if (already_read(head, number)) {
            printf("You've already entered %d!\n", number);
        }
        else {
            head = add(head, number);
            printf("You entered %d!\n", number);
        }
    }
    clear(head);
    return 0;
}

我使用 gcc 编译它(这个文件在我的系统上称为program.c,所以我使用了命令gcc -Wall -g -o program program.c)。它编译得很好。然后,当我使用 valgrind (valgrind ./program) 运行它时,我输入一些数字以查看程序是否正常工作,然后我使用 CTRL-C 停止它。我没有错误。太好了。

LEAK SUMMARY:
    definetely lost: 0 bytes in 0 blocks
    indirectly lost: 0 bytes in 0 blocks
      possibly lost: 0 bytes in 0 blocks
    still reachable: 64 bytes in 4 blocks
         suppressed: 0 bytes in 0 blocks
ERROR SUMMARY: 0 errors from 0 context (suppressed: 8 from 6)

然后我回到代码中。我保持原样,除了我将main() 中的行更改为clear(head)//clear(head)。所以现在程序不再释放空间了。它有泄漏。我用valgrind 重新编译并再次运行它。我输入与以前相同的输入。而且...我得到相同的错误报告。和上面那个完全一样。我不明白为什么会这样。它不应该报告内存泄漏,因为我没有释放内存吗?我做错了吗?

【问题讨论】:

  • clear(head); 出现在 return 0; 之前,此时所有分配的内存都被释放并自动返回给操作系统。这可能就是 Valgrind 没有报告内存泄漏的原因。 没有。
  • 如果您在等待输入时 Ctrl-C 则永远不会调用 clear(),因此它是否存在无关紧要。如果它确实被调用(例如,如果您以 Ctrl-D 结束文件),那么它会无限递归并崩溃。
  • 如果clear 没有被调用,那么你的内存仍然可以访问。 valgrind 不会将此视为泄漏;它假定您需要该内存直到程序结束,并且依赖它在退出时自动释放。如果这不是您的理念,那么您可以将“仍然可访问”条目解释为泄漏。
  • 顺便说一句,显示的代码无法编译。它在already_read 中缺少p 声明。 clear 函数也没有意义——它会导致堆栈溢出和/或其他未定义的行为,因为它使用相同的指针值无限递归地调用自身。
  • 跟进最后一条消息,您需要复制并粘贴您正在编译和运行的确切代码。重新输入的近似值还不够好。

标签: c valgrind


【解决方案1】:

如果我在 clear call 被注释掉的情况下运行代码并输入 1, 2, 3, 2, q 那么我得到

==60380== 48 (16 direct, 32 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==60380==    at 0x4839755: malloc (vg_replace_malloc.c:307)
==60380==    by 0x401178: add (test.c:14)
==60380==    by 0x401335: main (test.c:63)
==60380== 
==60380== LEAK SUMMARY:
==60380==    definitely lost: 16 bytes in 1 blocks
==60380==    indirectly lost: 32 bytes in 2 blocks
==60380==      possibly lost: 0 bytes in 0 blocks
==60380==    still reachable: 0 bytes in 0 blocks
==60380==         suppressed: 0 bytes in 0 blocks

命令valgrind --leak-check=full ./test

这正是我所期望的。这是在 amd64 上,所以每个节点都是 16 字节。分配了 3 个节点(用于 1、2 和 3,但不用于重复的 2 或 q)。在main() 的末尾,head 变量超出范围。所以在终止时不存在指向头(1)节点的指针->这是一个明确的泄漏。由于链表,确实存在指向(2)和(3)节点的指针(从头节点到(2)和从(2)到(3)的指针。因此(2)和(3)节点是间接泄漏。

【讨论】:

    猜你喜欢
    • 2015-02-28
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    • 1970-01-01
    • 2012-05-08
    • 2015-08-12
    • 2020-05-01
    相关资源
    最近更新 更多