简体   繁体   中英

Memory leak after realloc call

I have a **void where each position point to *void that point to my struct record with 3 fields (*char, int, float). I want to load data from a csv in my struct, but when it's time to reallocate memory, because size is equal to array's capacity, I got realloc(): invalid next size. I did not get my printf("realloc fails") so I think that tmp is not null, but anyway I lost my memory pointer.

struct record{
    int id;
    char* field1;
    int field2;
    float field3; 
};

long array_size = 0; 
long array_capacity = INITIAL_CAPACITY;
void** array;

void** array_create(){

    void **array = (void**)malloc(INITIAL_CAPACITY*sizeof(void*));
    if(array == NULL){
        fprintf(stderr, "array_create: unable to allocate memory for the array");
        exit(EXIT_FAILURE);
    }

    return array;
}

void add_on_array(void** array, void* elem){

    if(array == NULL){
        fprintf(stderr,"add_on_array: array parameter cannot be NULL");
        exit(EXIT_FAILURE);
    }
    if(elem == NULL){
        fprintf(stderr,"add_on_array: elem parameter cannot be NULL");
        exit(EXIT_FAILURE);
    }
    
    if(array_size >= array_capacity){

        void** tmp = realloc(array, 2*(sizeof(void*)*array_capacity));
        if(tmp == NULL){
            printf("Realloc fails\n");
            exit(EXIT_FAILURE);
        }
        array = tmp;

        array_capacity = 2*array_capacity;
    }
    array[array_size] = elem;
    array_size++;

}

    while(fgets(buffer,buf_size,fp) != NULL){
        read_line_p = strdup(buffer);
        if(read_line_p == NULL){
            fprintf(stderr,"main: unable to allocate memory for the read line");
            exit(EXIT_FAILURE);
        }

        // strcpy(read_line_p,buffer);
        char *id_field_in_read_line_p = strtok(read_line_p, ",");
        char *field1_in_read_line_p = strtok(NULL,","); 
        char *field2_in_read_line_p = strtok(NULL,",");  
        char *field3_in_read_line_p = strtok(NULL, ",");

        char *field1 = malloc((strlen(field1_in_read_line_p)+1)*sizeof(char));
        
        if(field1 == NULL){
            fprintf(stderr,"main: unable to allocate memory for the string field of the read record");
            exit(EXIT_FAILURE);
        }
        int id = atoi(id_field_in_read_line_p); 
        strcpy(field1,field1_in_read_line_p); 
        int field2 = atoi(field2_in_read_line_p);
        float field3 = atof(field3_in_read_line_p);
        struct record *record_p = malloc(sizeof(struct record));
        if(field1 == NULL){
            fprintf(stderr,"main: unable to allocate memory for the read record");
            exit(EXIT_FAILURE);
        } 
        record_p->id = id;
        record_p->field1 = field1;
        record_p->field2 = field2;
        record_p->field3 = field3;
        add_on_array(array, (void*)record_p);
        
        free(read_line_p);
    }
    fclose(fp);
    stampa_array(array, array->size);
    printf("\nData loaded\n");
    
}

Well, you are doing some "real bad" things here.

First of all you have a global variable with the name array here:

void** array;

In general global variables is something you should avoid. (In the rare cases where you really need a global variable, I'll recommend that you give it an "ugly" name that isn't used for anything else - like: globalVariableArray )

But worse - you also have a function that has an argument named array here:

void add_on_array(void** array, void* elem){
    ...
}

What does that mean? Having both a global array and an argument array ? Which will be accessed in the function?

The answer is that the function argument array acts as a function local variable and it will hide the global variable.

So when you do:

array = tmp;

you change the local array variable - not the global.

When the function return the local variable no longer exists, ie any changes made to it is lost.

In other words - the memory allocated by realloc is lost and you have a leak.

First steps to fix this is:

  1. Move the global variable into main

  2. When calling a function that needs to change array , you need to pass the address of array , ie &array . Functioon prototype must be changed accordingly.

Likewise for the other globals...

But why not put all the array stuff into a struct?

Like:

struct ArrayContainer
{
    long array_size; 
    long array_capacity;
    void** array;
}

And in main do:

struct ArrayContainer container = {0, INITIAL_CAPACITY, NULL};
container.array = ...;  // Allocate INITIAL_CAPACITY

I think that will simplify your code a lot as you only need to pass a pointer to this struct to the functions. Then you can change all three members through that pointer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM