Realloc on an array of structs, address boundary error when indexing

Viewed 109

I have some code where I'm trying to read lines in from a file and store some information from each line in a struct. Since I don't know how long the file will be, I'm dynamically adjusting the array of structs using realloc.

My issue is that my code seems to work fine for the first 3 (technically 6) lines, and then I receive SIGSEGV (address boundary error). gdb says that this happens when trying to index the array (array[i]->string = (char*) _tmp).

typedef struct {
    char* string;
    int len;
} buffer;


int read_into_array(char *filename, buffer** array) {
    int n;
    size_t size;
    char* buf = NULL;
    FILE *file = fopen(filename, "r");

    int i = 0;
    while (1) {
        buffer *tmp = (buffer*)realloc(*array, sizeof(buffer) * (i + 1));
        if (!tmp)
            printf("Failed realloc\n");

        *array = tmp;

        // First line is ignored, second line is taken as data.
        getline(&buf, &size, file);
        n = getline(&buf, &size, file);
        if (n > 0) {
            void* _tmp = malloc(sizeof(char) * n);
            if (!_tmp)
                printf("Failed malloc\n");

            array[i]->string = (char*) _tmp;
            array[i]->len = n-1;
            strncpy(array[i]->string, buf, n-1);
        }

        i++;
        if (feof(file)) {
            printf("saw end of file, leaving.\n");
            break;
        }
    }

    return i;
}

int main(int argc, char* argv[]) {
    char *filename = argv[1];

    buffer *array = (buffer*) calloc(1, sizeof(buffer));
    int num = read_into_array(filename, &array);
}

Apologies for the somewhat poor formatting, I've been trying to figure this out for a while.

Since it seems to work for the first few lines, my assumption is that I'm going wrong somewhere in the realloc calculation. My other guess is that I'm somehow using/reading the file incorrectly.

Thanks for any help. For posterity, the file looks something like this https://hastebin.com/vinidiyita.sm (the real file is thousands of lines long).

1 Answers

when you do *array=tmp you're allocating memory for array[0]

then you're using array[i] that should be a pointer to a buffer, but points to garbage or 0

You're confusing two ways to use data.

The first is by using arrays - there's the non-dynamic:

buffer array[x] = {0};
int num = read_into_array(filename, &array);

then you can use array[i]

and there's the dynamic type:

buffer **array = calloc(initial_len*sizeof(buffer *));
int num = read_into_array(filename, array, initial_len);
read_into_array(char *filename, buffer **&array, int initial_len)
{
    int len = initial_len;
...
    while()
    {
        ...
        if(i>len)
        {
            array = realloc(array, sizeof(buffer*) * (i + 1));
            len = i;
        }
        array[i] = calloc(sizeof(buffer));
    }
}
Related