簡體   English   中英

為什么valgrind報告glibc tsearch()隨機泄漏內存?

[英]Why does valgrind report that glibc tsearch() randomly leaks memory?

我正在使用glibc tsearch() API系列在示例程序中存儲動態分配的數據塊。

我發現當我使用tsearch()向樹中添加幾個malloc() ed塊時,valgrind會將其中一些塊報告為“可能丟失”。 雖然“可能丟失”與“絕對丟失”並不完全相同,但之前的SO建議通常是調查造成這些問題的原因。

我的示例程序如下:

#include <stdio.h>
#include <search.h>
#include <stdlib.h>
#include <signal.h>

struct data {
    int id;
    char *str;
};

static int
compare (const void *a, const void *b) {
    const struct data *data_a = a, *data_b = b;

    if (data_a->id < data_b->id) {
        return -1;
    } else if (data_a->id > data_b->id) {
        return 1;
    } else {
        return 0;
    }
}

int main (int argc, char **argv) {
    void *tree = NULL;
    struct data *d1, *d2, *d3, *d4;

    d1 = malloc(sizeof(struct data));
    d1->id = 10;
    d1->str = "Hello";
    tsearch(d1, &tree, compare);

    d2 = malloc(sizeof(struct data));
    d2->id = 30;
    d2->str = "Goodbye";
    tsearch(d2, &tree, compare);

    d3 = malloc(sizeof(struct data));
    d3->id = 20;
    d3->str = "Thanks";
    tsearch(d3, &tree, compare);

    d4 = malloc(sizeof(struct data));
    d4->id = 40;
    d4->str = "OK";
    tsearch(d4, &tree, compare);

    raise(SIGINT);

    return 0;
}

請注意,我在main()的末尾調用raise(SIGINT) ,以便valgrind仍然能夠在隱式free() d之前分析已分配的塊。

我在valgrind下編譯和運行如下:

$ gcc ts.c -o ts
$ valgrind --leak-check=full ./ts
==2091== Memcheck, a memory error detector
==2091== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2091== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==2091== Command: ./ts
==2091== 
==2091== 
==2091== Process terminating with default action of signal 2 (SIGINT)
==2091==    at 0x4E7AE97: raise (raise.c:51)
==2091==    by 0x1088CE: main (in /home/ubuntu/ts)
==2091== 
==2091== HEAP SUMMARY:
==2091==     in use at exit: 160 bytes in 8 blocks
==2091==   total heap usage: 8 allocs, 0 frees, 160 bytes allocated
==2091== 
==2091== 24 bytes in 1 blocks are possibly lost in loss record 8 of 8
==2091==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2091==    by 0x4F59483: tsearch (tsearch.c:338)
==2091==    by 0x108801: main (in /home/ubuntu/ts)
==2091== 
==2091== LEAK SUMMARY:
==2091==    definitely lost: 0 bytes in 0 blocks
==2091==    indirectly lost: 0 bytes in 0 blocks
==2091==      possibly lost: 24 bytes in 1 blocks
==2091==    still reachable: 136 bytes in 7 blocks
==2091==         suppressed: 0 bytes in 0 blocks
==2091== Reachable blocks (those to which a pointer was found) are not shown.
==2091== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==2091== 
==2091== For counts of detected and suppressed errors, rerun with: -v
==2091== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

$ 

Valgrind報告說丟失了一個24字節的塊。 如果我在d4分配和樹添加之前移動raise(SIGINT) ,則報告沒有丟失塊。

為什么在添加4個塊時會丟失一個塊,即使在添加3個塊時沒有丟失?

事實證明,glibc tsearch()實現有點頑皮,可以在指向存儲在二叉搜索樹中的塊的指針中旋轉低位。 它使用指針中的低位來存儲標志: https//code.woboq.org/userspace/glibc/misc/tsearch.c.html#341

特別是,實現使用這些宏來設置或清除低階指針位,將塊分別標記為紅色或黑色:

#define SETRED(N) (N)->left_node |= ((uintptr_t) 0x1)
#define SETBLACK(N) (N)->left_node &= ~((uintptr_t) 0x1)

指針有效地遞增,這使得valgrind認為這些有效指針(存儲在tsearch()樹中)已經被覆蓋,因此可能會丟失 但這些不是丟失的塊 - 它們成功地存儲在二進制搜索樹中,以低位為模。 當訪問樹時, tsearch()將對這些位進行必要的屏蔽。 tsearch()可以這樣做,因為malloc() ed塊通常與至少偶數地址對齊。

只有在二叉樹中標記為“紅色”節點的塊才會設置此位,因此其模式“可能丟失”或完全取決於實現如何將塊分類為“紅色”或“黑色”期間添加,刪除和重新平衡操作。

所以tsearch() s bit-twiddling使得valgrind錯誤地認為這些塊丟失了。 在這種情況下,valgrind報告誤報。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM