C. двойное освобождение или коррупция (! prev) Прервано (ядро сброшено) - PullRequest
1 голос
/ 16 апреля 2020

Я пытаюсь использовать «фиксированную схему памяти» и предварительно выделить память и повторно использовать ее через allo c, init, free fashion столько раз, сколько это возможно.

free () будет вызываться только при завершении работы, но я хочу протестировать много итераций.

Хотя я вызываю свою функцию allo c bn_tree_alloc_node_space_heap() и функцию init bn_tree_init_node_heap(), свободную функцию bn_tree_free_node_space можно вызвать только один раз.

Ниже приведен полный воспроизводимый фрагмент моего управления памятью, 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;
}

Вот вывод, который я ожидаю / хочу :

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

Но я получаю этот вывод / ошибку:

alloc
init
free
alloc
init
double free or corruption (!prev)
Aborted (core dumped)
  1. Как это можно исправить?

  2. Не могу ли я сделать allo c, init, бесплатно столько раз, сколько захочу (до тех пор, пока я звонил allo c до освобождения) ИЛИ я могу делать только allo c () один раз, то много init (), один раз бесплатно ()?

Спасибо за миллион и, пожалуйста, будьте любезны предоставить краткие ответы с минимальными изменениями.

1 Ответ

0 голосов
/ 16 апреля 2020

Проблема в том, что ваша bn_tree_free_node_space функция принимает в качестве аргумента копию переменной указателя - то есть вы передаете указатель на значение - таким образом, строка nodes = NULL; в конце этой функции устанавливает только переменную local на NULL, а не изменяет значение переменной node_processing_space.

Чтобы это исправить (с минимальными изменениями в вашем коде logi c 1 ), вам нужно передать этой функции указатель на указатель и разыменовать его в функции. Итак, ваша функция должна выглядеть следующим образом:

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;
}

Вам, конечно, также необходимо изменить прототип функции (непосредственно перед вашим main), чтобы соответствовать новому определению:

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

Кроме того, вам (ясно) необходимо изменить вызовы этой функции, чтобы передать адрес указателя node_processing_space:

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

Не стесняйтесь спрашивать дальнейшее уточнение и / или объяснение.


1 РЕДАКТИРОВАТЬ: Существуют другие способы (некоторые могут утверждать, лучше способов) для реализации вашей системы, а также другие "незначительные" проблемы в вашем коде. Тем не менее, вы явно попросили «кратких ответов с минимальными изменениями», поэтому я постарался выполнить этот запрос!
...