Search code examples
cstructdynamic-memory-allocationcalloc

Invalid write after allocating memory for struct member in array of structs


I need to pass an array of structs to a function and it is my understanding that I have to allocate memory for the whole array of structs, as well as for each individual struct member in every struct inside the array.

The way I have done it results in an invalid write error from valgrind (caused in the second line inside function read_file). What is wrong?

typedef struct test
{
    char *string1; 
    int num1; 
    int num2;
    char *string2;
} Test;

static void read_file(Test *test)
{
    test = (Test *)calloc(16, sizeof(test));
    test[0].string1 = (char *)calloc(strlen("hello") + 1, sizeof(char));
}

int main(void)
{
    int i = 0;
    Test test[16];

    for (i = 0; i < 16; i++)
    {
        memset(&test[i], 0, sizeof(test[i]));
        test[i] = (Test) { "", 0, 0, "" };
    }

    read_file(test);
    return 0;
}

PS: I know that I have to free the allocated memory, but first I want to get the above code working.


Solution

  • Test *test
    

    The test variable inside read_file function is a pointer to the Test struct.

    sizeof(test)
    

    This is equal to the sizeof of a pointer.

    test = (Test *)calloc(16, sizeof(test));
    

    This allocates memory for 16 pointer to Test structure. This does not allocate memory for 16 structures, only for pointers to them.

    test[0].string1 = 
    

    is invalid and undefined behavior happens. As sizeof(test) is way smaller then sizeof(Test), there is not enough memory to access test0[].string1. So this accesses the memory "out of bounds" and this accesses invalid / not allocated memory region. As you try to write to it (you are doing an assigment) the expresssion is invalid and undefined behavior happens. Valgrind correctly detects that as "write error" - you try to write to memory you don't own.