Search code examples
c89

realloc(): invalid next size with array lists and the "struct hack"


I'm trying to implement an arraylist in c.

typedef struct ArrayList {
    size_t len;
    size_t size;
    int arr[1];
} ArrayList;

I have a function that reallocates it when the array gets full.

void array_list_push(ArrayList* list, int num) {
    if (list->len == list->size) {
        size_t size = list->size;
        size *= 2;
        printf("%ld\n", size); // It prints the size
        list = realloc(list, size * 2 + (sizeof(ArrayList) - 1 * sizeof(int)));
        list->size = size;
    }
    list->arr[list->len++] = num;
}

Here is the "testing" function.

#include <stdio.h>
#include "array_list.h"

int main() {
    ArrayList *list = array_list_create(2);
    unsigned i, j;
    for(i = 0; i < 32; i++)
    {
        array_list_push(list, i); // side-effect: prints the size. for ""debugging""
        printf("[");
        for(j=0; j < array_list_get_length(list); j++)
            printf("%d, ", array_list_get(list, j));
        printf("]\n");
    }
    return 0;
}

And the output:

[0, ]
[0, 1, ]
4
[0, 1, 2, ]
[0, 1, 2, 3, ]
8
[0, 1, 2, 3, 4, ]
[0, 1, 2, 3, 4, 5, ]
[0, 1, 2, 3, 4, 5, 6, ]
[0, 1, 2, 3, 4, 5, 6, 7, ]
16
realloc(): invalid next size
Aborted (core dumped)

Why am i getting this error, and why don't the first 2 reallocations fail?

Here's array_list_create

ArrayList* array_list_create(size_t initial_size) {
    ArrayList *list = malloc(sizeof(ArrayList) + sizeof(int) * (initial_size - 1));
    list->len = 0;
    list->size = initial_size;
    return list;
}

After changing my realloc function according to Nate Eldredge's answer, i get the following output:

[0, ]
[0, 1, ]
4
[0, 1, 2, ]
[0, 1, 2, 3, ]
8
[]
[5, ]
[5, 6, ]
[5, 6, 7, ]
[5, 6, 7, 8, ]
[5, 6, 7, 8, 9, ]
[5, 6, 7, 8, 9, 10, ]
[5, 6, 7, 8, 9, 10, 11, ]
[5, 6, 7, 8, 9, 10, 11, 12, ]
[5, 6, 7, 8, 9, 10, 11, 12, 539768155, ]
[5, 6, 7, 8, 9, 10, 11, 12, 539768155, 924855350, ]
[5, 6, 7, 8, 9, 10, 11, 12, 539768155, 924855350, 741875756, ]
[5, 6, 7, 8, 9, 10, 11, 12, 539768155, 924855350, 741875756, 539769120, ]
[5, 6, 7, 8, 9, 10, 11, 12, 539768155, 924855350, 741875756, 539769120, 539766833, ]
[5, 6, 7, 8, 9, 10, 11, 12, 539768155, 924855350, 741875756, 539769120, 539766833, 539767089, ]
[5, 6, 7, 8, 9, 10, 11, 12, 539768155, 924855350, 741875756, 539769120, 539766833, 539767089, 539767345, ]
[5, 6, 7, 8, 9, 10, 11, 12, 539768155, 924855350, 741875756, 539769120, 539766833, 539767089, 539767345, 926495541, ]
[5, 6, 7, 8, 9, 10, 11, 12, 539768155, 924855350, 741875756, 539769120, 539766833, 539767089, 539767345, 926495541, 892418102, ]

And so on with scrambled numbers. I try to redirect it into a file with ./main > output and in the editor it shows weird ?s. Here's the output of cat output

?
[5, 6, 7, 8, 9, ]
[5, 6, 7, 8, 9, 10, ]
[5, 6, 7, 8, 9, 10, 11, ]
[5, 6, 7, 8, 9, 10, 11, 12, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, ]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, ]

Solution

  • list = realloc(list, size * 2 + (sizeof(ArrayList) - 1 * sizeof(int)));
    

    This calculation looks wrong. I don't know where the 2 came from but it makes no sense; it ought to be sizeof(int). I think it might be clearer to write it as

    list = realloc(list, sizeof(ArrayList) + (size - 1)*sizeof(int));