Home > Mobile >  hashtable issue in C; double free detected in tcache 2
hashtable issue in C; double free detected in tcache 2

Time:11-29

I am coding a hash table with singly linkedList and I have this problem free(): double free detected in tcache 2 I tried to fix it but did'nt make it, the problem its the free() , so could you explain me why I have it, So if anyone can help, so please help me, I'm trying to fix it for hours now... Thank you.

I've watched some video on youtube and many topics on websitte and also here but I didn't find a solution for mine.

This are my functions:

/****  c file */

/*
some functions here 
.
.
.
*/

strhash_table * strhash_table_destroy(strhash_table * table)
{
    unsigned int i;
    super_list *list;
    s_node *node;

    for (i = 0; i < table->len; i  ) {
        list = table->list   i;
        for (node = list->node; node != NULL; node = node->next) {
            free(node->data);
        }
        list_destroy(list->node);
    }
    free(table->list);

    free(table);
    return table;
 
}

strhash_table * strhash_table_free(strhash_table * table)
{
    unsigned int i;
    super_list *list;
    for (i = 0; i < table->len; i  ) {
        list = table->list   i;
        if (list->len > 0) {
            free(list->node->data);
            list_destroy(list->node);
            list->len = 0;
            return table;
        }
    }
    return table;
}

strhash_table * strhash_table_remove(strhash_table * table, char * str)
{
    const int index = hashCode(str, table->len);
    if (table->list[index].len == 0) return table;

    s_node *find_node;
    const int result = list_process(table->list[index].node, &find_str_node, str, &find_node);
    if (result == 1) {
        free(find_node->data);
        table->list[index].node = list_remove(table->list[index].node, find_node->data);
        table->list[index].len--;
    }
    return table;
}

/**** test file */


strhash_table * test_init(const unsigned int len)
{
    strhash_table * table = strhash_table_init(len);
    if (!table) {
        printf(RED"Tha HashTable hasn't been created\n"reset);
        assert(0);
    }
    printf(GRN"***Tha HashTable has been created***\n"reset);
    return table;
}

strhash_table * test_destroy(strhash_table * table){
    
    table = strhash_table_destroy(table);
    if (table->list->node) {
        printf(RED"The HashTable hasn't been destroyed (%p)\n"reset, table->list->node);
        assert(0);
    }
    printf(GRN"The HashTable has been destroyed\n"reset);
    return NULL;
}

int main(void)
{
    strhash_table * table =strhash_table_init(10);
    strhash_print(table);
    strhash_table_add(table, "ele1");
    strhash_table_add(table, "ele2");
    strhash_table_add(table, "ele3");
    strhash_table_add(table, "ele4");
    strhash_table_add(table, "ele5");
    //strhash_table_remove(table,"ele1");
    //strhash_table_free(table);
    test_destroy(table); 

    return 0;
}

Thank you in advance ^^

CodePudding user response:

You should move list_destroy(list->node); outside the inner loop. You are freeing the node list multiple times inside a loop where you iterate on the node links.

Here is a modified version:

strhash_table *strhash_table_destroy(strhash_table *table) {
    unsigned int i;
    super_list *list;
    s_node *node;

    for (i = 0; i < table->len; i  ) {
        list = table->list   i;
        for (node = list->node; node != NULL; node = node->next) {
            free(node->data);
        }
        list_destroy(list->node);
    }
    free(table->list);
    free(table);
    return table;
}

void list_destroy(s_node *head) {
    while (head) {
        head = list_headRemove(head);
    }
}

s_node *list_headRemove(s_node *head) {
    if (!head) return head;
    s_node *n = head->next;
    free(head);
    return n;
}

UPDATE

In the code posted, there are conflicting versions of functions list_destroy and list_headRemove, furthermore there are 2 calls to free(node); in the second function list_destroy, both of which are useless since node is a null pointer when the while loop exits.

UPDATE 2

There is a problem in strhash_table_free: you free list->node but you do not update list->node, so the list is freed a second time in strhash_table_destroy where list->len is not tested.

The field len in super_list seems redundant. You should just test if the node member is NULL and set it to NULL when the list is freed.

CodePudding user response:

A cleaner way to do it in my opinion assuming you don't reuse list_headRemove and list_headRemove :

strhash_table *strhash_table_destroy(strhash_table *table) {
    unsigned int i;
    super_list *list;
    s_node *node, *next;

    for (i = 0; i < table->len; i  ) {
        
        list = table->list   i;
        node = list->node;

        while (node) {
            next = node->next;

            free(node->data);           
            free(node);

            node = next;
        }

    }

    free(table->list);
    free(table);

    return table; /* This pointer is not valid anymore be careful */
}
  • Related