4

I tried to create my own malloc function in C, using array as the memory i'll be working with. But when the remaining memory size surpasses a certain number of bits, the program crashes saying " Exception thrown: write access violation."

I divide the memory to a blocks. Each block will have a little metadata block that preserves the size of the block and whether is it free or taken (at the beginning, the entire memory array is one big block). Then my malloc finds the first memory block with sufficient size and uses it (or part of it).

The problem is: If i initialize an array of size 20000 bytes for example, my malloc will only work if the remaining free bytes in array would be 17708 or more.

#include <stdio.h>

char memory[20000];             

struct block {                  
    unsigned int size;
    int free;
    struct block* next;
};

struct block* freeList = (void*)memory;

void initialize() {             /
    freeList->size = 20000 - sizeof(struct block);
    freeList->free = 1;
    freeList->next = NULL;
}

void split(struct block* fitting_slot, unsigned int size) {         
    struct block* new = (void*)(fitting_slot + size + sizeof(struct block));
    unsigned int temp = (fitting_slot->size) - size - sizeof(struct block);
    printf("Remaining memory size is %d\n", temp);

    new->size = temp;            // this is where program crashes
    new->free = 1;
    new->next = fitting_slot->next;
    fitting_slot->size = size;
    fitting_slot->free = 0;
    fitting_slot->next = new;
}


void* MyMalloc(unsigned int noOfBytes) {
    struct block* curr;
    void* result;
    if (!(freeList->size)) {
        initialize();
    }
    curr = freeList;

    while ((((curr->size) < (noOfBytes + sizeof(struct block))) || ((curr->free) == 0)) && (curr->next != NULL)) {          
        curr = curr->next;
    }
    printf("From the free memory of size : %d\n", curr->size);
    printf("We will occupy this size : %d\n", noOfBytes + sizeof(struct block));

    if ((curr->size) == (noOfBytes + sizeof(struct block))) {
        curr->free = 0;
        result = (void*)(++curr);
        printf("Exact fitting block allocated\n\n");
    }
    else if ((curr->size) > (noOfBytes + sizeof(struct block))) {
        split(curr, noOfBytes);
        result = (void*)(++curr);
        printf("Fitting block allocated with a split\n\n");
    }
    else {
        result = NULL;
        printf("Sorry. No sufficient memory to allocate\n\n");
    }
    return result;
}

int main(){
    unsigned int size = 2270 * sizeof(char);       
    char* k = (char)MyMalloc(size);
    printf("Success\n");
}

If the number of "size" is 2269 or lower, program works correctly.

If the number of "size" in main is 2270 or higher, program crashes on the line new->size = temp in function split() saying "Exception thrown: write access violation."

klutt
  • 30,332
  • 17
  • 55
  • 95
newbie5
  • 45
  • 4

3 Answers3

4

OK, so I think you are offsetting by the wrong amount. Pointers in C have an indication of the size of thing they are pointing to, so if you want a byte offset you need to cast the pointer to char*, or I think void* should also work fine. (see the edit below, this was mistaken)

I have not done a detailed debug, however changing line 20 from

struct block* new = (void*)(fitting_slot + size + sizeof(struct block));

to:

struct block* new = (void*)(fitting_slot) + size + sizeof(struct block);

seemed to at least stop the errors.

I can set size right up to 19968 (the max) and all seems well.


EDIT

So, as @R.. correctly pointed out below, arithmatic on void pointers is not allowed (although gcc and probably other compilers let you get away with it) - see this answer, for example, on the topic.

The most appropriate thing would seem to be casting to char*. Given that the fitting_slot variable is also already in units of the block size, rather than adding sizeof(struct block) it is simpler to just add 1 to that, then the size once case to char:

struct block* new = (void*)((char*)(fitting_slot+1) + size);

I've tested this and it seems to work the same in gcc as the previous edit, but legally now.

Euan Smith
  • 2,102
  • 1
  • 16
  • 26
1

In the line where new is assigned pointer arithmetic is done on a struct block*. When you do pinter arithmetic on a typed pointer, c semantics assumes, that an array is being manipulated. For example ptr++ on a struct block* increases the value of the pointer by sizeof(struct block). You should cast your pointer to char* before performing arithmetic on it this way. I am not sure I got everything, but I hope this can get you started.

g_bor
  • 1,077
  • 6
  • 14
0

I used my debugger.I assume that you forgot a malloc in split function.

struct block* new = (void*)malloc(fitting_slot + size + sizeof(struct block));

If you use a debbuger you'll find out that new->size was unreachable address.

**this would be line 20, if the include is in line 1.