Search code examples
cmemory-managementansi-c

C. double free or corruption (!prev) Aborted (core dumped)


I'm trying to use a "fixed memory scheme" and pre-allocate memory & reuse it via alloc, init, free fashion as many times as possible.

free() will called at shutdown only, but I want to test many iterations.

Although I call my alloc function bn_tree_alloc_node_space_heap() & init function bn_tree_init_node_heap(), I can only call free function bn_tree_free_node_space once.

Below is a complete reproducible snippet of my memory management, maint_test.c:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <float.h>
#define BN_TREE_HEAP_SIZE 100

/*variables internal*/
typedef struct bntree_internals;

/*bn_tree_node is single bntree_t leaf*/
typedef struct bn_tree_node {
    struct bn_tree_node* left;
    struct bn_tree_node* right;
    float* dataset;
    float distance_to_neighbor;
    int visited;
    int heap_index;
} bn_tree_node;

/*tree*/
typedef struct {
    /*in order to  keep track of the bn-tree root*/
    bn_tree_node* _root;
    /*pointer to internal variables struct*/
    struct bntree_internals* _internals;

} bntree_t;


/*bn tree leaf nodes heap*/
bn_tree_node* node_processing_space = NULL;

/*leaf nodes*/
void bn_tree_alloc_node_space_heap(int max_dimensions);
bn_tree_node*
get_pre_allocated_bn_tree_node_heap();
void bn_tree_init_node_heap(bn_tree_node* nodes, int max_dimensions);
void bn_tree_free_node_space(bn_tree_node* nodes);

int main(int argc, char** argv) {

    /*PROBLEM:called the alloc,init,free cycle several times, problem, 
     getting seg fault on 2nd call of free()*/
    bn_tree_alloc_node_space_heap(3);
    assert(get_pre_allocated_bn_tree_node_heap());
    printf("alloc\n");
    bn_tree_init_node_heap(node_processing_space, 3);
    printf("init\n");
    bn_tree_free_node_space(node_processing_space);
    printf("free\n");

    bn_tree_alloc_node_space_heap(3);
    assert(get_pre_allocated_bn_tree_node_heap());
    printf("alloc\n");
    bn_tree_init_node_heap(node_processing_space, 3);
    printf("init\n");
    bn_tree_free_node_space(node_processing_space);
    printf("free\n");

    bn_tree_alloc_node_space_heap(3);
    assert(get_pre_allocated_bn_tree_node_heap());
    printf("alloc\n");
    bn_tree_init_node_heap(node_processing_space, 3);
    printf("init\n");
    bn_tree_free_node_space(node_processing_space);
    printf("free\n");

    bn_tree_alloc_node_space_heap(3);
    assert(get_pre_allocated_bn_tree_node_heap());
    printf("alloc\n");
    bn_tree_init_node_heap(node_processing_space, 3);
    printf("init\n");
    bn_tree_free_node_space(node_processing_space);
    printf("free\n");



    return (EXIT_SUCCESS);
}

void bn_tree_alloc_node_space_heap(int max_dimensions) {
    if (NULL == node_processing_space) {
        node_processing_space = (bn_tree_node*) calloc(BN_TREE_HEAP_SIZE, sizeof (bn_tree_node));


        //TODO: bn_tree_set_k_dimensions (max_dimensions);

        int i = 0;
        for (; i < BN_TREE_HEAP_SIZE; i++) {
            node_processing_space[i].dataset = (float*) calloc(max_dimensions, sizeof (float));

        }

        //bn_heap_tail_index = bn_heap_head_index = 0;
    }
}

bn_tree_node* get_pre_allocated_bn_tree_node_heap() {
    return node_processing_space;
}

void bn_tree_init_node_heap(bn_tree_node* nodes, int max_dimensions) {

    int i = 0;
    int c = 0;
    for (; i < BN_TREE_HEAP_SIZE; i++) {

        /*reset  values */
        if (NULL != nodes[i].dataset) {
            c = 0;
            for (; c < max_dimensions; c++) {
                nodes[i].dataset[c] = FLT_MIN;
            }
        }
        nodes[i].visited = 0;
        nodes[i].distance_to_neighbor = FLT_MAX;
        nodes[i].left = NULL;
        nodes[i].right = NULL;
        nodes[i].heap_index = -1;

    }
}


/*PROBLEM is subsequent call to free(), but if I alloc again why cant I free again?*/
void bn_tree_free_node_space(bn_tree_node* nodes) {
    int i = 0;
    for (; i < BN_TREE_HEAP_SIZE; i++) {
        if (nodes[i].dataset) {
            free(nodes[i].dataset);
        }
    }

    free(nodes);
    nodes = NULL;
}

Here is the output that I expect/want:

alloc
init
free
alloc
init
free
alloc
init
free
alloc
init
free

But Im getting this output/error:

alloc
init
free
alloc
init
double free or corruption (!prev)
Aborted (core dumped)
  1. How can fix this?

  2. Can't I do alloc,init,free as many times as I want (as long as I called alloc before free) OR I can do only alloc() once, then many init(), free() once?

Thanks a million & please be kind enough to provide concise answers with minimal changes.


Solution

  • The problem is that your bn_tree_free_node_space function takes, as its argument, a copy of the pointer variable - that is, you are passing the pointer by value - thus, the line nodes = NULL; at the end of that function only sets the local variable to NULL and does not change the value of the node_processing_space variable.

    To fix this (with minimal changes to your code logic1), you need to pass that function a pointer to the pointer, and dereference that in the function. So, your function should look like this:

    void bn_tree_free_node_space(bn_tree_node** nodes) // Argument is pointer-to-pointer
    {
        int i = 0;
        for (; i < BN_TREE_HEAP_SIZE; i++) {
            if ((*nodes)[i].dataset) { // Now we need to use (*nodes) to get the underlying pointer
                free((*nodes)[i].dataset); // ... same here
            }
        }
    
        free(*nodes); /// ... and here
        *nodes = NULL;
    }
    

    You will, of course, also need to change the function prototype (just before your main) to match the new definition:

    void bn_tree_free_node_space(bn_tree_node** nodes); // Must match definition!
    

    Fruther, you will (clearly) need to change the calls to that function to pass the address of the node_processing_space pointer:

    bn_tree_free_node_space(&node_processing_space); // Likewise for the other 3 calls!
    

    Feel free to ask for further clarification and/or explanation.


    1 EDIT: There are other ways (some may argue better ways) to implement your system, and also other 'minor' issues in your code. However, you did explicitly ask for "concise answers with minimal changes," so I have endeavoured to comply with that request!