ohhnoes_
ohhnoes_

Reputation: 33

malloc overwriting struct elements

Calling malloc before assigning 0 to count works as expected. But, if I call malloc after assigning 0 to count then it overwrites the value of count. I get a random number printed out for count every time I run it.

Could someone explain why count gets overwritten?

#include <stdio.h>
#include <stdlib.h>

typedef struct list list;

struct list {
    size_t element_size;
    size_t capacity;
    size_t count;
    void* data;
};

list* create_list(size_t element_size) {
    list* list = malloc(sizeof(list));

    list->element_size = element_size;
    list->capacity = 8;
    list->data = malloc(8 * element_size);
    list->count = 0;

    // If malloc is called here instead then count is overwritten
    // list->data = malloc(8 * element_size);

    printf("count: %zu\n", list->count);

    return list;
}

int main(int argc, char** argv) {
    list* l = create_list(sizeof(int));
}

Upvotes: 2

Views: 594

Answers (2)

S.S. Anne
S.S. Anne

Reputation: 15576

You're allocating the size of a pointer here:

list* list = malloc(sizeof(list));

Instead you should do this:

list* list = malloc(sizeof(*list));

Although I would prefer removing

typedef struct list list;

and using:

struct list *list = malloc(sizeof(*list));

as this makes it more clear that you're dealing with the size of the structure and not the size of the pointer.

On another note, MSVCRT does not support the %zu or %zd format specifiers for printf. Start your C file with this line:

#define __USE_MINGW_ANSI_STDIO 1

and you should be able to use those specifiers.

Upvotes: 2

hyde
hyde

Reputation: 62797

Ah, I think problem is here:

list* list = malloc(sizeof(list));

sizeof(list) gives size of pointer, because at that point list is a pointer, not the struct type any more. So you allocate too little memory, and hit undefined behavior when you initialize the struct data by writing in unallocated memory.

Fix by changing the variable or type name... Or use sizeof(*list) to get the correct size. Or, if you want my opinion/preference, do not use typedef with structs. Or several of these, so here you might have struct list *lst = malloc(sizeof(*lst));.


Even though it is usually not very productive with Undefined Behavior, we can take an educated guess at what probably happens: If you call malloc after writing that 0 beyond what you allocated, then malloc creates a new allocation and overwrites the 0 with its own allocation data and you get that value in output. If you do it the other way, writing that 0 will instead overwrite the allocation data. Both are quite fatal in the long run, so you can consider yourself lucky you noticed the strange output and spotted the UB early, instead of having mysterious crashes later.

Upvotes: 6

Related Questions