Search code examples
cmemorystructmalloccalloc

Malloc is throwing an error for pointer being freed


so I have a function that creates a flexible array type and all paths use calloc to define the size of the array. However when I try to destroy the struct, it says that the memory was not allocated.

typedef struct {
    int size;
    void *items;
} Array;

typedef enum {
    CHAR,
    INT,
    FLOAT,
    DOUBLE
} datatype;

Array *create_array(int initial_size, datatype type)
{
    Array *arr = malloc(sizeof(Array));

    arr->size = initial_size;

    switch (type) {
        case CHAR:
            arr->items = (char *) calloc(5, sizeof(char));
            break;
        case INT:
            arr->items = (int *) calloc(arr->size, sizeof(int));
            break;
        case FLOAT:
            arr->items = (float *) calloc(arr->size, sizeof(float));
            break;
        case DOUBLE:
            arr->items = (double *) calloc(arr->size, sizeof(double));
            break;
        default:
            exit(1); // will handle later on
            break;
    }
    return arr;
}

void destroy_array(Array *arr)
{
    free(arr->items); // this is the line that throws the error
    free(arr);
}

The exact error is:

flexibleArray(63110,0x10c3c6600) malloc: *** error for object 0x600000c21120: pointer being freed was not allocated flexibleArray(63110,0x10c3c6600) malloc: *** set a breakpoint in malloc_error_break to debug

I just don't understand why memory I'm allocating with calloc does not require to be freed.

Thanks for anyone's input!

Main Loop

There is just a lot of random code in there that I am using to test out changing the size of the array. I don't think it would affect the outcome of the destroy function.

    int main() {
        Array *newArr = create_array(5, INT);
        int *val;
        int w = 20;
        val = &w;

        printf("%s\n", typename(w));

        ((int *)newArr->items)[0] = *val;
        ((int *)newArr->items)[1] = 35;
        ((int *)newArr->items)[2] = 20;
        ((int *)newArr->items)[3] = 351;
        ((int *)newArr->items)[4] = 315;

        for(int i = 0; i < newArr->size; i++) {
            printf("%d\n", ((int *)newArr->items)[i]);
        }

        realloc(newArr->items, 10);

        ((int *)newArr->items)[5] = 50;
        for(int i = 0; i < newArr->size; i++) {
            printf("%d\n", ((int *)newArr->items)[i]);
        }

        destroy_array(newArr);
    }

Solution

  • You currently ignore the return value from realloc. If it needs to relocate the allocated data, you get undefined behavior.

    Another problem is that you allocate room for 10 bytes, not 10 int.

    Fix:

    // allocate space for 10 `int`:
    void* np = realloc(newArr->items, 10 * sizeof(int));
    
    if(np) {
        // realloc success
        newArr->items = np;
    } else {
        // realloc failure
        destroy_array(newArr);
        return 1;
    }