Search code examples
cmemoryfree

Double free error detected while cleaning


I am getting error while clearing the array

I want to copy all the data of some variables from the MySettings structure

struct Block {
    int id;  
};
 
struct MySettings {
    int conf_id;
    int group;
    int enable;
    int hide_name;
    int login_persistence;
    int remove_cache;
    struct Block *block;
};
 
 
struct MySettings *Settings[50];
 
void clear(void) {
    puts("Clearing...");
    for(int i = 0; i < 50; i++) {
        if(Settings[i]) {
            if(Settings[i]->block)
                free(Settings[i]->block);
 
            free(Settings[i]);
            Settings[i] = NULL;
        }
    }
}
 
int GetGroupID(int i)
{
    return i;
}
 
void read_db(void) {
    puts("Allocating...");
 
    for(int i = 0; i < 10; i++) {
        struct MySettings *st = calloc(1, sizeof *st);
 
        st->conf_id = i;
 
        st->hide_name = 1;
        st->login_persistence = 1;
        st->remove_cache = 1;
 
        st->block = realloc(st->block, (i + 1) * sizeof *st->block);
        st->block[i].id = i+1;      
 
        for(int g = 0; g < 5; g++) {
            st->group = GetGroupID(g);
            st->enable = 1;
            printf("pointer %p group_id %d enable %s\n", st, st->group, st->enable ? "true" : "false");
 
            Settings[st->group] = st;
        }
 
 
    }
 
    clear();    
}
 
 
int main(void) 
{
    read_db();
    puts("Done...");
    return 0;
}

In the group and enable part, I look for a way for each entry to have a different address

What currently happens is that when I do the for loop using variable g all group and enable generated in this loop have the same address

I want group and enable to always have different addresses

What should I do ?


Solution

  • This is possible and even easy to do

    When you set Settings[st->group] = st, the loop will always use the same address.

    To create an address at each exit of the for loop we need to create a new structure

    As for the double free issue, we need to create a separate settings cleaning to avoid this type of problem

    Here's the example, based on your code:

    #include <stdio.h>
    #include <stdlib.h>
    
    struct Block {
        int id;  
    };
    
    struct config {
        int conf_id;
        int hide_name;
        int login_persistence;
        int remove_cache;
        struct Block *block;
    };
     
    struct MySettings {
        int group;
        int enable;
        struct config *conf; 
    };
     
    struct config *conf[50];
    struct MySettings *Settings[50];
     
    void clear(void) {
        puts("Cleaning...");
        for(int i = 0; i < 50; i++) {
            if(conf[i]) {
                if(conf[i]->block)
                    free(conf[i]->block);
                    
                free(conf[i]);
                conf[i] = NULL;
            }
     
            if(Settings[i]) {
                free(Settings[i]);
                Settings[i] = NULL;
            }
        }
    }
     
    int GetGroupID(int i)
    {
        return i;
    }
     
    void read_db(void) {
        puts("Allocating...");
     
        for(int i = 0; i < 10; i++) {
            struct config *config = calloc(1, sizeof *conf);
     
            config->conf_id = i;
     
            config->hide_name = 1;
            config->login_persistence = 1;
            config->remove_cache = 1;
     
            config->block = realloc(config->block, (i + 1) * sizeof *config->block);
            config->block[i].id = i+1;      
     
            for(int g = 0; g < 5; g++) {
                struct MySettings *st = calloc(1, sizeof *st);
                st->group = GetGroupID(g);
                st->enable = 1;
                st->conf = config;
                printf("pointer %p pointer conf %p group_id %d enable %s\n", st, st->conf, st->group, st->enable ? "true" : "false");
     
                Settings[st->group] = st;
            }
     
            conf[config->conf_id] = config;
        }
     
        clear();    
    }
     
     
    int main(void) 
    {
        read_db();
        puts("Done...");
        return 0;
    }
    

    I have the following output from this code:

    Allocating...
    pointer 0x55e6ed1d62b0 pointer conf 0x55e6ed1d6270 group_id 0 enable true
    pointer 0x55e6ed1d62d0 pointer conf 0x55e6ed1d6270 group_id 1 enable true
    pointer 0x55e6ed1d62f0 pointer conf 0x55e6ed1d6270 group_id 2 enable true
    pointer 0x55e6ed1d6310 pointer conf 0x55e6ed1d6270 group_id 3 enable true
    pointer 0x55e6ed1d6330 pointer conf 0x55e6ed1d6270 group_id 4 enable true
    pointer 0x55e6ed1d6390 pointer conf 0x55e6ed1d6350 group_id 0 enable true
    pointer 0x55e6ed1d63b0 pointer conf 0x55e6ed1d6350 group_id 1 enable true
    pointer 0x55e6ed1d63d0 pointer conf 0x55e6ed1d6350 group_id 2 enable true
    pointer 0x55e6ed1d63f0 pointer conf 0x55e6ed1d6350 group_id 3 enable true
    pointer 0x55e6ed1d6410 pointer conf 0x55e6ed1d6350 group_id 4 enable true
    pointer 0x55e6ed1d6470 pointer conf 0x55e6ed1d6430 group_id 0 enable true
    pointer 0x55e6ed1d6490 pointer conf 0x55e6ed1d6430 group_id 1 enable true
    pointer 0x55e6ed1d64b0 pointer conf 0x55e6ed1d6430 group_id 2 enable true
    pointer 0x55e6ed1d64d0 pointer conf 0x55e6ed1d6430 group_id 3 enable true
    pointer 0x55e6ed1d64f0 pointer conf 0x55e6ed1d6430 group_id 4 enable true
    pointer 0x55e6ed1d6550 pointer conf 0x55e6ed1d6510 group_id 0 enable true
    pointer 0x55e6ed1d6570 pointer conf 0x55e6ed1d6510 group_id 1 enable true
    pointer 0x55e6ed1d6590 pointer conf 0x55e6ed1d6510 group_id 2 enable true
    pointer 0x55e6ed1d65b0 pointer conf 0x55e6ed1d6510 group_id 3 enable true
    pointer 0x55e6ed1d65d0 pointer conf 0x55e6ed1d6510 group_id 4 enable true
    pointer 0x55e6ed1d6630 pointer conf 0x55e6ed1d65f0 group_id 0 enable true
    pointer 0x55e6ed1d6650 pointer conf 0x55e6ed1d65f0 group_id 1 enable true
    pointer 0x55e6ed1d6670 pointer conf 0x55e6ed1d65f0 group_id 2 enable true
    pointer 0x55e6ed1d6690 pointer conf 0x55e6ed1d65f0 group_id 3 enable true
    pointer 0x55e6ed1d66b0 pointer conf 0x55e6ed1d65f0 group_id 4 enable true
    pointer 0x55e6ed1d6710 pointer conf 0x55e6ed1d66d0 group_id 0 enable true
    pointer 0x55e6ed1d6730 pointer conf 0x55e6ed1d66d0 group_id 1 enable true
    pointer 0x55e6ed1d6750 pointer conf 0x55e6ed1d66d0 group_id 2 enable true
    pointer 0x55e6ed1d6770 pointer conf 0x55e6ed1d66d0 group_id 3 enable true
    pointer 0x55e6ed1d6790 pointer conf 0x55e6ed1d66d0 group_id 4 enable true
    pointer 0x55e6ed1d6800 pointer conf 0x55e6ed1d67b0 group_id 0 enable true
    pointer 0x55e6ed1d6820 pointer conf 0x55e6ed1d67b0 group_id 1 enable true
    pointer 0x55e6ed1d6840 pointer conf 0x55e6ed1d67b0 group_id 2 enable true
    pointer 0x55e6ed1d6860 pointer conf 0x55e6ed1d67b0 group_id 3 enable true
    pointer 0x55e6ed1d6880 pointer conf 0x55e6ed1d67b0 group_id 4 enable true
    pointer 0x55e6ed1d68f0 pointer conf 0x55e6ed1d68a0 group_id 0 enable true
    pointer 0x55e6ed1d6910 pointer conf 0x55e6ed1d68a0 group_id 1 enable true
    pointer 0x55e6ed1d6930 pointer conf 0x55e6ed1d68a0 group_id 2 enable true
    pointer 0x55e6ed1d6950 pointer conf 0x55e6ed1d68a0 group_id 3 enable true
    pointer 0x55e6ed1d6970 pointer conf 0x55e6ed1d68a0 group_id 4 enable true
    pointer 0x55e6ed1d69e0 pointer conf 0x55e6ed1d6990 group_id 0 enable true
    pointer 0x55e6ed1d6a00 pointer conf 0x55e6ed1d6990 group_id 1 enable true
    pointer 0x55e6ed1d6a20 pointer conf 0x55e6ed1d6990 group_id 2 enable true
    pointer 0x55e6ed1d6a40 pointer conf 0x55e6ed1d6990 group_id 3 enable true
    pointer 0x55e6ed1d6a60 pointer conf 0x55e6ed1d6990 group_id 4 enable true
    pointer 0x55e6ed1d6ad0 pointer conf 0x55e6ed1d6a80 group_id 0 enable true
    pointer 0x55e6ed1d6af0 pointer conf 0x55e6ed1d6a80 group_id 1 enable true
    pointer 0x55e6ed1d6b10 pointer conf 0x55e6ed1d6a80 group_id 2 enable true
    pointer 0x55e6ed1d6b30 pointer conf 0x55e6ed1d6a80 group_id 3 enable true
    pointer 0x55e6ed1d6b50 pointer conf 0x55e6ed1d6a80 group_id 4 enable true
    Clearing...
    Done...
    

    This should work as expected