Search code examples
cpointersmallocfreeheap-corruption

Heap corruption when freeing allocated memory (C)


I'm allocating memory dynamically to maintain a list of items, but when trying to remove an item using free(), I get a memory heap corruption error. And I know this would be a lot easier to do in C++ (or java, or any other object-oriented language actually), but I have to do this in C (note: C code, but compiled in Microsoft Visual Studio 2010, and thus a C++ compiler).

Here is what the item "looks" like:

//item.h
typedef struct 
{
    char* titel;
    char* auteur;
    int jaar;
} Boek;

typedef struct
{
enum {BOEK, TIJDSCHRIFT} itemType;
    union {
        Boek* boek;
        Tijdschrift* tijdschrift;
    } itemData;
    struct Item* next;
} Item;

Here is how it is created/allocated. I've also switched between using strdup and malloc/strcpy for allocating the strings, but that didn't seem to have any effect. Also, the item I'm trying to remove is of the BOEK type, the TIJDSCHRIFT allocator/deallocator works in a similar way though.

//item.c
Item* nieuwBoek(char* _titel, char* _auteur, int _jaar)
{
    Item* item = (Item*) malloc(sizeof(Item*));
    item->itemType=BOEK;
    item->itemData.boek=(Boek*) malloc(sizeof(Boek*));
    item->itemData.boek->titel=strdup(_titel);
    item->itemData.boek->auteur=strdup(_auteur);
    item->itemData.boek->jaar=_jaar;
    item->next=NULL;
    return item;
}

The returned pointer is then used by another function which passes it to the item->next of the previous item in the list.

Here is how I'm trying to free it. It is my understanding that I'll have to free the allocated strings before freeing the struct itself, but even when I just call free(item) (either by commenting out the other code in deleteItem or by calling it in the main code: free(nieuwBoek(...) I get the heap corruption error.

void deleteItem(Item* item)
{
    if (item->itemType==BOEK)
    {
        free(item->itemData.boek->titel); // When not running in debug-mode it crashes here.
        free(item->itemData.boek->auteur);
        free(item->itemData.boek); // When running in debug mode it crashes here.
    }
    /*else if... TIJDSCHRIFT deallocator here*/
    free(item); 
}

And the pointer passed to deleteItem() is a valid pointer pointing to an item. Its probably something incredibly stupid I'm doing wrong/missing, but I've been stumped over this problem all day now, so I'm asking you guys for help. Oh, and the next->pointer is set to NULL prior to the deleting of an item, so it's already disconnected from the list, if that matters.


Solution

  • Item* item = (Item*) malloc(sizeof(Item*));
    

    You should change that sizeof to sizeof(Item) or sizeof(*item). Otherwise you'll allocate just enough to hold a pointer, not nearly enough for your structure.

    Personally I prefer sizeof *item - that way if I ever change its type, I only have to do it in one place.


    Side notes:

    • What the corruption means: since you allocated to little memory, when you filled your struct fields to messed up the internal bookkeeping of malloc and the next operation detected it
    • Although a matter of personal preference, you should probably not cast the return of malloc